diff options
1546 files changed, 41081 insertions, 6885 deletions
@@ -3199,6 +3199,297 @@ </scannerConfigBuildInfo> </storageModule> </cconfiguration> + <cconfiguration id="0.980756260.1834106966.226646757.1415775202.1627288159"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.980756260.1834106966.226646757.1415775202.1627288159" moduleId="org.eclipse.cdt.core.settings" name="NetworkTool"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.MachO64" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GNU_ELF" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="be.el_tramo.ecppunit.CPPUnitErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildProperties="" description="" errorParsers="org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.GmakeErrorParser;org.eclipse.cdt.core.CWDLocator;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser;be.el_tramo.ecppunit.CPPUnitErrorParser" id="0.980756260.1834106966.226646757.1415775202.1627288159" name="NetworkTool" parent="org.eclipse.cdt.build.core.prefbase.cfg"> + <folderInfo id="0.980756260.1834106966.226646757.1415775202.1627288159." name="/" resourcePath=""> + <toolChain errorParsers="" id="org.eclipse.cdt.build.core.prefbase.toolchain.1096610170" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain"> + <targetPlatform binaryParser="org.eclipse.cdt.core.MachO64;org.eclipse.cdt.core.ELF;org.eclipse.cdt.core.PE;org.eclipse.cdt.core.GNU_ELF" id="org.eclipse.cdt.build.core.prefbase.toolchain.1096610170.316602503" name=""/> + <builder arguments="${ProjDirPath}/3rdParty/SCons/scons.py" autoBuildTarget="Swiften/Examples/NetworkTool" buildPath="" cleanBuildTarget="-c" command="python" enableAutoBuild="true" errorParsers="org.eclipse.cdt.core.GmakeErrorParser;org.eclipse.cdt.core.CWDLocator" id="org.eclipse.cdt.build.core.settings.default.builder.2054666555" incrementalBuildTarget="Swiften/Examples/NetworkTool" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/> + <tool errorParsers="org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser" id="org.eclipse.cdt.build.core.settings.holder.libs.1235898736" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/> + <tool errorParsers="org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser" id="org.eclipse.cdt.build.core.settings.holder.435535367" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder"> + <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1960300889" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> + </tool> + <tool errorParsers="org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser" id="org.eclipse.cdt.build.core.settings.holder.569051524" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder"> + <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1305417300" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> + </tool> + <tool errorParsers="org.eclipse.cdt.core.VCErrorParser;org.eclipse.cdt.core.GCCErrorParser;org.eclipse.cdt.core.GASErrorParser;org.eclipse.cdt.core.GLDErrorParser" id="org.eclipse.cdt.build.core.settings.holder.1784984314" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder"> + <inputType id="org.eclipse.cdt.build.core.settings.holder.inType.479612703" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> + </tool> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> + <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> + <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/> + <storageModule moduleId="scannerConfiguration"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="makefileGenerator"> + <runAction arguments="-E -P -v -dD" command="" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <scannerConfigBuildInfo instanceId="0.980756260.1834106966.1269306596"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="makefileGenerator"> + <runAction arguments="-E -P -v -dD" command="" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="0.980756260"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="makefileGenerator"> + <runAction arguments="-E -P -v -dD" command="" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> + <buildOutputProvider> + <openAction enabled="true" filePath=""/> + <parser enabled="true"/> + </buildOutputProvider> + <scannerInfoProvider id="specsFile"> + <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> + <parser enabled="true"/> + </scannerInfoProvider> + </profile> + </scannerConfigBuildInfo> + </storageModule> + </cconfiguration> </storageModule> <storageModule moduleId="cdtBuildSystem" version="4.0.0"> <project id="swift.null.189117846" name="swift"/> @@ -21,6 +21,7 @@ *.ilk *.res *.moc +*.patch *~ _CL_* *.manifest @@ -37,3 +38,8 @@ Swift/QtUI/swift Swift/QtUI/DefaultTheme.qrc checker-report.xml VERSION.* +cppcheck.log +/build +/.settings/ +/nbproject/private/ +3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpcstrings.h @@ -18,7 +18,7 @@ </dictionary> <dictionary> <key>org.eclipse.cdt.make.core.autoBuildTarget</key> - <value></value> + <value>Swift</value> </dictionary> <dictionary> <key>org.eclipse.cdt.make.core.buildArguments</key> @@ -29,6 +29,10 @@ <value>python</value> </dictionary> <dictionary> + <key>org.eclipse.cdt.make.core.buildLocation</key> + <value></value> + </dictionary> + <dictionary> <key>org.eclipse.cdt.make.core.cleanBuildTarget</key> <value>-c</value> </dictionary> @@ -50,7 +54,7 @@ </dictionary> <dictionary> <key>org.eclipse.cdt.make.core.fullBuildTarget</key> - <value></value> + <value>Swift</value> </dictionary> <dictionary> <key>org.eclipse.cdt.make.core.stopOnError</key> diff --git a/3rdParty/Boost/SConscript b/3rdParty/Boost/SConscript index 562b1b0..714b90b 100644 --- a/3rdParty/Boost/SConscript +++ b/3rdParty/Boost/SConscript @@ -23,9 +23,9 @@ elif env.get("BOOST_BUNDLED", False) : #if env["PLATFORM"] == "darwin" : # cppdefines += ["BOOST_ASIO_DISABLE_KQUEUE"] if env["PLATFORM"] == "win32" : - cppflags = ["/I" + Dir("src").abspath] + cppflags = ["/I" + Dir("#/3rdParty/Boost/src").abspath] else : - cppflags = [("-isystem", Dir("src").abspath)] + cppflags = [("-isystem", Dir("#/3rdParty/Boost/src").abspath)] ################################################################################ @@ -90,7 +90,6 @@ elif env.get("BOOST_BUNDLED", False) : "src/libs/program_options/src/config_file.cpp", "src/libs/program_options/src/convert.cpp", "src/libs/program_options/src/options_description.cpp", - "src/libs/program_options/src/parsers.cpp", "src/libs/program_options/src/positional_options.cpp", "src/libs/program_options/src/split.cpp", "src/libs/program_options/src/program_options_utf8_codecvt_facet.cpp", @@ -98,6 +97,11 @@ elif env.get("BOOST_BUNDLED", False) : "src/libs/program_options/src/variables_map.cpp", "src/libs/program_options/src/winmain.cpp"] + if env["PLATFORM"] != "darwin" or env["target"] == "native" : + sources += [ + "src/libs/program_options/src/parsers.cpp", + ] + if env["PLATFORM"] != "win32" : sources += [ "src/libs/thread/src/pthread/once.cpp", @@ -116,7 +120,15 @@ elif env.get("BOOST_BUNDLED", False) : bcp_env = myenv.Clone() bcp_env.MergeFlags(bcp_env["BOOST_FLAGS"]) bcp_env.Append(CPPPATH = ["src/tools/bcp"]) + bcp_env.Replace(CPPDEFINES = [flag for flag in bcp_env["CPPDEFINES"] if flag[0] != "BOOST_FILESYSTEM_VERSION"]) bcp_env.Program("bcp", [ + "src/libs/filesystem/v3/src/codecvt_error_category.cpp", + "src/libs/filesystem/v3/src/operations.cpp", + "src/libs/filesystem/v3/src/path.cpp", + "src/libs/filesystem/v3/src/path_traits.cpp", + "src/libs/filesystem/v3/src/portability.cpp", + "src/libs/filesystem/v3/src/unique_path.cpp", + "src/libs/filesystem/v3/src/windows_file_codecvt.cpp", "src/tools/bcp/add_path.cpp", "src/tools/bcp/add_dependent_lib.cpp", "src/tools/bcp/bcp_imp.cpp", diff --git a/3rdParty/Boost/src/boost/date_time/dst_transition_generators.hpp b/3rdParty/Boost/src/boost/date_time/dst_transition_generators.hpp new file mode 100644 index 0000000..6c4da1c --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/dst_transition_generators.hpp @@ -0,0 +1,75 @@ +/* Copyright (c) 2002,2003,2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + */ +#ifndef DATE_TIME_DATE_DST_TRANSITION_DAY_GEN_HPP__ +#define DATE_TIME_DATE_DST_TRANSITION_DAY_GEN_HPP__ + + + +namespace boost { +namespace date_time { + + //! Defines base interface for calculating start and end date of daylight savings + template<class date_type> + class dst_day_calc_rule + { + public: + typedef typename date_type::year_type year_type; + virtual ~dst_day_calc_rule() {}; + virtual date_type start_day(year_type y) const=0; + virtual std::string start_rule_as_string() const=0; + virtual date_type end_day(year_type y) const=0; + virtual std::string end_rule_as_string() const=0; + + }; + + //! Canonical form for a class that provides day rule calculation + /*! This class is used to generate specific sets of dst rules + * + *@param spec Provides a specifiction of the function object types used + * to generate start and end days of daylight savings as well + * as the date type. + */ + template<class spec> + class day_calc_dst_rule : public dst_day_calc_rule<typename spec::date_type> + { + public: + typedef typename spec::date_type date_type; + typedef typename date_type::year_type year_type; + typedef typename spec::start_rule start_rule; + typedef typename spec::end_rule end_rule; + day_calc_dst_rule(start_rule dst_start, + end_rule dst_end) : + dst_start_(dst_start), + dst_end_(dst_end) + {} + virtual date_type start_day(year_type y) const + { + return dst_start_.get_date(y); + } + virtual std::string start_rule_as_string() const + { + return dst_start_.to_string(); + } + virtual date_type end_day(year_type y) const + { + return dst_end_.get_date(y); + } + virtual std::string end_rule_as_string() const + { + return dst_end_.to_string(); + } + private: + start_rule dst_start_; + end_rule dst_end_; + }; + + +} }//namespace + + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/local_time/conversion.hpp b/3rdParty/Boost/src/boost/date_time/local_time/conversion.hpp new file mode 100644 index 0000000..13e4d3e --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/conversion.hpp @@ -0,0 +1,34 @@ +#ifndef DATE_TIME_LOCAL_TIME_CONVERSION_HPP__ +#define DATE_TIME_LOCAL_TIME_CONVERSION_HPP__ + +/* Copyright (c) 2003-2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2009-06-04 04:24:49 -0400 (Thu, 04 Jun 2009) $ + */ + + +#include "boost/date_time/posix_time/conversion.hpp" +#include "boost/date_time/c_time.hpp" +#include "boost/date_time/local_time/local_date_time.hpp" + +namespace boost { +namespace local_time { + +//! Function that creates a tm struct from a local_date_time +inline +std::tm to_tm(const local_date_time& lt) { + std::tm lt_tm = posix_time::to_tm(lt.local_time()); + if(lt.is_dst()){ + lt_tm.tm_isdst = 1; + } + else{ + lt_tm.tm_isdst = 0; + } + return lt_tm; +} + + +}} // namespaces +#endif // DATE_TIME_LOCAL_TIME_CONVERSION_HPP__ diff --git a/3rdParty/Boost/src/boost/date_time/local_time/custom_time_zone.hpp b/3rdParty/Boost/src/boost/date_time/local_time/custom_time_zone.hpp new file mode 100644 index 0000000..a6c1d42 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/custom_time_zone.hpp @@ -0,0 +1,169 @@ +#ifndef LOCAL_TIME_CUSTOM_TIME_ZONE_HPP__ +#define LOCAL_TIME_CUSTOM_TIME_ZONE_HPP__ + +/* Copyright (c) 2003-2005 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + +#include "boost/date_time/time_zone_base.hpp" +#include "boost/date_time/time_zone_names.hpp" +#include "boost/date_time/posix_time/posix_time.hpp" +#include "boost/date_time/local_time/dst_transition_day_rules.hpp" +#include "boost/date_time/string_convert.hpp" +//#include "boost/date_time/special_defs.hpp" +#include "boost/shared_ptr.hpp" + +namespace boost { +namespace local_time { + + //typedef boost::date_time::time_zone_names time_zone_names; + typedef boost::date_time::dst_adjustment_offsets<boost::posix_time::time_duration> dst_adjustment_offsets; + //typedef boost::date_time::time_zone_base<boost::posix_time::ptime> time_zone; + typedef boost::shared_ptr<dst_calc_rule> dst_calc_rule_ptr; + + //! A real time zone + template<class CharT> + class custom_time_zone_base : public date_time::time_zone_base<posix_time::ptime,CharT> { + public: + typedef boost::posix_time::time_duration time_duration_type; + typedef date_time::time_zone_base<posix_time::ptime,CharT> base_type; + typedef typename base_type::string_type string_type; + typedef typename base_type::stringstream_type stringstream_type; + typedef date_time::time_zone_names_base<CharT> time_zone_names; + typedef CharT char_type; + + custom_time_zone_base(const time_zone_names& zone_names, + const time_duration_type& utc_offset, + const dst_adjustment_offsets& dst_shift, + boost::shared_ptr<dst_calc_rule> calc_rule) : + zone_names_(zone_names), + base_utc_offset_(utc_offset), + dst_offsets_(dst_shift), + dst_calc_rules_(calc_rule) + {}; + virtual ~custom_time_zone_base() {}; + virtual string_type dst_zone_abbrev() const + { + return zone_names_.dst_zone_abbrev(); + } + virtual string_type std_zone_abbrev() const + { + return zone_names_.std_zone_abbrev(); + } + virtual string_type dst_zone_name() const + { + return zone_names_.dst_zone_name(); + } + virtual string_type std_zone_name() const + { + return zone_names_.std_zone_name(); + } + //! True if zone uses daylight savings adjustments + virtual bool has_dst() const + { + return (dst_calc_rules_); //if calc_rule is set the tz has dst + } + //! Local time that DST starts -- NADT if has_dst is false + virtual posix_time::ptime dst_local_start_time(gregorian::greg_year y) const + { + gregorian::date d(gregorian::not_a_date_time); + if (dst_calc_rules_) { + d = dst_calc_rules_->start_day(y); + } + return posix_time::ptime(d, dst_offsets_.dst_start_offset_); + } + //! Local time that DST ends -- NADT if has_dst is false + virtual posix_time::ptime dst_local_end_time(gregorian::greg_year y) const + { + gregorian::date d(gregorian::not_a_date_time); + if (dst_calc_rules_) { + d = dst_calc_rules_->end_day(y); + } + return posix_time::ptime(d, dst_offsets_.dst_end_offset_); + } + //! Base offset from UTC for zone (eg: -07:30:00) + virtual time_duration_type base_utc_offset() const + { + return base_utc_offset_; + } + //! Adjustment forward or back made while DST is in effect + virtual time_duration_type dst_offset() const + { + return dst_offsets_.dst_adjust_; + } + //! Returns a POSIX time_zone string for this object + virtual string_type to_posix_string() const + { + // std offset dst [offset],start[/time],end[/time] - w/o spaces + stringstream_type ss; + ss.fill('0'); + boost::shared_ptr<dst_calc_rule> no_rules; + // std + ss << std_zone_abbrev(); + // offset + if(base_utc_offset().is_negative()) { + // inverting the sign guarantees we get two digits + ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours(); + } + else { + ss << '+' << std::setw(2) << base_utc_offset().hours(); + } + if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) { + ss << ':' << std::setw(2) << base_utc_offset().minutes(); + if(base_utc_offset().seconds() != 0) { + ss << ':' << std::setw(2) << base_utc_offset().seconds(); + } + } + if(dst_calc_rules_ != no_rules) { + // dst + ss << dst_zone_abbrev(); + // dst offset + if(dst_offset().is_negative()) { + // inverting the sign guarantees we get two digits + ss << '-' << std::setw(2) << dst_offset().invert_sign().hours(); + } + else { + ss << '+' << std::setw(2) << dst_offset().hours(); + } + if(dst_offset().minutes() != 0 || dst_offset().seconds() != 0) { + ss << ':' << std::setw(2) << dst_offset().minutes(); + if(dst_offset().seconds() != 0) { + ss << ':' << std::setw(2) << dst_offset().seconds(); + } + } + // start/time + ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->start_rule_as_string()) << '/' + << std::setw(2) << dst_offsets_.dst_start_offset_.hours() << ':' + << std::setw(2) << dst_offsets_.dst_start_offset_.minutes(); + if(dst_offsets_.dst_start_offset_.seconds() != 0) { + ss << ':' << std::setw(2) << dst_offsets_.dst_start_offset_.seconds(); + } + // end/time + ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->end_rule_as_string()) << '/' + << std::setw(2) << dst_offsets_.dst_end_offset_.hours() << ':' + << std::setw(2) << dst_offsets_.dst_end_offset_.minutes(); + if(dst_offsets_.dst_end_offset_.seconds() != 0) { + ss << ':' << std::setw(2) << dst_offsets_.dst_end_offset_.seconds(); + } + } + + return ss.str(); + } + private: + time_zone_names zone_names_; + bool has_dst_; + time_duration_type base_utc_offset_; + dst_adjustment_offsets dst_offsets_; + boost::shared_ptr<dst_calc_rule> dst_calc_rules_; + }; + + typedef custom_time_zone_base<char> custom_time_zone; + +} }//namespace + + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/local_time/date_duration_operators.hpp b/3rdParty/Boost/src/boost/date_time/local_time/date_duration_operators.hpp new file mode 100644 index 0000000..ee87022 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/date_duration_operators.hpp @@ -0,0 +1,115 @@ +#ifndef LOCAL_TIME_DATE_DURATION_OPERATORS_HPP___ +#define LOCAL_TIME_DATE_DURATION_OPERATORS_HPP___ + +/* Copyright (c) 2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or + * http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + +#include "boost/date_time/gregorian/greg_duration_types.hpp" +#include "boost/date_time/local_time/local_date_time.hpp" + +namespace boost { +namespace local_time { + + /*!@file date_duration_operators.hpp Operators for local_date_time and + * optional gregorian types. Operators use snap-to-end-of-month behavior. + * Further details on this behavior can be found in reference for + * date_time/date_duration_types.hpp and documentation for + * month and year iterators. + */ + + + /*! Adds a months object and a local_date_time. Result will be same + * day-of-month as local_date_time unless original day was the last day of month. + * see date_time::months_duration for more details */ + inline + local_date_time + operator+(const local_date_time& t, const boost::gregorian::months& m) + { + return t + m.get_offset(t.utc_time().date()); + } + + /*! Adds a months object to a local_date_time. Result will be same + * day-of-month as local_date_time unless original day was the last day of month. + * see date_time::months_duration for more details */ + inline + local_date_time + operator+=(local_date_time& t, const boost::gregorian::months& m) + { + return t += m.get_offset(t.utc_time().date()); + } + + /*! Subtracts a months object and a local_date_time. Result will be same + * day-of-month as local_date_time unless original day was the last day of month. + * see date_time::months_duration for more details */ + inline + local_date_time + operator-(const local_date_time& t, const boost::gregorian::months& m) + { + // get_neg_offset returns a negative duration, so we add + return t + m.get_neg_offset(t.utc_time().date()); + } + + /*! Subtracts a months object from a local_date_time. Result will be same + * day-of-month as local_date_time unless original day was the last day of month. + * see date_time::months_duration for more details */ + inline + local_date_time + operator-=(local_date_time& t, const boost::gregorian::months& m) + { + // get_neg_offset returns a negative duration, so we add + return t += m.get_neg_offset(t.utc_time().date()); + } + + // local_date_time & years + + /*! Adds a years object and a local_date_time. Result will be same + * month and day-of-month as local_date_time unless original day was the + * last day of month. see date_time::years_duration for more details */ + inline + local_date_time + operator+(const local_date_time& t, const boost::gregorian::years& y) + { + return t + y.get_offset(t.utc_time().date()); + } + + /*! Adds a years object to a local_date_time. Result will be same + * month and day-of-month as local_date_time unless original day was the + * last day of month. see date_time::years_duration for more details */ + inline + local_date_time + operator+=(local_date_time& t, const boost::gregorian::years& y) + { + return t += y.get_offset(t.utc_time().date()); + } + + /*! Subtracts a years object and a local_date_time. Result will be same + * month and day-of-month as local_date_time unless original day was the + * last day of month. see date_time::years_duration for more details */ + inline + local_date_time + operator-(const local_date_time& t, const boost::gregorian::years& y) + { + // get_neg_offset returns a negative duration, so we add + return t + y.get_neg_offset(t.utc_time().date()); + } + + /*! Subtracts a years object from a local_date_time. Result will be same + * month and day-of-month as local_date_time unless original day was the + * last day of month. see date_time::years_duration for more details */ + inline + local_date_time + operator-=(local_date_time& t, const boost::gregorian::years& y) + { + // get_neg_offset returns a negative duration, so we add + return t += y.get_neg_offset(t.utc_time().date()); + } + + +}} // namespaces + +#endif // LOCAL_TIME_DATE_DURATION_OPERATORS_HPP___ diff --git a/3rdParty/Boost/src/boost/date_time/local_time/dst_transition_day_rules.hpp b/3rdParty/Boost/src/boost/date_time/local_time/dst_transition_day_rules.hpp new file mode 100644 index 0000000..3d6cfba --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/dst_transition_day_rules.hpp @@ -0,0 +1,77 @@ +#ifndef LOCAL_TIME_DST_TRANSITION_DAY_RULES_HPP__ +#define LOCAL_TIME_DST_TRANSITION_DAY_RULES_HPP__ + +/* Copyright (c) 2003-2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + + +#include "boost/date_time/gregorian/gregorian_types.hpp" +#include "boost/date_time/dst_transition_generators.hpp" + +namespace boost { +namespace local_time { + + //! Provides rule of the form starting Apr 30 ending Oct 21 + typedef date_time::dst_day_calc_rule<gregorian::date> dst_calc_rule; + + struct partial_date_rule_spec + { + typedef gregorian::date date_type; + typedef gregorian::partial_date start_rule; + typedef gregorian::partial_date end_rule; + }; + + //! Provides rule of the form first Sunday in April, last Saturday in Oct + typedef date_time::day_calc_dst_rule<partial_date_rule_spec> partial_date_dst_rule; + + struct first_last_rule_spec + { + typedef gregorian::date date_type; + typedef gregorian::first_kday_of_month start_rule; + typedef gregorian::last_kday_of_month end_rule; + }; + + //! Provides rule of the form first Sunday in April, last Saturday in Oct + typedef date_time::day_calc_dst_rule<first_last_rule_spec> first_last_dst_rule; + + struct last_last_rule_spec + { + typedef gregorian::date date_type; + typedef gregorian::last_kday_of_month start_rule; + typedef gregorian::last_kday_of_month end_rule; + }; + + //! Provides rule of the form last Sunday in April, last Saturday in Oct + typedef date_time::day_calc_dst_rule<last_last_rule_spec> last_last_dst_rule; + + struct nth_last_rule_spec + { + typedef gregorian::date date_type; + typedef gregorian::nth_kday_of_month start_rule; + typedef gregorian::last_kday_of_month end_rule; + }; + + //! Provides rule in form of [1st|2nd|3rd|4th] Sunday in April, last Sunday in Oct + typedef date_time::day_calc_dst_rule<nth_last_rule_spec> nth_last_dst_rule; + + struct nth_kday_rule_spec + { + typedef gregorian::date date_type; + typedef gregorian::nth_kday_of_month start_rule; + typedef gregorian::nth_kday_of_month end_rule; + }; + + //! Provides rule in form of [1st|2nd|3rd|4th] Sunday in April/October + typedef date_time::day_calc_dst_rule<nth_kday_rule_spec> nth_kday_dst_rule; + //! Provides rule in form of [1st|2nd|3rd|4th] Sunday in April/October + typedef date_time::day_calc_dst_rule<nth_kday_rule_spec> nth_day_of_the_week_in_month_dst_rule; + + +} }//namespace + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/local_time/local_date_time.hpp b/3rdParty/Boost/src/boost/date_time/local_time/local_date_time.hpp new file mode 100644 index 0000000..9c9f623 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/local_date_time.hpp @@ -0,0 +1,528 @@ +#ifndef LOCAL_TIME_LOCAL_DATE_TIME_HPP__ +#define LOCAL_TIME_LOCAL_DATE_TIME_HPP__ + +/* Copyright (c) 2003-2005 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2010-01-10 14:17:23 -0500 (Sun, 10 Jan 2010) $ + */ + +#include <string> +#include <iomanip> +#include <sstream> +#include <stdexcept> +#include <boost/shared_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/date_time/time.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> //todo remove? +#include <boost/date_time/dst_rules.hpp> +#include <boost/date_time/time_zone_base.hpp> +#include <boost/date_time/special_defs.hpp> +#include <boost/date_time/time_resolution_traits.hpp> // absolute_value + +namespace boost { +namespace local_time { + + //! simple exception for reporting when STD or DST cannot be determined + struct ambiguous_result : public std::logic_error + { + ambiguous_result (std::string const& msg = std::string()) : + std::logic_error(std::string("Daylight Savings Results are ambiguous: " + msg)) {} + }; + //! simple exception for when time label given cannot exist + struct time_label_invalid : public std::logic_error + { + time_label_invalid (std::string const& msg = std::string()) : + std::logic_error(std::string("Time label given is invalid: " + msg)) {} + }; + struct dst_not_valid: public std::logic_error + { + dst_not_valid(std::string const& msg = std::string()) : + std::logic_error(std::string("is_dst flag does not match resulting dst for time label given: " + msg)) {} + }; + + //TODO: I think these should be in local_date_time_base and not + // necessarily brought into the namespace + using date_time::time_is_dst_result; + using date_time::is_in_dst; + using date_time::is_not_in_dst; + using date_time::ambiguous; + using date_time::invalid_time_label; + + //! Representation of "wall-clock" time in a particular time zone + /*! Representation of "wall-clock" time in a particular time zone + * Local_date_time_base holds a time value (date and time offset from 00:00) + * along with a time zone. The time value is stored as UTC and conversions + * to wall clock time are made as needed. This approach allows for + * operations between wall-clock times in different time zones, and + * daylight savings time considerations, to be made. Time zones are + * required to be in the form of a boost::shared_ptr<time_zone_base>. + */ + template<class utc_time_=posix_time::ptime, + class tz_type=date_time::time_zone_base<utc_time_,char> > + class local_date_time_base : public date_time::base_time<utc_time_, + boost::posix_time::posix_time_system> { + public: + typedef utc_time_ utc_time_type; + typedef typename utc_time_type::time_duration_type time_duration_type; + typedef typename utc_time_type::date_type date_type; + typedef typename date_type::duration_type date_duration_type; + typedef typename utc_time_type::time_system_type time_system_type; + /*! This constructor interprets the passed time as a UTC time. + * So, for example, if the passed timezone is UTC-5 then the + * time will be adjusted back 5 hours. The time zone allows for + * automatic calculation of whether the particular time is adjusted for + * daylight savings, etc. + * If the time zone shared pointer is null then time stays unadjusted. + *@param t A UTC time + *@param tz Timezone for to adjust the UTC time to. + */ + local_date_time_base(utc_time_type t, + boost::shared_ptr<tz_type> tz) : + date_time::base_time<utc_time_type, time_system_type>(t), + zone_(tz) + { + // param was already utc so nothing more to do + } + + /*! This constructs a local time -- the passed time information + * understood to be in the passed tz. The DST flag must be passed + * to indicate whether the time is in daylight savings or not. + * @throws -- time_label_invalid if the time passed does not exist in + * the given locale. The non-existent case occurs typically + * during the shift-back from daylight savings time. When + * the clock is shifted forward a range of times + * (2 am to 3 am in the US) is skipped and hence is invalid. + * @throws -- dst_not_valid if the DST flag is passed for a period + * where DST is not active. + */ + local_date_time_base(date_type d, + time_duration_type td, + boost::shared_ptr<tz_type> tz, + bool dst_flag) : //necessary for constr_adj() + date_time::base_time<utc_time_type,time_system_type>(construction_adjustment(utc_time_type(d, td), tz, dst_flag)), + zone_(tz) + { + if(tz != boost::shared_ptr<tz_type>() && tz->has_dst()){ + + // d & td are already local so we use them + time_is_dst_result result = check_dst(d, td, tz); + bool in_dst = (result == is_in_dst); // less processing than is_dst() + + // ambig occurs at end, invalid at start + if(result == invalid_time_label){ + // Ex: 2:15am local on trans-in day in nyc, dst_flag irrelevant + std::ostringstream ss; + ss << "time given: " << d << ' ' << td; + boost::throw_exception(time_label_invalid(ss.str())); + } + else if(result != ambiguous && in_dst != dst_flag){ + // is dst_flag accurate? + // Ex: false flag in NYC in June + std::ostringstream ss; + ss.setf(std::ios_base::boolalpha); + ss << "flag given: dst=" << dst_flag << ", dst calculated: dst=" << in_dst; + boost::throw_exception(dst_not_valid(ss.str())); + } + + // everything checks out and conversion to utc already done + } + } + + //TODO maybe not the right set...Ignore the last 2 for now... + enum DST_CALC_OPTIONS { EXCEPTION_ON_ERROR, NOT_DATE_TIME_ON_ERROR }; + //ASSUME_DST_ON_ERROR, ASSUME_NOT_DST_ON_ERROR }; + + /*! This constructs a local time -- the passed time information + * understood to be in the passed tz. The DST flag is calculated + * according to the specified rule. + */ + local_date_time_base(date_type d, + time_duration_type td, + boost::shared_ptr<tz_type> tz, + DST_CALC_OPTIONS calc_option) : + // dummy value - time_ is set in constructor code + date_time::base_time<utc_time_type,time_system_type>(utc_time_type(d,td)), + zone_(tz) + { + time_is_dst_result result = check_dst(d, td, tz); + if(result == ambiguous) { + if(calc_option == EXCEPTION_ON_ERROR){ + std::ostringstream ss; + ss << "time given: " << d << ' ' << td; + boost::throw_exception(ambiguous_result(ss.str())); + } + else{ // NADT on error + this->time_ = posix_time::posix_time_system::get_time_rep(date_type(date_time::not_a_date_time), time_duration_type(date_time::not_a_date_time)); + } + } + else if(result == invalid_time_label){ + if(calc_option == EXCEPTION_ON_ERROR){ + std::ostringstream ss; + ss << "time given: " << d << ' ' << td; + boost::throw_exception(time_label_invalid(ss.str())); + } + else{ // NADT on error + this->time_ = posix_time::posix_time_system::get_time_rep(date_type(date_time::not_a_date_time), time_duration_type(date_time::not_a_date_time)); + } + } + else if(result == is_in_dst){ + utc_time_type t = + construction_adjustment(utc_time_type(d, td), tz, true); + this->time_ = posix_time::posix_time_system::get_time_rep(t.date(), + t.time_of_day()); + } + else{ + utc_time_type t = + construction_adjustment(utc_time_type(d, td), tz, false); + this->time_ = posix_time::posix_time_system::get_time_rep(t.date(), + t.time_of_day()); + } + } + + + //! Determines if given time label is in daylight savings for given zone + /*! Determines if given time label is in daylight savings for given zone. + * Takes a date and time_duration representing a local time, along + * with time zone, and returns a time_is_dst_result object as result. + */ + static time_is_dst_result check_dst(date_type d, + time_duration_type td, + boost::shared_ptr<tz_type> tz) + { + if(tz != boost::shared_ptr<tz_type>() && tz->has_dst()) { + typedef typename date_time::dst_calculator<date_type, time_duration_type> dst_calculator; + return dst_calculator::local_is_dst( + d, td, + tz->dst_local_start_time(d.year()).date(), + tz->dst_local_start_time(d.year()).time_of_day(), + tz->dst_local_end_time(d.year()).date(), + tz->dst_local_end_time(d.year()).time_of_day(), + tz->dst_offset() + ); + } + else{ + return is_not_in_dst; + } + } + + //! Simple destructor, releases time zone if last referrer + ~local_date_time_base() {}; + + //! Copy constructor + local_date_time_base(const local_date_time_base& rhs) : + date_time::base_time<utc_time_type, time_system_type>(rhs), + zone_(rhs.zone_) + {} + + //! Special values constructor + explicit local_date_time_base(const boost::date_time::special_values sv, + boost::shared_ptr<tz_type> tz = boost::shared_ptr<tz_type>()) : + date_time::base_time<utc_time_type, time_system_type>(utc_time_type(sv)), + zone_(tz) + {} + + //! returns time zone associated with calling instance + boost::shared_ptr<tz_type> zone() const + { + return zone_; + } + //! returns false is time_zone is NULL and if time value is a special_value + bool is_dst() const + { + if(zone_ != boost::shared_ptr<tz_type>() && zone_->has_dst() && !this->is_special()) { + // check_dst takes a local time, *this is utc + utc_time_type lt(this->time_); + lt += zone_->base_utc_offset(); + // dst_offset only needs to be considered with ambiguous time labels + // make that adjustment there + + switch(check_dst(lt.date(), lt.time_of_day(), zone_)){ + case is_not_in_dst: + return false; + case is_in_dst: + return true; + case ambiguous: + if(lt + zone_->dst_offset() < zone_->dst_local_end_time(lt.date().year())) { + return true; + } + break; + case invalid_time_label: + if(lt >= zone_->dst_local_start_time(lt.date().year())) { + return true; + } + break; + } + } + return false; + } + //! Returns object's time value as a utc representation + utc_time_type utc_time() const + { + return utc_time_type(this->time_); + } + //! Returns object's time value as a local representation + utc_time_type local_time() const + { + if(zone_ != boost::shared_ptr<tz_type>()){ + utc_time_type lt = this->utc_time() + zone_->base_utc_offset(); + if (is_dst()) { + lt += zone_->dst_offset(); + } + return lt; + } + return utc_time_type(this->time_); + } + //! Returns string in the form "2003-Aug-20 05:00:00 EDT" + /*! Returns string in the form "2003-Aug-20 05:00:00 EDT". If + * time_zone is NULL the time zone abbreviation will be "UTC". The time + * zone abbrev will not be included if calling object is a special_value*/ + std::string to_string() const + { + //TODO is this a temporary function ??? + std::ostringstream ss; + if(this->is_special()){ + ss << utc_time(); + return ss.str(); + } + if(zone_ == boost::shared_ptr<tz_type>()) { + ss << utc_time() << " UTC"; + return ss.str(); + } + bool is_dst_ = is_dst(); + utc_time_type lt = this->utc_time() + zone_->base_utc_offset(); + if (is_dst_) { + lt += zone_->dst_offset(); + } + ss << local_time() << " "; + if (is_dst()) { + ss << zone_->dst_zone_abbrev(); + } + else { + ss << zone_->std_zone_abbrev(); + } + return ss.str(); + } + /*! returns a local_date_time_base in the given time zone with the + * optional time_duration added. */ + local_date_time_base local_time_in(boost::shared_ptr<tz_type> new_tz, + time_duration_type td=time_duration_type(0,0,0)) const + { + return local_date_time_base(utc_time_type(this->time_) + td, new_tz); + } + + //! Returns name of associated time zone or "Coordinated Universal Time". + /*! Optional bool parameter will return time zone as an offset + * (ie "+07:00" extended iso format). Empty string is returned for + * classes that do not use a time_zone */ + std::string zone_name(bool as_offset=false) const + { + if(zone_ == boost::shared_ptr<tz_type>()) { + if(as_offset) { + return std::string("Z"); + } + else { + return std::string("Coordinated Universal Time"); + } + } + if (is_dst()) { + if(as_offset) { + time_duration_type td = zone_->base_utc_offset(); + td += zone_->dst_offset(); + return zone_as_offset(td, ":"); + } + else { + return zone_->dst_zone_name(); + } + } + else { + if(as_offset) { + time_duration_type td = zone_->base_utc_offset(); + return zone_as_offset(td, ":"); + } + else { + return zone_->std_zone_name(); + } + } + } + //! Returns abbreviation of associated time zone or "UTC". + /*! Optional bool parameter will return time zone as an offset + * (ie "+0700" iso format). Empty string is returned for classes + * that do not use a time_zone */ + std::string zone_abbrev(bool as_offset=false) const + { + if(zone_ == boost::shared_ptr<tz_type>()) { + if(as_offset) { + return std::string("Z"); + } + else { + return std::string("UTC"); + } + } + if (is_dst()) { + if(as_offset) { + time_duration_type td = zone_->base_utc_offset(); + td += zone_->dst_offset(); + return zone_as_offset(td, ""); + } + else { + return zone_->dst_zone_abbrev(); + } + } + else { + if(as_offset) { + time_duration_type td = zone_->base_utc_offset(); + return zone_as_offset(td, ""); + } + else { + return zone_->std_zone_abbrev(); + } + } + } + + //! returns a posix_time_zone string for the associated time_zone. If no time_zone, "UTC+00" is returned. + std::string zone_as_posix_string() const + { + if(zone_ == shared_ptr<tz_type>()) { + return std::string("UTC+00"); + } + return zone_->to_posix_string(); + } + + //! Equality comparison operator + /*bool operator==(const date_time::base_time<boost::posix_time::ptime,boost::posix_time::posix_time_system>& rhs) const + { // fails due to rhs.time_ being protected + return date_time::base_time<boost::posix_time::ptime,boost::posix_time::posix_time_system>::operator==(rhs); + //return this->time_ == rhs.time_; + }*/ + //! Equality comparison operator + bool operator==(const local_date_time_base& rhs) const + { + return time_system_type::is_equal(this->time_, rhs.time_); + } + //! Non-Equality comparison operator + bool operator!=(const local_date_time_base& rhs) const + { + return !(*this == rhs); + } + //! Less than comparison operator + bool operator<(const local_date_time_base& rhs) const + { + return time_system_type::is_less(this->time_, rhs.time_); + } + //! Less than or equal to comparison operator + bool operator<=(const local_date_time_base& rhs) const + { + return (*this < rhs || *this == rhs); + } + //! Greater than comparison operator + bool operator>(const local_date_time_base& rhs) const + { + return !(*this <= rhs); + } + //! Greater than or equal to comparison operator + bool operator>=(const local_date_time_base& rhs) const + { + return (*this > rhs || *this == rhs); + } + + //! Local_date_time + date_duration + local_date_time_base operator+(const date_duration_type& dd) const + { + return local_date_time_base(time_system_type::add_days(this->time_,dd), zone_); + } + //! Local_date_time += date_duration + local_date_time_base operator+=(const date_duration_type& dd) + { + this->time_ = time_system_type::add_days(this->time_,dd); + return *this; + } + //! Local_date_time - date_duration + local_date_time_base operator-(const date_duration_type& dd) const + { + return local_date_time_base(time_system_type::subtract_days(this->time_,dd), zone_); + } + //! Local_date_time -= date_duration + local_date_time_base operator-=(const date_duration_type& dd) + { + this->time_ = time_system_type::subtract_days(this->time_,dd); + return *this; + } + //! Local_date_time + time_duration + local_date_time_base operator+(const time_duration_type& td) const + { + return local_date_time_base(time_system_type::add_time_duration(this->time_,td), zone_); + } + //! Local_date_time += time_duration + local_date_time_base operator+=(const time_duration_type& td) + { + this->time_ = time_system_type::add_time_duration(this->time_,td); + return *this; + } + //! Local_date_time - time_duration + local_date_time_base operator-(const time_duration_type& td) const + { + return local_date_time_base(time_system_type::subtract_time_duration(this->time_,td), zone_); + } + //! Local_date_time -= time_duration + local_date_time_base operator-=(const time_duration_type& td) + { + this->time_ = time_system_type::subtract_time_duration(this->time_,td); + return *this; + } + //! local_date_time -= local_date_time --> time_duration_type + time_duration_type operator-(const local_date_time_base& rhs) const + { + return utc_time_type(this->time_) - utc_time_type(rhs.time_); + } + private: + boost::shared_ptr<tz_type> zone_; + //bool is_dst_; + + /*! Adjust the passed in time to UTC? + */ + utc_time_type construction_adjustment(utc_time_type t, + boost::shared_ptr<tz_type> z, + bool dst_flag) + { + if(z != boost::shared_ptr<tz_type>()) { + if(dst_flag && z->has_dst()) { + t -= z->dst_offset(); + } // else no adjust + t -= z->base_utc_offset(); + } + return t; + } + + /*! Simple formatting code -- todo remove this? + */ + std::string zone_as_offset(const time_duration_type& td, + const std::string& separator) const + { + std::ostringstream ss; + if(td.is_negative()) { + // a negative duration is represented as "-[h]h:mm" + // we require two digits for the hour. A positive duration + // with the %H flag will always give two digits + ss << "-"; + } + else { + ss << "+"; + } + ss << std::setw(2) << std::setfill('0') + << date_time::absolute_value(td.hours()) + << separator + << std::setw(2) << std::setfill('0') + << date_time::absolute_value(td.minutes()); + return ss.str(); + } + }; + + //!Use the default parameters to define local_date_time + typedef local_date_time_base<> local_date_time; + +} } + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/local_time/local_time.hpp b/3rdParty/Boost/src/boost/date_time/local_time/local_time.hpp new file mode 100644 index 0000000..f7d4cc6 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/local_time.hpp @@ -0,0 +1,24 @@ +#ifndef LOCAL_TIME_LOCAL_TIME_HPP__ +#define LOCAL_TIME_LOCAL_TIME_HPP__ + +/* Copyright (c) 2003-2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + +#include "boost/date_time/posix_time/posix_time.hpp" +#include "boost/date_time/local_time/local_date_time.hpp" +#include "boost/date_time/local_time/local_time_types.hpp" +#if !defined(USE_DATE_TIME_PRE_1_33_FACET_IO) +#include "boost/date_time/local_time/local_time_io.hpp" +#endif // USE_DATE_TIME_PRE_1_33_FACET_IO +#include "boost/date_time/local_time/posix_time_zone.hpp" +#include "boost/date_time/local_time/custom_time_zone.hpp" +#include "boost/date_time/local_time/tz_database.hpp" +#include "boost/date_time/local_time/conversion.hpp" +#include "boost/date_time/time_zone_base.hpp" + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/local_time/local_time_io.hpp b/3rdParty/Boost/src/boost/date_time/local_time/local_time_io.hpp new file mode 100644 index 0000000..c161ff7 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/local_time_io.hpp @@ -0,0 +1,186 @@ +#ifndef BOOST_DATE_TIME_LOCAL_TIME_IO_HPP__ +#define BOOST_DATE_TIME_LOCAL_TIME_IO_HPP__ + +/* Copyright (c) 2003-2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-13 14:05:31 -0500 (Thu, 13 Nov 2008) $ + */ + +#include <locale> +#include <iostream> +#include <iterator> // i/ostreambuf_iterator +#include <boost/io/ios_state.hpp> +#include <boost/date_time/time_facet.hpp> +#include <boost/date_time/string_convert.hpp> +#include <boost/date_time/local_time/local_date_time.hpp> +#include <boost/date_time/local_time/posix_time_zone.hpp> +#include <boost/date_time/local_time/conversion.hpp> // to_tm will be needed in the facets + +namespace boost { +namespace local_time { + + typedef boost::date_time::time_facet<local_date_time, wchar_t> wlocal_time_facet; + typedef boost::date_time::time_facet<local_date_time, char> local_time_facet; + + typedef boost::date_time::time_input_facet<local_date_time::utc_time_type,wchar_t> wlocal_time_input_facet; + typedef boost::date_time::time_input_facet<local_date_time::utc_time_type,char> local_time_input_facet; + + //! operator<< for local_date_time - see local_time docs for formatting details + template<class CharT, class TraitsT> + inline + std::basic_ostream<CharT, TraitsT>& + operator<<(std::basic_ostream<CharT, TraitsT>& os, const local_date_time& ldt) + { + boost::io::ios_flags_saver iflags(os); + typedef local_date_time time_type;//::utc_time_type typename + typedef date_time::time_facet<time_type, CharT> custom_time_facet; + typedef std::time_put<CharT> std_time_facet; + std::ostreambuf_iterator<CharT> oitr(os); + + if(std::has_facet<custom_time_facet>(os.getloc())) { + std::use_facet<custom_time_facet>(os.getloc()).put(oitr, + os, + os.fill(), + ldt); + } + else { + custom_time_facet* f = new custom_time_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(oitr, os, os.fill(), ldt); + } + + return os; + } + + + //! input operator for local_date_time + template <class CharT, class Traits> + inline + std::basic_istream<CharT, Traits>& + operator>>(std::basic_istream<CharT, Traits>& is, local_date_time& ldt) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename local_date_time::utc_time_type utc_time_type; + typedef typename date_time::time_input_facet<utc_time_type, CharT> time_input_facet; + + // intermediate objects + std::basic_string<CharT> tz_str; + utc_time_type pt(not_a_date_time); + + std::istreambuf_iterator<CharT,Traits> sit(is), str_end; + if(std::has_facet<time_input_facet>(is.getloc())) { + std::use_facet<time_input_facet>(is.getloc()).get_local_time(sit, str_end, is, pt, tz_str); + } + else { + time_input_facet* f = new time_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get_local_time(sit, str_end, is, pt, tz_str); + } + if(tz_str.empty()) { + time_zone_ptr null_ptr; + // a null time_zone_ptr creates a local_date_time that is UTC + ldt = local_date_time(pt, null_ptr); + } + else { + time_zone_ptr tz_ptr(new posix_time_zone(date_time::convert_string_type<CharT,char>(tz_str))); + // the "date & time" constructor expects the time label to *not* be utc. + // a posix_tz_string also expects the time label to *not* be utc. + ldt = local_date_time(pt.date(), pt.time_of_day(), tz_ptr, local_date_time::EXCEPTION_ON_ERROR); + } + } + catch(...) { + // mask tells us what exceptions are turned on + std::ios_base::iostate exception_mask = is.exceptions(); + // if the user wants exceptions on failbit, we'll rethrow our + // date_time exception & set the failbit + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} // ignore this one + throw; // rethrow original exception + } + else { + // if the user want's to fail quietly, we simply set the failbit + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + + //! output operator for local_time_period + template <class CharT, class TraitsT> + inline + std::basic_ostream<CharT, TraitsT>& + operator<<(std::basic_ostream<CharT, TraitsT>& os, + const boost::local_time::local_time_period& p) { + boost::io::ios_flags_saver iflags(os); + typedef boost::date_time::time_facet<local_date_time, CharT> custom_facet; + typedef std::time_put<CharT> std_time_facet; + std::ostreambuf_iterator<CharT> oitr(os); + if (std::has_facet<custom_facet>(os.getloc())) { + std::use_facet<custom_facet>(os.getloc()).put(oitr, os, os.fill(), p); + } + else { + //instantiate a custom facet for dealing with periods since the user + //has not put one in the stream so far. This is for efficiency + //since we would always need to reconstruct for every time period + //if the local did not already exist. Of course this will be overridden + //if the user imbues as some later point. + custom_facet* f = new custom_facet(); + std::locale l = std::locale(os.getloc(), f); + os.imbue(l); + f->put(oitr, os, os.fill(), p); + } + return os; + } + + //! input operator for local_time_period + template <class CharT, class Traits> + inline + std::basic_istream<CharT, Traits>& + operator>>(std::basic_istream<CharT, Traits>& is, boost::local_time::local_time_period& tp) + { + boost::io::ios_flags_saver iflags(is); + typename std::basic_istream<CharT, Traits>::sentry strm_sentry(is, false); + if (strm_sentry) { + try { + typedef typename date_time::time_input_facet<local_date_time, CharT> time_input_facet; + + std::istreambuf_iterator<CharT,Traits> sit(is), str_end; + if(std::has_facet<time_input_facet>(is.getloc())) { + std::use_facet<time_input_facet>(is.getloc()).get(sit, str_end, is, tp); + } + else { + time_input_facet* f = new time_input_facet(); + std::locale l = std::locale(is.getloc(), f); + is.imbue(l); + f->get(sit, str_end, is, tp); + } + } + catch(...) { + std::ios_base::iostate exception_mask = is.exceptions(); + if(std::ios_base::failbit & exception_mask) { + try { is.setstate(std::ios_base::failbit); } + catch(std::ios_base::failure&) {} + throw; // rethrow original exception + } + else { + is.setstate(std::ios_base::failbit); + } + + } + } + return is; + } + +} } // namespaces + +#endif // BOOST_DATE_TIME_LOCAL_TIME_IO_HPP__ diff --git a/3rdParty/Boost/src/boost/date_time/local_time/local_time_types.hpp b/3rdParty/Boost/src/boost/date_time/local_time/local_time_types.hpp new file mode 100644 index 0000000..ed58b80 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/local_time_types.hpp @@ -0,0 +1,52 @@ +#ifndef LOCAL_TIME_LOCAL_TIME_TYPES_HPP__ +#define LOCAL_TIME_LOCAL_TIME_TYPES_HPP__ + +/* Copyright (c) 2003-2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + +#include "boost/date_time/local_time/local_date_time.hpp" +#include "boost/date_time/period.hpp" +#include "boost/date_time/time_iterator.hpp" +#include "boost/date_time/compiler_config.hpp" +#if defined(BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES) +#include "boost/date_time/local_time/date_duration_operators.hpp" +#endif //BOOST_DATE_TIME_OPTIONAL_GREGORIAN_TYPES +#include "boost/date_time/local_time/custom_time_zone.hpp" + +namespace boost { +namespace local_time { + + typedef boost::date_time::period<local_date_time, + boost::posix_time::time_duration> local_time_period; + + typedef date_time::time_itr<local_date_time> local_time_iterator; + + typedef date_time::second_clock<local_date_time> local_sec_clock; + typedef date_time::microsec_clock<local_date_time> local_microsec_clock; + + typedef date_time::time_zone_base<posix_time::ptime, char> time_zone; + typedef date_time::time_zone_base<posix_time::ptime, wchar_t> wtime_zone; + + //! Shared Pointer for custom_time_zone and posix_time_zone objects + typedef boost::shared_ptr<time_zone> time_zone_ptr; + typedef boost::shared_ptr<wtime_zone> wtime_zone_ptr; + + typedef date_time::time_zone_names_base<char> time_zone_names; + typedef date_time::time_zone_names_base<wchar_t> wtime_zone_names; + + //bring special enum values into the namespace + using date_time::special_values; + using date_time::not_special; + using date_time::neg_infin; + using date_time::pos_infin; + using date_time::not_a_date_time; + using date_time::max_date_time; + using date_time::min_date_time; + +}} // namespaces + +#endif // LOCAL_TIME_LOCAL_TIME_TYPES_HPP__ diff --git a/3rdParty/Boost/src/boost/date_time/local_time/posix_time_zone.hpp b/3rdParty/Boost/src/boost/date_time/local_time/posix_time_zone.hpp new file mode 100644 index 0000000..2a0199f --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/posix_time_zone.hpp @@ -0,0 +1,474 @@ +#ifndef _DATE_TIME_POSIX_TIME_ZONE__ +#define _DATE_TIME_POSIX_TIME_ZONE__ + +/* Copyright (c) 2003-2005 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2010-06-10 13:24:38 -0400 (Thu, 10 Jun 2010) $ + */ + +#include <string> +#include <sstream> +#include <stdexcept> +#include <boost/tokenizer.hpp> +#include <boost/throw_exception.hpp> +#include <boost/date_time/gregorian/gregorian.hpp> +#include <boost/date_time/time_zone_names.hpp> +#include <boost/date_time/time_zone_base.hpp> +#include <boost/date_time/local_time/dst_transition_day_rules.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/string_convert.hpp> +#include <boost/date_time/time_parsing.hpp> + +namespace boost{ +namespace local_time{ + + //! simple exception for UTC and Daylight savings start/end offsets + struct bad_offset : public std::out_of_range + { + bad_offset(std::string const& msg = std::string()) : + std::out_of_range(std::string("Offset out of range: " + msg)) {} + }; + //! simple exception for UTC daylight savings adjustment + struct bad_adjustment : public std::out_of_range + { + bad_adjustment(std::string const& msg = std::string()) : + std::out_of_range(std::string("Adjustment out of range: " + msg)) {} + }; + + typedef boost::date_time::dst_adjustment_offsets<boost::posix_time::time_duration> dst_adjustment_offsets; + + //! A time zone class constructed from a POSIX time zone string + /*! A POSIX time zone string takes the form of:<br> + * "std offset dst [offset],start[/time],end[/time]" (w/no spaces) + * 'std' specifies the abbrev of the time zone.<br> + * 'offset' is the offset from UTC.<br> + * 'dst' specifies the abbrev of the time zone during daylight savings time.<br> + * The second offset is how many hours changed during DST. Default=1<br> + * 'start' and'end' are the dates when DST goes into (and out of) effect.<br> + * 'offset' takes the form of: [+|-]hh[:mm[:ss]] {h=0-23, m/s=0-59}<br> + * 'time' and 'offset' take the same form. Time defaults=02:00:00<br> + * 'start' and 'end' can be one of three forms:<br> + * Mm.w.d {month=1-12, week=1-5 (5 is always last), day=0-6}<br> + * Jn {n=1-365 Feb29 is never counted}<br> + * n {n=0-365 Feb29 is counted in leap years}<br> + * Example "PST-5PDT01:00:00,M4.1.0/02:00:00,M10.1.0/02:00:00" + * <br> + * Exceptions will be thrown under these conditions:<br> + * An invalid date spec (see date class)<br> + * A boost::local_time::bad_offset exception will be thrown for:<br> + * A DST start or end offset that is negative or more than 24 hours<br> + * A UTC zone that is greater than +14 or less than -12 hours<br> + * A boost::local_time::bad_adjustment exception will be thrown for:<br> + * A DST adjustment that is 24 hours or more (positive or negative)<br> + * + * Note that UTC zone offsets can be greater than +12: + * http://www.worldtimezone.com/utc/utc+1200.html + */ + template<class CharT> + class posix_time_zone_base : public date_time::time_zone_base<posix_time::ptime,CharT> { + public: + typedef boost::posix_time::time_duration time_duration_type; + typedef date_time::time_zone_names_base<CharT> time_zone_names; + typedef date_time::time_zone_base<posix_time::ptime,CharT> base_type; + typedef typename base_type::string_type string_type; + typedef CharT char_type; + typedef typename base_type::stringstream_type stringstream_type; + typedef boost::char_separator<char_type, std::char_traits<char_type> > char_separator_type; + typedef boost::tokenizer<char_separator_type, + typename string_type::const_iterator, + string_type> tokenizer_type; + typedef typename tokenizer_type::iterator tokenizer_iterator_type; + + //! Construct from a POSIX time zone string + posix_time_zone_base(const string_type& s) : + //zone_names_("std_name","std_abbrev","no-dst","no-dst"), + zone_names_(), + has_dst_(false), + base_utc_offset_(posix_time::hours(0)), + dst_offsets_(posix_time::hours(0),posix_time::hours(0),posix_time::hours(0)), + dst_calc_rules_() + { +#ifdef __HP_aCC + // Work around bug in aC++ compiler: see QXCR1000880488 in the + // HP bug tracking system + const char_type sep_chars[2] = {',',0}; +#else + const char_type sep_chars[2] = {','}; +#endif + char_separator_type sep(sep_chars); + tokenizer_type tokens(s, sep); + tokenizer_iterator_type it = tokens.begin(), end = tokens.end(); + if (it == end) + BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse time zone name")); + calc_zone(*it++); + if(has_dst_) + { + if (it == end) + BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse DST begin time")); + string_type dst_begin = *it++; + + if (it == end) + BOOST_THROW_EXCEPTION(std::invalid_argument("Could not parse DST end time")); + string_type dst_end = *it; + calc_rules(dst_begin, dst_end); + } + } + virtual ~posix_time_zone_base() {}; + //!String for the zone when not in daylight savings (eg: EST) + virtual string_type std_zone_abbrev()const + { + return zone_names_.std_zone_abbrev(); + } + //!String for the timezone when in daylight savings (eg: EDT) + /*! For those time zones that have no DST, an empty string is used */ + virtual string_type dst_zone_abbrev() const + { + return zone_names_.dst_zone_abbrev(); + } + //!String for the zone when not in daylight savings (eg: Eastern Standard Time) + /*! The full STD name is not extracted from the posix time zone string. + * Therefore, the STD abbreviation is used in it's place */ + virtual string_type std_zone_name()const + { + return zone_names_.std_zone_name(); + } + //!String for the timezone when in daylight savings (eg: Eastern Daylight Time) + /*! The full DST name is not extracted from the posix time zone string. + * Therefore, the STD abbreviation is used in it's place. For time zones + * that have no DST, an empty string is used */ + virtual string_type dst_zone_name()const + { + return zone_names_.dst_zone_name(); + } + //! True if zone uses daylight savings adjustments otherwise false + virtual bool has_dst()const + { + return has_dst_; + } + //! Local time that DST starts -- NADT if has_dst is false + virtual posix_time::ptime dst_local_start_time(gregorian::greg_year y)const + { + gregorian::date d(gregorian::not_a_date_time); + if(has_dst_) + { + d = dst_calc_rules_->start_day(y); + } + return posix_time::ptime(d, dst_offsets_.dst_start_offset_); + } + //! Local time that DST ends -- NADT if has_dst is false + virtual posix_time::ptime dst_local_end_time(gregorian::greg_year y)const + { + gregorian::date d(gregorian::not_a_date_time); + if(has_dst_) + { + d = dst_calc_rules_->end_day(y); + } + return posix_time::ptime(d, dst_offsets_.dst_end_offset_); + } + //! Base offset from UTC for zone (eg: -07:30:00) + virtual time_duration_type base_utc_offset()const + { + return base_utc_offset_; + } + //! Adjustment forward or back made while DST is in effect + virtual time_duration_type dst_offset()const + { + return dst_offsets_.dst_adjust_; + } + + //! Returns a POSIX time_zone string for this object + virtual string_type to_posix_string() const + { + // std offset dst [offset],start[/time],end[/time] - w/o spaces + stringstream_type ss; + ss.fill('0'); + boost::shared_ptr<dst_calc_rule> no_rules; + // std + ss << std_zone_abbrev(); + // offset + if(base_utc_offset().is_negative()) { + // inverting the sign guarantees we get two digits + ss << '-' << std::setw(2) << base_utc_offset().invert_sign().hours(); + } + else { + ss << '+' << std::setw(2) << base_utc_offset().hours(); + } + if(base_utc_offset().minutes() != 0 || base_utc_offset().seconds() != 0) { + ss << ':' << std::setw(2) << base_utc_offset().minutes(); + if(base_utc_offset().seconds() != 0) { + ss << ':' << std::setw(2) << base_utc_offset().seconds(); + } + } + if(dst_calc_rules_ != no_rules) { + // dst + ss << dst_zone_abbrev(); + // dst offset + if(dst_offset().is_negative()) { + // inverting the sign guarantees we get two digits + ss << '-' << std::setw(2) << dst_offset().invert_sign().hours(); + } + else { + ss << '+' << std::setw(2) << dst_offset().hours(); + } + if(dst_offset().minutes() != 0 || dst_offset().seconds() != 0) { + ss << ':' << std::setw(2) << dst_offset().minutes(); + if(dst_offset().seconds() != 0) { + ss << ':' << std::setw(2) << dst_offset().seconds(); + } + } + // start/time + ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->start_rule_as_string()) << '/' + << std::setw(2) << dst_offsets_.dst_start_offset_.hours() << ':' + << std::setw(2) << dst_offsets_.dst_start_offset_.minutes(); + if(dst_offsets_.dst_start_offset_.seconds() != 0) { + ss << ':' << std::setw(2) << dst_offsets_.dst_start_offset_.seconds(); + } + // end/time + ss << ',' << date_time::convert_string_type<char, char_type>(dst_calc_rules_->end_rule_as_string()) << '/' + << std::setw(2) << dst_offsets_.dst_end_offset_.hours() << ':' + << std::setw(2) << dst_offsets_.dst_end_offset_.minutes(); + if(dst_offsets_.dst_end_offset_.seconds() != 0) { + ss << ':' << std::setw(2) << dst_offsets_.dst_end_offset_.seconds(); + } + } + + return ss.str(); + } + private: + time_zone_names zone_names_; + bool has_dst_; + time_duration_type base_utc_offset_; + dst_adjustment_offsets dst_offsets_; + boost::shared_ptr<dst_calc_rule> dst_calc_rules_; + + /*! Extract time zone abbreviations for STD & DST as well + * as the offsets for the time shift that occurs and how + * much of a shift. At this time full time zone names are + * NOT extracted so the abbreviations are used in their place */ + void calc_zone(const string_type& obj){ + const char_type empty_string[2] = {'\0'}; + stringstream_type ss(empty_string); + typename string_type::const_pointer sit = obj.c_str(), obj_end = sit + obj.size(); + string_type l_std_zone_abbrev, l_dst_zone_abbrev; + + // get 'std' name/abbrev + while(std::isalpha(*sit)){ + ss << *sit++; + } + l_std_zone_abbrev = ss.str(); + ss.str(empty_string); + + // get UTC offset + if(sit != obj_end){ + // get duration + while(sit != obj_end && !std::isalpha(*sit)){ + ss << *sit++; + } + base_utc_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str()); + ss.str(empty_string); + + // base offset must be within range of -12 hours to +14 hours + if(base_utc_offset_ < time_duration_type(-12,0,0) || + base_utc_offset_ > time_duration_type(14,0,0)) + { + boost::throw_exception(bad_offset(posix_time::to_simple_string(base_utc_offset_))); + } + } + + // get DST data if given + if(sit != obj_end){ + has_dst_ = true; + + // get 'dst' name/abbrev + while(sit != obj_end && std::isalpha(*sit)){ + ss << *sit++; + } + l_dst_zone_abbrev = ss.str(); + ss.str(empty_string); + + // get DST offset if given + if(sit != obj_end){ + // get duration + while(sit != obj_end && !std::isalpha(*sit)){ + ss << *sit++; + } + dst_offsets_.dst_adjust_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(ss.str()); + ss.str(empty_string); + } + else{ // default DST offset + dst_offsets_.dst_adjust_ = posix_time::hours(1); + } + + // adjustment must be within +|- 1 day + if(dst_offsets_.dst_adjust_ <= time_duration_type(-24,0,0) || + dst_offsets_.dst_adjust_ >= time_duration_type(24,0,0)) + { + boost::throw_exception(bad_adjustment(posix_time::to_simple_string(dst_offsets_.dst_adjust_))); + } + } + // full names not extracted so abbrevs used in their place + zone_names_ = time_zone_names(l_std_zone_abbrev, l_std_zone_abbrev, l_dst_zone_abbrev, l_dst_zone_abbrev); + } + + void calc_rules(const string_type& start, const string_type& end){ +#ifdef __HP_aCC + // Work around bug in aC++ compiler: see QXCR1000880488 in the + // HP bug tracking system + const char_type sep_chars[2] = {'/',0}; +#else + const char_type sep_chars[2] = {'/'}; +#endif + char_separator_type sep(sep_chars); + tokenizer_type st_tok(start, sep); + tokenizer_type et_tok(end, sep); + tokenizer_iterator_type sit = st_tok.begin(); + tokenizer_iterator_type eit = et_tok.begin(); + + // generate date spec + char_type x = string_type(*sit).at(0); + if(x == 'M'){ + M_func(*sit, *eit); + } + else if(x == 'J'){ + julian_no_leap(*sit, *eit); + } + else{ + julian_day(*sit, *eit); + } + + ++sit; + ++eit; + // generate durations + // starting offset + if(sit != st_tok.end()){ + dst_offsets_.dst_start_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(*sit); + } + else{ + // default + dst_offsets_.dst_start_offset_ = posix_time::hours(2); + } + // start/end offsets must fall on given date + if(dst_offsets_.dst_start_offset_ < time_duration_type(0,0,0) || + dst_offsets_.dst_start_offset_ >= time_duration_type(24,0,0)) + { + boost::throw_exception(bad_offset(posix_time::to_simple_string(dst_offsets_.dst_start_offset_))); + } + + // ending offset + if(eit != et_tok.end()){ + dst_offsets_.dst_end_offset_ = date_time::str_from_delimited_time_duration<time_duration_type,char_type>(*eit); + } + else{ + // default + dst_offsets_.dst_end_offset_ = posix_time::hours(2); + } + // start/end offsets must fall on given date + if(dst_offsets_.dst_end_offset_ < time_duration_type(0,0,0) || + dst_offsets_.dst_end_offset_ >= time_duration_type(24,0,0)) + { + boost::throw_exception(bad_offset(posix_time::to_simple_string(dst_offsets_.dst_end_offset_))); + } + } + + /* Parses out a start/end date spec from a posix time zone string. + * Date specs come in three possible formats, this function handles + * the 'M' spec. Ex "M2.2.4" => 2nd month, 2nd week, 4th day . + */ + void M_func(const string_type& s, const string_type& e){ + typedef gregorian::nth_kday_of_month nkday; + unsigned short sm=0,sw=0,sd=0,em=0,ew=0,ed=0; // start/end month,week,day +#ifdef __HP_aCC + // Work around bug in aC++ compiler: see QXCR1000880488 in the + // HP bug tracking system + const char_type sep_chars[3] = {'M','.',0}; +#else + const char_type sep_chars[3] = {'M','.'}; +#endif + char_separator_type sep(sep_chars); + tokenizer_type stok(s, sep), etok(e, sep); + + tokenizer_iterator_type it = stok.begin(); + sm = lexical_cast<unsigned short>(*it++); + sw = lexical_cast<unsigned short>(*it++); + sd = lexical_cast<unsigned short>(*it); + + it = etok.begin(); + em = lexical_cast<unsigned short>(*it++); + ew = lexical_cast<unsigned short>(*it++); + ed = lexical_cast<unsigned short>(*it); + + dst_calc_rules_ = shared_ptr<dst_calc_rule>( + new nth_kday_dst_rule( + nth_last_dst_rule::start_rule( + static_cast<nkday::week_num>(sw),sd,sm), + nth_last_dst_rule::start_rule( + static_cast<nkday::week_num>(ew),ed,em) + ) + ); + } + + //! Julian day. Feb29 is never counted, even in leap years + // expects range of 1-365 + void julian_no_leap(const string_type& s, const string_type& e){ + typedef gregorian::gregorian_calendar calendar; + const unsigned short year = 2001; // Non-leap year + unsigned short sm=1; + int sd=0; + sd = lexical_cast<int>(s.substr(1)); // skip 'J' + while(sd >= calendar::end_of_month_day(year,sm)){ + sd -= calendar::end_of_month_day(year,sm++); + } + unsigned short em=1; + int ed=0; + ed = lexical_cast<int>(e.substr(1)); // skip 'J' + while(ed > calendar::end_of_month_day(year,em)){ + ed -= calendar::end_of_month_day(year,em++); + } + + dst_calc_rules_ = shared_ptr<dst_calc_rule>( + new partial_date_dst_rule( + partial_date_dst_rule::start_rule( + sd, static_cast<date_time::months_of_year>(sm)), + partial_date_dst_rule::end_rule( + ed, static_cast<date_time::months_of_year>(em)) + ) + ); + } + + //! Julian day. Feb29 is always counted, but exception thrown in non-leap years + // expects range of 0-365 + void julian_day(const string_type& s, const string_type& e){ + int sd=0, ed=0; + sd = lexical_cast<int>(s); + ed = lexical_cast<int>(e); + dst_calc_rules_ = shared_ptr<dst_calc_rule>( + new partial_date_dst_rule( + partial_date_dst_rule::start_rule(++sd),// args are 0-365 + partial_date_dst_rule::end_rule(++ed) // pd expects 1-366 + ) + ); + } + + //! helper function used when throwing exceptions + static std::string td_as_string(const time_duration_type& td) + { + std::string s; +#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO) + s = posix_time::to_simple_string(td); +#else + std::stringstream ss; + ss << td; + s = ss.str(); +#endif + return s; + } + }; + + typedef posix_time_zone_base<char> posix_time_zone; + +} } // namespace boost::local_time + + +#endif // _DATE_TIME_POSIX_TIME_ZONE__ diff --git a/3rdParty/Boost/src/boost/date_time/local_time/tz_database.hpp b/3rdParty/Boost/src/boost/date_time/local_time/tz_database.hpp new file mode 100644 index 0000000..4cfca45 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/local_time/tz_database.hpp @@ -0,0 +1,32 @@ +#ifndef BOOST_DATE_TIME_TZ_DATABASE_HPP__ +#define BOOST_DATE_TIME_TZ_DATABASE_HPP__ + +/* Copyright (c) 2003-2004 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + +#include <string> +#include "boost/date_time/local_time/custom_time_zone.hpp" +#include "boost/date_time/local_time/dst_transition_day_rules.hpp" +#include "boost/date_time/tz_db_base.hpp" + + +namespace boost { +namespace local_time { + + using date_time::data_not_accessible; + using date_time::bad_field_count; + + //! Object populated with boost::shared_ptr<time_zone_base> objects + /*! Object populated with boost::shared_ptr<time_zone_base> objects + * Database is populated from specs stored in external csv file. See + * date_time::tz_db_base for greater detail */ + typedef date_time::tz_db_base<custom_time_zone, nth_kday_dst_rule> tz_database; + +}} // namespace + +#endif // BOOST_DATE_TIME_TZ_DATABASE_HPP__ + diff --git a/3rdParty/Boost/src/boost/date_time/time_zone_base.hpp b/3rdParty/Boost/src/boost/date_time/time_zone_base.hpp new file mode 100644 index 0000000..0d3cb90 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/time_zone_base.hpp @@ -0,0 +1,99 @@ +#ifndef _DATE_TIME_TIME_ZONE_BASE__ +#define _DATE_TIME_TIME_ZONE_BASE__ + +/* Copyright (c) 2003-2005 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + + +#include <string> +#include <sstream> + +namespace boost { +namespace date_time { + + + + //! Interface class for dynamic time zones. + /*! This class represents the base interface for all timezone + * representations. Subclasses may provide different systems + * for identifying a particular zone. For example some may + * provide a geographical based zone construction while others + * may specify the offset from GMT. Another possible implementation + * would be to convert from POSIX timezone strings. Regardless of + * the construction technique, this is the interface that these + * time zone types must provide. + * + * Note that this class is intended to be used as a shared + * resource (hence the derivation from boost::counted_base. + */ + template<typename time_type, typename CharT> + class time_zone_base { + public: + typedef CharT char_type; + typedef std::basic_string<CharT> string_type; + typedef std::basic_ostringstream<CharT> stringstream_type; + typedef typename time_type::date_type::year_type year_type; + typedef typename time_type::time_duration_type time_duration_type; + + time_zone_base() {}; + virtual ~time_zone_base() {}; + //!String for the timezone when in daylight savings (eg: EDT) + virtual string_type dst_zone_abbrev() const=0; + //!String for the zone when not in daylight savings (eg: EST) + virtual string_type std_zone_abbrev() const=0; + //!String for the timezone when in daylight savings (eg: Eastern Daylight Time) + virtual string_type dst_zone_name() const=0; + //!String for the zone when not in daylight savings (eg: Eastern Standard Time) + virtual string_type std_zone_name() const=0; + //! True if zone uses daylight savings adjustments otherwise false + virtual bool has_dst() const=0; + //! Local time that DST starts -- undefined if has_dst is false + virtual time_type dst_local_start_time(year_type y) const=0; + //! Local time that DST ends -- undefined if has_dst is false + virtual time_type dst_local_end_time(year_type y) const=0; + //! Base offset from UTC for zone (eg: -07:30:00) + virtual time_duration_type base_utc_offset() const=0; + //! Adjustment forward or back made while DST is in effect + virtual time_duration_type dst_offset() const=0; + //! Returns a POSIX time_zone string for this object + virtual string_type to_posix_string() const =0; + + private: + + }; + + + //! Structure which holds the time offsets associated with daylight savings time + /*! + *@param time_duration_type A type used to represent the offset + */ + template<class time_duration_type> + class dst_adjustment_offsets + { + public: + dst_adjustment_offsets(const time_duration_type& dst_adjust, + const time_duration_type& dst_start_offset, + const time_duration_type& dst_end_offset) : + dst_adjust_(dst_adjust), + dst_start_offset_(dst_start_offset), + dst_end_offset_(dst_end_offset) + {} + + //! Amount DST adjusts the clock eg: plus one hour + time_duration_type dst_adjust_; + //! Time past midnight on start transition day that dst starts + time_duration_type dst_start_offset_; + //! Time past midnight on end transition day that dst ends + time_duration_type dst_end_offset_; + }; + + +} } //namespace date_time + + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/time_zone_names.hpp b/3rdParty/Boost/src/boost/date_time/time_zone_names.hpp new file mode 100644 index 0000000..05260c7 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/time_zone_names.hpp @@ -0,0 +1,98 @@ +#ifndef DATE_TIME_TIME_ZONE_NAMES_HPP__ +#define DATE_TIME_TIME_ZONE_NAMES_HPP__ + +/* Copyright (c) 2002-2003,2005 CrystalClear Software, Inc. + * Use, modification and distribution is subject to the + * Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland + * $Date: 2008-02-27 15:00:24 -0500 (Wed, 27 Feb 2008) $ + */ + +#include <string> + +namespace boost { +namespace date_time { + + template<class CharT> + struct default_zone_names { + public: + typedef CharT char_type; + static const char_type standard_name[9]; + static const char_type standard_abbrev[11]; + static const char_type non_dst_identifier[7]; + }; + template <class CharT> + const typename default_zone_names<CharT>::char_type + default_zone_names<CharT>::standard_name[9] = + {'s','t','d','_','n','a','m','e'}; + + template <class CharT> + const typename default_zone_names<CharT>::char_type + default_zone_names<CharT>::standard_abbrev[11] = + {'s','t','d','_','a','b','b','r','e','v'}; + + template <class CharT> + const typename default_zone_names<CharT>::char_type + default_zone_names<CharT>::non_dst_identifier[7] = + {'n','o','-','d','s','t'}; + + //! Base type that holds various string names for timezone output. + /*! Class that holds various types of strings used for timezones. + * For example, for the western United States there is the full + * name: Pacific Standard Time and the abbreviated name: PST. + * During daylight savings there are additional names: + * Pacific Daylight Time and PDT. + *@parm CharT Allows class to support different character types + */ + template<class CharT> + class time_zone_names_base + { + public: + typedef std::basic_string<CharT> string_type; + time_zone_names_base() : + std_zone_name_(default_zone_names<CharT>::standard_name), + std_zone_abbrev_(default_zone_names<CharT>::standard_abbrev), + dst_zone_name_(default_zone_names<CharT>::non_dst_identifier), + dst_zone_abbrev_(default_zone_names<CharT>::non_dst_identifier) + {} + time_zone_names_base(const string_type& std_zone_name_str, + const string_type& std_zone_abbrev_str, + const string_type& dst_zone_name_str, + const string_type& dst_zone_abbrev_str) : + std_zone_name_(std_zone_name_str), + std_zone_abbrev_(std_zone_abbrev_str), + dst_zone_name_(dst_zone_name_str), + dst_zone_abbrev_(dst_zone_abbrev_str) + {} + string_type dst_zone_abbrev() const + { + return dst_zone_abbrev_; + } + string_type std_zone_abbrev() const + { + return std_zone_abbrev_; + } + string_type dst_zone_name() const + { + return dst_zone_name_; + } + string_type std_zone_name() const + { + return std_zone_name_; + } + private: + string_type std_zone_name_; + string_type std_zone_abbrev_; + string_type dst_zone_name_; + string_type dst_zone_abbrev_; + + }; + + //! Specialization of timezone names for standard char. + //typedef time_zone_names_base<char> time_zone_names; + +} } //namespace + + +#endif diff --git a/3rdParty/Boost/src/boost/date_time/tz_db_base.hpp b/3rdParty/Boost/src/boost/date_time/tz_db_base.hpp new file mode 100644 index 0000000..2440115 --- /dev/null +++ b/3rdParty/Boost/src/boost/date_time/tz_db_base.hpp @@ -0,0 +1,378 @@ +#ifndef DATE_TIME_TZ_DB_BASE_HPP__ +#define DATE_TIME_TZ_DB_BASE_HPP__ + +/* Copyright (c) 2003-2005 CrystalClear Software, Inc. + * Subject to the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + * Author: Jeff Garland, Bart Garst + * $Date: 2008-11-12 14:37:53 -0500 (Wed, 12 Nov 2008) $ + */ + +#include <map> +#include <vector> +#include <string> +#include <sstream> +#include <fstream> +#include <stdexcept> +#include <boost/tokenizer.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/throw_exception.hpp> +#include <boost/date_time/compiler_config.hpp> +#include <boost/date_time/time_zone_names.hpp> +#include <boost/date_time/time_zone_base.hpp> +#include <boost/date_time/time_parsing.hpp> + +namespace boost { + namespace date_time { + + //! Exception thrown when tz database cannot locate requested data file + class data_not_accessible : public std::logic_error + { + public: + data_not_accessible() : + std::logic_error(std::string("Unable to locate or access the required datafile.")) + {} + data_not_accessible(const std::string& filespec) : + std::logic_error(std::string("Unable to locate or access the required datafile. Filespec: " + filespec)) + {} + }; + + //! Exception thrown when tz database locates incorrect field structure in data file + class bad_field_count : public std::out_of_range + { + public: + bad_field_count(const std::string& s) : + std::out_of_range(s) + {} + }; + + //! Creates a database of time_zones from csv datafile + /*! The csv file containing the zone_specs used by the + * tz_db_base is intended to be customized by the + * library user. When customizing this file (or creating your own) the + * file must follow a specific format. + * + * This first line is expected to contain column headings and is therefore + * not processed by the tz_db_base. + * + * Each record (line) must have eleven fields. Some of those fields can + * be empty. Every field (even empty ones) must be enclosed in + * double-quotes. + * Ex: + * @code + * "America/Phoenix" <- string enclosed in quotes + * "" <- empty field + * @endcode + * + * Some fields represent a length of time. The format of these fields + * must be: + * @code + * "{+|-}hh:mm[:ss]" <- length-of-time format + * @endcode + * Where the plus or minus is mandatory and the seconds are optional. + * + * Since some time zones do not use daylight savings it is not always + * necessary for every field in a zone_spec to contain a value. All + * zone_specs must have at least ID and GMT offset. Zones that use + * daylight savings must have all fields filled except: + * STD ABBR, STD NAME, DST NAME. You should take note + * that DST ABBR is mandatory for zones that use daylight savings + * (see field descriptions for further details). + * + * ******* Fields and their description/details ********* + * + * ID: + * Contains the identifying string for the zone_spec. Any string will + * do as long as it's unique. No two ID's can be the same. + * + * STD ABBR: + * STD NAME: + * DST ABBR: + * DST NAME: + * These four are all the names and abbreviations used by the time + * zone being described. While any string will do in these fields, + * care should be taken. These fields hold the strings that will be + * used in the output of many of the local_time classes. + * Ex: + * @code + * time_zone nyc = tz_db.time_zone_from_region("America/New_York"); + * local_time ny_time(date(2004, Aug, 30), IS_DST, nyc); + * cout << ny_time.to_long_string() << endl; + * // 2004-Aug-30 00:00:00 Eastern Daylight Time + * cout << ny_time.to_short_string() << endl; + * // 2004-Aug-30 00:00:00 EDT + * @endcode + * + * NOTE: The exact format/function names may vary - see local_time + * documentation for further details. + * + * GMT offset: + * This is the number of hours added to utc to get the local time + * before any daylight savings adjustments are made. Some examples + * are: America/New_York offset -5 hours, & Africa/Cairo offset +2 hours. + * The format must follow the length-of-time format described above. + * + * DST adjustment: + * The amount of time added to gmt_offset when daylight savings is in + * effect. The format must follow the length-of-time format described + * above. + * + * DST Start Date rule: + * This is a specially formatted string that describes the day of year + * in which the transition take place. It holds three fields of it's own, + * separated by semicolons. + * The first field indicates the "nth" weekday of the month. The possible + * values are: 1 (first), 2 (second), 3 (third), 4 (fourth), 5 (fifth), + * and -1 (last). + * The second field indicates the day-of-week from 0-6 (Sun=0). + * The third field indicates the month from 1-12 (Jan=1). + * + * Examples are: "-1;5;9"="Last Friday of September", + * "2;1;3"="Second Monday of March" + * + * Start time: + * Start time is the number of hours past midnight, on the day of the + * start transition, the transition takes place. More simply put, the + * time of day the transition is made (in 24 hours format). The format + * must follow the length-of-time format described above with the + * exception that it must always be positive. + * + * DST End date rule: + * See DST Start date rule. The difference here is this is the day + * daylight savings ends (transition to STD). + * + * End time: + * Same as Start time. + */ + template<class time_zone_type, class rule_type> + class tz_db_base { + public: + /* Having CharT as a template parameter created problems + * with posix_time::duration_from_string. Templatizing + * duration_from_string was not possible at this time, however, + * it should be possible in the future (when poor compilers get + * fixed or stop being used). + * Since this class was designed to use CharT as a parameter it + * is simply typedef'd here to ease converting in back to a + * parameter the future */ + typedef char char_type; + + typedef typename time_zone_type::base_type time_zone_base_type; + typedef typename time_zone_type::time_duration_type time_duration_type; + typedef time_zone_names_base<char_type> time_zone_names; + typedef boost::date_time::dst_adjustment_offsets<time_duration_type> dst_adjustment_offsets; + typedef std::basic_string<char_type> string_type; + + //! Constructs an empty database + tz_db_base() {} + + //! Process csv data file, may throw exceptions + /*! May throw data_not_accessible, or bad_field_count exceptions */ + void load_from_file(const std::string& pathspec) + { + string_type in_str; + std::string buff; + + std::ifstream ifs(pathspec.c_str()); + if(!ifs){ + boost::throw_exception(data_not_accessible(pathspec)); + } + std::getline(ifs, buff); // first line is column headings + + while( std::getline(ifs, buff)) { + parse_string(buff); + } + } + + //! returns true if record successfully added to map + /*! Takes a region name in the form of "America/Phoenix", and a + * time_zone object for that region. The id string must be a unique + * name that does not already exist in the database. */ + bool add_record(const string_type& region, + boost::shared_ptr<time_zone_base_type> tz) + { + typename map_type::value_type p(region, tz); + return (m_zone_map.insert(p)).second; + } + + //! Returns a time_zone object built from the specs for the given region + /*! Returns a time_zone object built from the specs for the given + * region. If region does not exist a local_time::record_not_found + * exception will be thrown */ + boost::shared_ptr<time_zone_base_type> + time_zone_from_region(const string_type& region) const + { + // get the record + typename map_type::const_iterator record = m_zone_map.find(region); + if(record == m_zone_map.end()){ + return boost::shared_ptr<time_zone_base_type>(); //null pointer + } + return record->second; + } + + //! Returns a vector of strings holding the time zone regions in the database + std::vector<std::string> region_list() const + { + typedef std::vector<std::string> vector_type; + vector_type regions; + typename map_type::const_iterator itr = m_zone_map.begin(); + while(itr != m_zone_map.end()) { + regions.push_back(itr->first); + ++itr; + } + return regions; + } + + private: + typedef std::map<string_type, boost::shared_ptr<time_zone_base_type> > map_type; + map_type m_zone_map; + + // start and end rule are of the same type + typedef typename rule_type::start_rule::week_num week_num; + + /* TODO: mechanisms need to be put in place to handle different + * types of rule specs. parse_rules() only handles nth_kday + * rule types. */ + + //! parses rule specs for transition day rules + rule_type* parse_rules(const string_type& sr, const string_type& er) const + { + using namespace gregorian; + // start and end rule are of the same type, + // both are included here for readability + typedef typename rule_type::start_rule start_rule; + typedef typename rule_type::end_rule end_rule; + + // these are: [start|end] nth, day, month + int s_nth = 0, s_d = 0, s_m = 0; + int e_nth = 0, e_d = 0, e_m = 0; + split_rule_spec(s_nth, s_d, s_m, sr); + split_rule_spec(e_nth, e_d, e_m, er); + + typename start_rule::week_num s_wn, e_wn; + s_wn = get_week_num(s_nth); + e_wn = get_week_num(e_nth); + + + return new rule_type(start_rule(s_wn, s_d, s_m), + end_rule(e_wn, e_d, e_m)); + } + //! helper function for parse_rules() + week_num get_week_num(int nth) const + { + typedef typename rule_type::start_rule start_rule; + switch(nth){ + case 1: + return start_rule::first; + case 2: + return start_rule::second; + case 3: + return start_rule::third; + case 4: + return start_rule::fourth; + case 5: + case -1: + return start_rule::fifth; + default: + // shouldn't get here - add error handling later + break; + } + return start_rule::fifth; // silence warnings + } + + //! splits the [start|end]_date_rule string into 3 ints + void split_rule_spec(int& nth, int& d, int& m, string_type rule) const + { + typedef boost::char_separator<char_type, std::char_traits<char_type> > char_separator_type; + typedef boost::tokenizer<char_separator_type, + std::basic_string<char_type>::const_iterator, + std::basic_string<char_type> > tokenizer; + typedef boost::tokenizer<char_separator_type, + std::basic_string<char_type>::const_iterator, + std::basic_string<char_type> >::iterator tokenizer_iterator; + + const char_type sep_char[] = { ';', '\0'}; + char_separator_type sep(sep_char); + tokenizer tokens(rule, sep); // 3 fields + + tokenizer_iterator tok_iter = tokens.begin(); + nth = std::atoi(tok_iter->c_str()); ++tok_iter; + d = std::atoi(tok_iter->c_str()); ++tok_iter; + m = std::atoi(tok_iter->c_str()); + } + + + //! Take a line from the csv, turn it into a time_zone_type. + /*! Take a line from the csv, turn it into a time_zone_type, + * and add it to the map. Zone_specs in csv file are expected to + * have eleven fields that describe the time zone. Returns true if + * zone_spec successfully added to database */ + bool parse_string(string_type& s) + { + std::vector<string_type> result; + typedef boost::token_iterator_generator<boost::escaped_list_separator<char_type>, string_type::const_iterator, string_type >::type token_iter_type; + + token_iter_type i = boost::make_token_iterator<string_type>(s.begin(), s.end(),boost::escaped_list_separator<char_type>()); + + token_iter_type end; + while (i != end) { + result.push_back(*i); + i++; + } + + enum db_fields { ID, STDABBR, STDNAME, DSTABBR, DSTNAME, GMTOFFSET, + DSTADJUST, START_DATE_RULE, START_TIME, END_DATE_RULE, + END_TIME, FIELD_COUNT }; + + //take a shot at fixing gcc 4.x error + const unsigned int expected_fields = static_cast<unsigned int>(FIELD_COUNT); + if (result.size() != expected_fields) { + std::ostringstream msg; + msg << "Expecting " << FIELD_COUNT << " fields, got " + << result.size() << " fields in line: " << s; + boost::throw_exception(bad_field_count(msg.str())); + BOOST_DATE_TIME_UNREACHABLE_EXPRESSION(return false); // should never reach + } + + // initializations + bool has_dst = true; + if(result[DSTABBR] == std::string()){ + has_dst = false; + } + + + // start building components of a time_zone + time_zone_names names(result[STDNAME], result[STDABBR], + result[DSTNAME], result[DSTABBR]); + + time_duration_type utc_offset = + str_from_delimited_time_duration<time_duration_type,char_type>(result[GMTOFFSET]); + + dst_adjustment_offsets adjust(time_duration_type(0,0,0), + time_duration_type(0,0,0), + time_duration_type(0,0,0)); + + boost::shared_ptr<rule_type> rules; + + if(has_dst){ + adjust = dst_adjustment_offsets( + str_from_delimited_time_duration<time_duration_type,char_type>(result[DSTADJUST]), + str_from_delimited_time_duration<time_duration_type,char_type>(result[START_TIME]), + str_from_delimited_time_duration<time_duration_type,char_type>(result[END_TIME]) + ); + + rules = + boost::shared_ptr<rule_type>(parse_rules(result[START_DATE_RULE], + result[END_DATE_RULE])); + } + string_type id(result[ID]); + boost::shared_ptr<time_zone_base_type> zone(new time_zone_type(names, utc_offset, adjust, rules)); + return (add_record(id, zone)); + + } + + }; + +} } // namespace + +#endif // DATE_TIME_TZ_DB_BASE_HPP__ diff --git a/3rdParty/Boost/src/boost/logic/tribool.hpp b/3rdParty/Boost/src/boost/logic/tribool.hpp new file mode 100644 index 0000000..229feb4 --- /dev/null +++ b/3rdParty/Boost/src/boost/logic/tribool.hpp @@ -0,0 +1,460 @@ +// Three-state boolean logic library + +// Copyright Douglas Gregor 2002-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +// For more information, see http://www.boost.org +#ifndef BOOST_LOGIC_TRIBOOL_HPP +#define BOOST_LOGIC_TRIBOOL_HPP + +#include <boost/logic/tribool_fwd.hpp> +#include <boost/config.hpp> +#include <boost/detail/workaround.hpp> + +#if BOOST_WORKAROUND(_MSC_VER, >= 1200) +# pragma once +#endif + +namespace boost { namespace logic { + +/// INTERNAL ONLY +namespace detail { +/** + * INTERNAL ONLY + * + * \brief A type used only to uniquely identify the 'indeterminate' + * function/keyword. + */ +struct indeterminate_t +{ +#if BOOST_WORKAROUND(__BORLANDC__, < 0x0600) + char dummy_; // BCB would use 8 bytes by default +#endif +}; + +} // end namespace detail + +/** + * INTERNAL ONLY + * The type of the 'indeterminate' keyword. This has the same type as the + * function 'indeterminate' so that we can recognize when the keyword is + * used. + */ +typedef bool (*indeterminate_keyword_t)(tribool, detail::indeterminate_t); + +/** + * \brief Keyword and test function for the indeterminate tribool value + * + * The \c indeterminate function has a dual role. It's first role is + * as a unary function that tells whether the tribool value is in the + * "indeterminate" state. It's second role is as a keyword + * representing the indeterminate (just like "true" and "false" + * represent the true and false states). If you do not like the name + * "indeterminate", and would prefer to use a different name, see the + * macro \c BOOST_TRIBOOL_THIRD_STATE. + * + * \returns <tt>x.value == tribool::indeterminate_value</tt> + * \throws nothrow + */ +inline bool +indeterminate(tribool x, + detail::indeterminate_t dummy = detail::indeterminate_t()); + +/** + * \brief A 3-state boolean type. + * + * 3-state boolean values are either true, false, or + * indeterminate. + */ +class tribool +{ +private: + /// INTERNAL ONLY + struct dummy { + void nonnull() {}; + }; + + typedef void (dummy::*safe_bool)(); + +public: + /** + * Construct a new 3-state boolean value with the value 'false'. + * + * \throws nothrow + */ + tribool() : value(false_value) {} + + /** + * Construct a new 3-state boolean value with the given boolean + * value, which may be \c true or \c false. + * + * \throws nothrow + */ + tribool(bool value) : value(value? true_value : false_value) {} + + /** + * Construct a new 3-state boolean value with an indeterminate value. + * + * \throws nothrow + */ + tribool(indeterminate_keyword_t) : value(indeterminate_value) {} + + /** + * Use a 3-state boolean in a boolean context. Will evaluate true in a + * boolean context only when the 3-state boolean is definitely true. + * + * \returns true if the 3-state boolean is true, false otherwise + * \throws nothrow + */ + operator safe_bool() const + { + return value == true_value? &dummy::nonnull : 0; + } + + /** + * The actual stored value in this 3-state boolean, which may be false, true, + * or indeterminate. + */ + enum value_t { false_value, true_value, indeterminate_value } value; +}; + +// Check if the given tribool has an indeterminate value. Also doubles as a +// keyword for the 'indeterminate' value +inline bool indeterminate(tribool x, detail::indeterminate_t) +{ + return x.value == tribool::indeterminate_value; +} + +/** @defgroup logical Logical operations + */ +//@{ +/** + * \brief Computes the logical negation of a tribool + * + * \returns the logical negation of the tribool, according to the + * table: + * <table border=1> + * <tr> + * <th><center><code>!</code></center></th> + * <th/> + * </tr> + * <tr> + * <th><center>false</center></th> + * <td><center>true</center></td> + * </tr> + * <tr> + * <th><center>true</center></th> + * <td><center>false</center></td> + * </tr> + * <tr> + * <th><center>indeterminate</center></th> + * <td><center>indeterminate</center></td> + * </tr> + * </table> + * \throws nothrow + */ +inline tribool operator!(tribool x) +{ + return x.value == tribool::false_value? tribool(true) + :x.value == tribool::true_value? tribool(false) + :tribool(indeterminate); +} + +/** + * \brief Computes the logical conjuction of two tribools + * + * \returns the result of logically ANDing the two tribool values, + * according to the following table: + * <table border=1> + * <tr> + * <th><center><code>&&</code></center></th> + * <th><center>false</center></th> + * <th><center>true</center></th> + * <th><center>indeterminate</center></th> + * </tr> + * <tr> + * <th><center>false</center></th> + * <td><center>false</center></td> + * <td><center>false</center></td> + * <td><center>false</center></td> + * </tr> + * <tr> + * <th><center>true</center></th> + * <td><center>false</center></td> + * <td><center>true</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * <tr> + * <th><center>indeterminate</center></th> + * <td><center>false</center></td> + * <td><center>indeterminate</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * </table> + * \throws nothrow + */ +inline tribool operator&&(tribool x, tribool y) +{ + if (static_cast<bool>(!x) || static_cast<bool>(!y)) + return false; + else if (static_cast<bool>(x) && static_cast<bool>(y)) + return true; + else + return indeterminate; +} + +/** + * \overload + */ +inline tribool operator&&(tribool x, bool y) +{ return y? x : tribool(false); } + +/** + * \overload + */ +inline tribool operator&&(bool x, tribool y) +{ return x? y : tribool(false); } + +/** + * \overload + */ +inline tribool operator&&(indeterminate_keyword_t, tribool x) +{ return !x? tribool(false) : tribool(indeterminate); } + +/** + * \overload + */ +inline tribool operator&&(tribool x, indeterminate_keyword_t) +{ return !x? tribool(false) : tribool(indeterminate); } + +/** + * \brief Computes the logical disjunction of two tribools + * + * \returns the result of logically ORing the two tribool values, + * according to the following table: + * <table border=1> + * <tr> + * <th><center><code>||</code></center></th> + * <th><center>false</center></th> + * <th><center>true</center></th> + * <th><center>indeterminate</center></th> + * </tr> + * <tr> + * <th><center>false</center></th> + * <td><center>false</center></td> + * <td><center>true</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * <tr> + * <th><center>true</center></th> + * <td><center>true</center></td> + * <td><center>true</center></td> + * <td><center>true</center></td> + * </tr> + * <tr> + * <th><center>indeterminate</center></th> + * <td><center>indeterminate</center></td> + * <td><center>true</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * </table> + * \throws nothrow + */ +inline tribool operator||(tribool x, tribool y) +{ + if (static_cast<bool>(!x) && static_cast<bool>(!y)) + return false; + else if (static_cast<bool>(x) || static_cast<bool>(y)) + return true; + else + return indeterminate; +} + +/** + * \overload + */ +inline tribool operator||(tribool x, bool y) +{ return y? tribool(true) : x; } + +/** + * \overload + */ +inline tribool operator||(bool x, tribool y) +{ return x? tribool(true) : y; } + +/** + * \overload + */ +inline tribool operator||(indeterminate_keyword_t, tribool x) +{ return x? tribool(true) : tribool(indeterminate); } + +/** + * \overload + */ +inline tribool operator||(tribool x, indeterminate_keyword_t) +{ return x? tribool(true) : tribool(indeterminate); } +//@} + +/** + * \brief Compare tribools for equality + * + * \returns the result of comparing two tribool values, according to + * the following table: + * <table border=1> + * <tr> + * <th><center><code>==</code></center></th> + * <th><center>false</center></th> + * <th><center>true</center></th> + * <th><center>indeterminate</center></th> + * </tr> + * <tr> + * <th><center>false</center></th> + * <td><center>true</center></td> + * <td><center>false</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * <tr> + * <th><center>true</center></th> + * <td><center>false</center></td> + * <td><center>true</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * <tr> + * <th><center>indeterminate</center></th> + * <td><center>indeterminate</center></td> + * <td><center>indeterminate</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * </table> + * \throws nothrow + */ +inline tribool operator==(tribool x, tribool y) +{ + if (indeterminate(x) || indeterminate(y)) + return indeterminate; + else + return (x && y) || (!x && !y); +} + +/** + * \overload + */ +inline tribool operator==(tribool x, bool y) { return x == tribool(y); } + +/** + * \overload + */ +inline tribool operator==(bool x, tribool y) { return tribool(x) == y; } + +/** + * \overload + */ +inline tribool operator==(indeterminate_keyword_t, tribool x) +{ return tribool(indeterminate) == x; } + +/** + * \overload + */ +inline tribool operator==(tribool x, indeterminate_keyword_t) +{ return tribool(indeterminate) == x; } + +/** + * \brief Compare tribools for inequality + * + * \returns the result of comparing two tribool values for inequality, + * according to the following table: + * <table border=1> + * <tr> + * <th><center><code>!=</code></center></th> + * <th><center>false</center></th> + * <th><center>true</center></th> + * <th><center>indeterminate</center></th> + * </tr> + * <tr> + * <th><center>false</center></th> + * <td><center>false</center></td> + * <td><center>true</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * <tr> + * <th><center>true</center></th> + * <td><center>true</center></td> + * <td><center>false</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * <tr> + * <th><center>indeterminate</center></th> + * <td><center>indeterminate</center></td> + * <td><center>indeterminate</center></td> + * <td><center>indeterminate</center></td> + * </tr> + * </table> + * \throws nothrow + */ +inline tribool operator!=(tribool x, tribool y) +{ + if (indeterminate(x) || indeterminate(y)) + return indeterminate; + else + return !((x && y) || (!x && !y)); +} + +/** + * \overload + */ +inline tribool operator!=(tribool x, bool y) { return x != tribool(y); } + +/** + * \overload + */ +inline tribool operator!=(bool x, tribool y) { return tribool(x) != y; } + +/** + * \overload + */ +inline tribool operator!=(indeterminate_keyword_t, tribool x) +{ return tribool(indeterminate) != x; } + +/** + * \overload + */ +inline tribool operator!=(tribool x, indeterminate_keyword_t) +{ return x != tribool(indeterminate); } + +} } // end namespace boost::logic + +// Pull tribool and indeterminate into namespace "boost" +namespace boost { + using logic::tribool; + using logic::indeterminate; +} + +/** + * \brief Declare a new name for the third state of a tribool + * + * Use this macro to declare a new name for the third state of a + * tribool. This state can have any number of new names (in addition + * to \c indeterminate), all of which will be equivalent. The new name will be + * placed in the namespace in which the macro is expanded. + * + * Example: + * BOOST_TRIBOOL_THIRD_STATE(true_or_false) + * + * tribool x(true_or_false); + * // potentially set x + * if (true_or_false(x)) { + * // don't know what x is + * } + */ +#define BOOST_TRIBOOL_THIRD_STATE(Name) \ +inline bool \ +Name(boost::logic::tribool x, \ + boost::logic::detail::indeterminate_t dummy = \ + boost::logic::detail::indeterminate_t()) \ +{ return x.value == boost::logic::tribool::indeterminate_value; } + +#endif // BOOST_LOGIC_TRIBOOL_HPP + diff --git a/3rdParty/Boost/src/boost/logic/tribool_fwd.hpp b/3rdParty/Boost/src/boost/logic/tribool_fwd.hpp new file mode 100644 index 0000000..2cdd91b --- /dev/null +++ b/3rdParty/Boost/src/boost/logic/tribool_fwd.hpp @@ -0,0 +1,15 @@ +// Three-state boolean logic library + +// Copyright Douglas Gregor 2002-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +// For more information, see http://www.boost.org +#ifndef BOOST_LOGIC_TRIBOOL_FWD_HPP +#define BOOST_LOGIC_TRIBOOL_FWD_HPP + +namespace boost { namespace logic { class tribool; } } + +#endif // BOOST_LOGIC_TRIBOOL_FWD_HPP diff --git a/3rdParty/Boost/update.sh b/3rdParty/Boost/update.sh index 6344d72..a7c0638 100755 --- a/3rdParty/Boost/update.sh +++ b/3rdParty/Boost/update.sh @@ -14,6 +14,7 @@ fi bind.hpp \ cast.hpp \ date_time/posix_time/posix_time.hpp \ + date_time/local_time/local_time.hpp \ foreach.hpp \ filesystem.hpp \ filesystem/fstream.hpp \ @@ -31,9 +32,10 @@ fi uuid/uuid_generators.hpp \ variant.hpp \ regex.hpp \ - boost/unordered_map.hpp \ - boost/algorithm/string.hpp \ - boost/format.hpp \ + unordered_map.hpp \ + algorithm/string.hpp \ + format.hpp \ + logic/tribool.hpp \ assign/list_of.hpp \ $TARGET_DIR diff --git a/3rdParty/LibMiniUPnPc/SConscript b/3rdParty/LibMiniUPnPc/SConscript new file mode 100644 index 0000000..c482109 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/SConscript @@ -0,0 +1,67 @@ +Import(["env", "conf_env"]) + +if env.get("LIBMINIUPNPC_BUNDLED", False) : + +################################################################################ +# Module flags +################################################################################ + + if env["SCONS_STAGE"] == "flags" : + env["LIBMINIUPNPC_FLAGS"] = { + "CPPPATH": [Dir("src/miniupnpc")], + "LIBPATH": [Dir(".")], + "LIBS": ["Swiften_MiniUPnPc"], + "INTERNAL_CPPDEFINES": ["STATICLIB"], + } + #if env["PLATFORM"] == "win32" : + # env["LIBIDN_FLAGS"]["CPPPATH"] += [Dir("stubs/win32")] + # if env["MSVC_VERSION"][:3] == "9.0" : + # env["LIBIDN_FLAGS"]["CPPPATH"] += [Dir("stubs/win32/VC2008")] + +################################################################################ +# Build +################################################################################ + + if env["SCONS_STAGE"] == "build" : + myenv = env.Clone() + myenv.Append(CPPPATH = ["src"]) + # Remove warn flags + myenv.Replace(CCFLAGS = [flag for flag in env["CCFLAGS"] if flag not in ["-W", "-Wall"]]) + + myenv.Append(CCFLAGS = ["-DNDEBUG", "-DSTATICLIB"]) + + if myenv["PLATFORM"] != "win32": + myenv.Append(CCFLAGS = ["-DMINIUPNPC_SET_SOCKET_TIMEOUT"]) + + if myenv["PLATFORM"] == "darwin": + myenv.Append(CCFLAGS = ["-DMACOSX", "-D_DARWIN_C_SOURCE"]) + + if myenv["PLATFORM"] == "win32": + myenv.Append(CCFLAGS = ["-DWIN32", "-D_WIN32_WINNT=0x0501"]) + + myenv.WriteVal("src/miniupnpc/miniupnpcstrings.h", myenv.Value( +""" +#ifndef __MINIUPNPCSTRINGS_H__ +#define __MINIUPNPCSTRINGS_H__ + +#define OS_STRING "$OS_STRING" +#define MINIUPNPC_VERSION_STRING "1.5" + +#endif +""".replace("$OS_STRING", myenv["PLATFORM"]))) + + myenv.StaticLibrary("Swiften_MiniUPnPc", [ + "src/miniupnpc/igd_desc_parse.c", + "src/miniupnpc/miniupnpc.c", + "src/miniupnpc/minixml.c", + "src/miniupnpc/minisoap.c", + "src/miniupnpc/minissdpc.c", + "src/miniupnpc/miniwget.c", + #"src/miniupnpc/upnpc.c", + "src/miniupnpc/upnpcommands.c", + "src/miniupnpc/upnpreplyparse.c", + "src/miniupnpc/upnperrors.c", + "src/miniupnpc/connecthostport.c", + "src/miniupnpc/portlistingparse.c", + "src/miniupnpc/receivedata.c" + ]) diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE new file mode 100644 index 0000000..2434c86 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/LICENSE @@ -0,0 +1,27 @@ +MiniUPnPc +Copyright (c) 2005-2011, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h new file mode 100644 index 0000000..1fe0599 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/bsdqueue.h @@ -0,0 +1,531 @@ +/* $OpenBSD: queue.h,v 1.31 2005/11/25 08:06:25 otto Exp $ */ +/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +#ifdef QUEUE_MACRO_DEBUG +#define _Q_INVALIDATE(a) (a) = ((void *)-1) +#else +#define _Q_INVALIDATE(a) +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#ifdef SLIST_ENTRY +#undef SLIST_ENTRY +#endif + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head)) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = SLIST_FIRST(head); \ + (var) != SLIST_END(head); \ + (var) = SLIST_NEXT(var, field)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != SLIST_END(head); \ + (varp) = &SLIST_NEXT((var), field)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) { \ + SLIST_FIRST(head) = SLIST_END(head); \ +} + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (0) + +#define SLIST_REMOVE_NEXT(head, elm, field) do { \ + (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->slh_first; \ + \ + while (curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + _Q_INVALIDATE((elm)->field.sle_next); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for((var) = LIST_FIRST(head); \ + (var)!= LIST_END(head); \ + (var) = LIST_NEXT(var, field)) + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + LIST_FIRST(head) = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.le_prev); \ + _Q_INVALIDATE((elm)->field.le_next); \ +} while (0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (0) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * tail queue access methods + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue access methods + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head)) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for((var) = CIRCLEQ_FIRST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_NEXT(var, field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for((var) = CIRCLEQ_LAST(head); \ + (var) != CIRCLEQ_END(head); \ + (var) = CIRCLEQ_PREV(var, field)) + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \ + CIRCLEQ_END(head)) \ + (head).cqh_last = (elm2); \ + else \ + (elm2)->field.cqe_next->field.cqe_prev = (elm2); \ + if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \ + CIRCLEQ_END(head)) \ + (head).cqh_first = (elm2); \ + else \ + (elm2)->field.cqe_prev->field.cqe_next = (elm2); \ + _Q_INVALIDATE((elm)->field.cqe_prev); \ + _Q_INVALIDATE((elm)->field.cqe_next); \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h new file mode 100644 index 0000000..f11e5e9 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/codelength.h @@ -0,0 +1,24 @@ +/* $Id: codelength.h,v 1.1 2008/10/06 22:04:06 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2008 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef __CODELENGTH_H__ +#define __CODELENGTH_H__ + +/* Encode length by using 7bit per Byte : + * Most significant bit of each byte specifies that the + * following byte is part of the code */ +#define DECODELENGTH(n, p) n = 0; \ + do { n = (n << 7) | (*p & 0x7f); } \ + while(*(p++)&0x80); + +#define CODELENGTH(n, p) if(n>=268435456) *(p++) = (n >> 28) | 0x80; \ + if(n>=2097152) *(p++) = (n >> 21) | 0x80; \ + if(n>=16384) *(p++) = (n >> 14) | 0x80; \ + if(n>=128) *(p++) = (n >> 7) | 0x80; \ + *(p++) = n & 0x7f; + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c new file mode 100644 index 0000000..7afd2b1 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.c @@ -0,0 +1,241 @@ +/* $Id: connecthostport.c,v 1.5 2011/04/09 08:49:50 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2010-2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +/* use getaddrinfo() or gethostbyname() + * uncomment the following line in order to use gethostbyname() */ +#ifdef NO_GETADDRINFO +#define USE_GETHOSTBYNAME +#endif + +#include <string.h> +#include <stdio.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#define MAXHOSTNAMELEN 64 +#define snprintf _snprintf +#define herror +#define socklen_t int +#else /* #ifdef WIN32 */ +#include <unistd.h> +#include <sys/param.h> +#include <errno.h> +#define closesocket close +#include <netdb.h> +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#ifndef USE_GETHOSTBYNAME +#include <sys/types.h> +#include <sys/socket.h> +#endif /* #ifndef USE_GETHOSTBYNAME */ +#endif /* #else WIN32 */ + +/* definition of PRINT_SOCKET_ERROR */ +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#if defined(__amigaos__) || defined(__amigaos4__) +#define herror(A) printf("%s\n", A) +#endif + +#include "connecthostport.h" + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port) +{ + int s, n; +#ifdef USE_GETHOSTBYNAME + struct sockaddr_in dest; + struct hostent *hp; +#else /* #ifdef USE_GETHOSTBYNAME */ + char tmp_host[MAXHOSTNAMELEN+1]; + char port_str[8]; + struct addrinfo *ai, *p; + struct addrinfo hints; +#endif /* #ifdef USE_GETHOSTBYNAME */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + struct timeval timeout; +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + +#ifdef USE_GETHOSTBYNAME + hp = gethostbyname(host); + if(hp == NULL) + { + herror(host); + return -1; + } + memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); + memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); + s = socket(PF_INET, SOCK_STREAM, 0); + if(s < 0) + { + PRINT_SOCKET_ERROR("socket"); + return -1; + } +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout for the connect() call */ + timeout.tv_sec = 5; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + timeout.tv_sec = 5; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + dest.sin_family = AF_INET; + dest.sin_port = htons(port); + n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); +#ifdef MINIUPNPC_IGNORE_EINTR + while(n < 0 && errno == EINTR) + { + socklen_t len; + fd_set wset; + int err; + FD_ZERO(&wset); + FD_SET(s, &wset); + if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) + continue; + /*len = 0;*/ + /*n = getpeername(s, NULL, &len);*/ + len = sizeof(err); + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + PRINT_SOCKET_ERROR("getsockopt"); + closesocket(s); + return -1; + } + if(err != 0) { + errno = err; + n = -1; + } + } +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ + if(n<0) + { + PRINT_SOCKET_ERROR("connect"); + closesocket(s); + return -1; + } +#else /* #ifdef USE_GETHOSTBYNAME */ + /* use getaddrinfo() instead of gethostbyname() */ + memset(&hints, 0, sizeof(hints)); + /* hints.ai_flags = AI_ADDRCONFIG; */ +#ifdef AI_NUMERICSERV + hints.ai_flags = AI_NUMERICSERV; +#endif + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; /* AF_INET, AF_INET6 or AF_UNSPEC */ + /* hints.ai_protocol = IPPROTO_TCP; */ + snprintf(port_str, sizeof(port_str), "%hu", port); + if(host[0] == '[') + { + /* literal ip v6 address */ + int i; + for(i = 0; host[i+1] && (host[i+1] != ']') && i < MAXHOSTNAMELEN; i++) + { + tmp_host[i] = host[i+1]; + } + tmp_host[i] = '\0'; + } + else + { + strncpy(tmp_host, host, MAXHOSTNAMELEN); + } + tmp_host[MAXHOSTNAMELEN] = '\0'; + n = getaddrinfo(tmp_host, port_str, &hints, &ai); + if(n != 0) + { +#ifdef WIN32 + fprintf(stderr, "getaddrinfo() error : %d\n", n); +#else + fprintf(stderr, "getaddrinfo() error : %s\n", gai_strerror(n)); +#endif + return -1; + } + s = -1; + for(p = ai; p; p = p->ai_next) + { + s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if(s < 0) + continue; +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT + /* setting a 3 seconds timeout for the connect() call */ + timeout.tv_sec = 5; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + timeout.tv_sec = 5; + timeout.tv_usec = 0; + if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#endif /* #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT */ + n = connect(s, p->ai_addr, p->ai_addrlen); +#ifdef MINIUPNPC_IGNORE_EINTR + while(n < 0 && errno == EINTR) + { + socklen_t len; + fd_set wset; + int err; + FD_ZERO(&wset); + FD_SET(s, &wset); + if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) + continue; + /*len = 0;*/ + /*n = getpeername(s, NULL, &len);*/ + len = sizeof(err); + if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + PRINT_SOCKET_ERROR("getsockopt"); + closesocket(s); + freeaddrinfo(ai); + return -1; + } + if(err != 0) { + errno = err; + n = -1; + } + } +#endif /* #ifdef MINIUPNPC_IGNORE_EINTR */ + if(n < 0) + { + closesocket(s); + continue; + } + else + { + break; + } + } + freeaddrinfo(ai); + if(s < 0) + { + PRINT_SOCKET_ERROR("socket"); + return -1; + } + if(n < 0) + { + PRINT_SOCKET_ERROR("connect"); + return -1; + } +#endif /* #ifdef USE_GETHOSTBYNAME */ + return s; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h new file mode 100644 index 0000000..57e24eb --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/connecthostport.h @@ -0,0 +1,17 @@ +/* $Id: connecthostport.h,v 1.1 2010/04/04 23:21:03 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2010 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __CONNECTHOSTPORT_H__ +#define __CONNECTHOSTPORT_H__ + +/* connecthostport() + * return a socket connected (TCP) to the host and port + * or -1 in case of error */ +int connecthostport(const char * host, unsigned short port); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h new file mode 100644 index 0000000..b804247 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/declspec.h @@ -0,0 +1,15 @@ +#ifndef __DECLSPEC_H__ +#define __DECLSPEC_H__ + +#if defined(WIN32) && !defined(STATICLIB) + #ifdef MINIUPNP_EXPORTS + #define LIBSPEC __declspec(dllexport) + #else + #define LIBSPEC __declspec(dllimport) + #endif +#else + #define LIBSPEC +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c new file mode 100644 index 0000000..6c3e656 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.c @@ -0,0 +1,125 @@ +/* $Id: igd_desc_parse.c,v 1.14 2011/04/11 09:19:24 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2010 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include "igd_desc_parse.h" +#include <stdio.h> +#include <string.h> + +/* Start element handler : + * update nesting level counter and copy element name */ +void IGDstartelt(void * d, const char * name, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + memcpy( datas->cureltname, name, l); + datas->cureltname[l] = '\0'; + datas->level++; + if( (l==7) && !memcmp(name, "service", l) ) { + datas->tmp.controlurl[0] = '\0'; + datas->tmp.eventsuburl[0] = '\0'; + datas->tmp.scpdurl[0] = '\0'; + datas->tmp.servicetype[0] = '\0'; + } +} + +/* End element handler : + * update nesting level counter and update parser state if + * service element is parsed */ +void IGDendelt(void * d, const char * name, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + datas->level--; + /*printf("endelt %2d %.*s\n", datas->level, l, name);*/ + if( (l==7) && !memcmp(name, "service", l) ) + { + /* + if( datas->state < 1 + && !strcmp(datas->servicetype, + // "urn:schemas-upnp-org:service:WANIPConnection:1") ) + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) + datas->state ++; + */ + if(0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1")) { + memcpy(&datas->CIF, &datas->tmp, sizeof(struct IGDdatas_service)); + } else if(0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1")) { + memcpy(&datas->IPv6FC, &datas->tmp, sizeof(struct IGDdatas_service)); + } else if(0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANIPConnection:1") + || 0==strcmp(datas->tmp.servicetype, + "urn:schemas-upnp-org:service:WANPPPConnection:1") ) { + if(datas->first.servicetype[0] == '\0') { + memcpy(&datas->first, &datas->tmp, sizeof(struct IGDdatas_service)); + } else { + memcpy(&datas->second, &datas->tmp, sizeof(struct IGDdatas_service)); + } + } + } +} + +/* Data handler : + * copy data depending on the current element name and state */ +void IGDdata(void * d, const char * data, int l) +{ + struct IGDdatas * datas = (struct IGDdatas *)d; + char * dstmember = 0; + /*printf("%2d %s : %.*s\n", + datas->level, datas->cureltname, l, data); */ + if( !strcmp(datas->cureltname, "URLBase") ) + dstmember = datas->urlbase; + else if( !strcmp(datas->cureltname, "presentationURL") ) + dstmember = datas->presentationurl; + else if( !strcmp(datas->cureltname, "serviceType") ) + dstmember = datas->tmp.servicetype; + else if( !strcmp(datas->cureltname, "controlURL") ) + dstmember = datas->tmp.controlurl; + else if( !strcmp(datas->cureltname, "eventSubURL") ) + dstmember = datas->tmp.eventsuburl; + else if( !strcmp(datas->cureltname, "SCPDURL") ) + dstmember = datas->tmp.scpdurl; +/* else if( !strcmp(datas->cureltname, "deviceType") ) + dstmember = datas->devicetype_tmp;*/ + if(dstmember) + { + if(l>=MINIUPNPC_URL_MAXSIZE) + l = MINIUPNPC_URL_MAXSIZE-1; + memcpy(dstmember, data, l); + dstmember[l] = '\0'; + } +} + +void printIGD(struct IGDdatas * d) +{ + printf("urlbase = '%s'\n", d->urlbase); + printf("WAN Device (Common interface config) :\n"); + /*printf(" deviceType = '%s'\n", d->CIF.devicetype);*/ + printf(" serviceType = '%s'\n", d->CIF.servicetype); + printf(" controlURL = '%s'\n", d->CIF.controlurl); + printf(" eventSubURL = '%s'\n", d->CIF.eventsuburl); + printf(" SCPDURL = '%s'\n", d->CIF.scpdurl); + printf("primary WAN Connection Device (IP or PPP Connection):\n"); + /*printf(" deviceType = '%s'\n", d->first.devicetype);*/ + printf(" servicetype = '%s'\n", d->first.servicetype); + printf(" controlURL = '%s'\n", d->first.controlurl); + printf(" eventSubURL = '%s'\n", d->first.eventsuburl); + printf(" SCPDURL = '%s'\n", d->first.scpdurl); + printf("secondary WAN Connection Device (IP or PPP Connection):\n"); + /*printf(" deviceType = '%s'\n", d->second.devicetype);*/ + printf(" servicetype = '%s'\n", d->second.servicetype); + printf(" controlURL = '%s'\n", d->second.controlurl); + printf(" eventSubURL = '%s'\n", d->second.eventsuburl); + printf(" SCPDURL = '%s'\n", d->second.scpdurl); + printf("WAN IPv6 Firewall Control :\n"); + /*printf(" deviceType = '%s'\n", d->IPv6FC.devicetype);*/ + printf(" servicetype = '%s'\n", d->IPv6FC.servicetype); + printf(" controlURL = '%s'\n", d->IPv6FC.controlurl); + printf(" eventSubURL = '%s'\n", d->IPv6FC.eventsuburl); + printf(" SCPDURL = '%s'\n", d->IPv6FC.scpdurl); +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h new file mode 100644 index 0000000..bab1fd5 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/igd_desc_parse.h @@ -0,0 +1,48 @@ +/* $Id: igd_desc_parse.h,v 1.10 2011/04/11 09:19:24 nanard Exp $ */ +/* Project : miniupnp + * http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2010 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef __IGD_DESC_PARSE_H__ +#define __IGD_DESC_PARSE_H__ + +/* Structure to store the result of the parsing of UPnP + * descriptions of Internet Gateway Devices */ +#define MINIUPNPC_URL_MAXSIZE (128) +struct IGDdatas_service { + char controlurl[MINIUPNPC_URL_MAXSIZE]; + char eventsuburl[MINIUPNPC_URL_MAXSIZE]; + char scpdurl[MINIUPNPC_URL_MAXSIZE]; + char servicetype[MINIUPNPC_URL_MAXSIZE]; + /*char devicetype[MINIUPNPC_URL_MAXSIZE];*/ +}; + +struct IGDdatas { + char cureltname[MINIUPNPC_URL_MAXSIZE]; + char urlbase[MINIUPNPC_URL_MAXSIZE]; + char presentationurl[MINIUPNPC_URL_MAXSIZE]; + int level; + /*int state;*/ + /* "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1" */ + struct IGDdatas_service CIF; + /* "urn:schemas-upnp-org:service:WANIPConnection:1" + * "urn:schemas-upnp-org:service:WANPPPConnection:1" */ + struct IGDdatas_service first; + /* if both WANIPConnection and WANPPPConnection are present */ + struct IGDdatas_service second; + /* "urn:schemas-upnp-org:service:WANIPv6FirewallControl:1" */ + struct IGDdatas_service IPv6FC; + /* tmp */ + struct IGDdatas_service tmp; +}; + +void IGDstartelt(void *, const char *, int); +void IGDendelt(void *, const char *, int); +void IGDdata(void *, const char *, int); +void printIGD(struct IGDdatas *); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c new file mode 100644 index 0000000..8889bf0 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.c @@ -0,0 +1,121 @@ +/* $Id: minisoap.c,v 1.21 2011/03/22 19:15:35 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2009 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * + * Minimal SOAP implementation for UPnP protocol. + */ +#include <stdio.h> +#include <string.h> +#ifdef WIN32 +#include <io.h> +#include <winsock2.h> +#define snprintf _snprintf +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#endif +#include "minisoap.h" +#include "miniupnpcstrings.h" + +/* only for malloc */ +#include <stdlib.h> + +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +/* httpWrite sends the headers and the body to the socket + * and returns the number of bytes sent */ +static int +httpWrite(int fd, const char * body, int bodysize, + const char * headers, int headerssize) +{ + int n = 0; + /*n = write(fd, headers, headerssize);*/ + /*if(bodysize>0) + n += write(fd, body, bodysize);*/ + /* Note : my old linksys router only took into account + * soap request that are sent into only one packet */ + char * p; + /* TODO: AVOID MALLOC */ + p = malloc(headerssize+bodysize); + if(!p) + return 0; + memcpy(p, headers, headerssize); + memcpy(p+headerssize, body, bodysize); + /*n = write(fd, p, headerssize+bodysize);*/ + n = send(fd, p, headerssize+bodysize, 0); + if(n<0) { + PRINT_SOCKET_ERROR("send"); + } + /* disable send on the socket */ + /* draytek routers dont seems to like that... */ +#if 0 +#ifdef WIN32 + if(shutdown(fd, SD_SEND)<0) { +#else + if(shutdown(fd, SHUT_WR)<0) { /*SD_SEND*/ +#endif + PRINT_SOCKET_ERROR("shutdown"); + } +#endif + free(p); + return n; +} + +/* self explanatory */ +int soapPostSubmit(int fd, + const char * url, + const char * host, + unsigned short port, + const char * action, + const char * body, + const char * httpversion) +{ + int bodysize; + char headerbuf[512]; + int headerssize; + char portstr[8]; + bodysize = (int)strlen(body); + /* We are not using keep-alive HTTP connections. + * HTTP/1.1 needs the header Connection: close to do that. + * This is the default with HTTP/1.0 + * Using HTTP/1.1 means we need to support chunked transfer-encoding : + * When using HTTP/1.1, the router "BiPAC 7404VNOX" always use chunked + * transfer encoding. */ + /* Connection: Close is normally there only in HTTP/1.1 but who knows */ + portstr[0] = '\0'; + if(port != 80) + snprintf(portstr, sizeof(portstr), ":%hu", port); + headerssize = snprintf(headerbuf, sizeof(headerbuf), + "POST %s HTTP/%s\r\n" + "Host: %s%s\r\n" + "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + "Content-Length: %d\r\n" + "Content-Type: text/xml\r\n" + "SOAPAction: \"%s\"\r\n" + "Connection: Close\r\n" + "Cache-Control: no-cache\r\n" /* ??? */ + "Pragma: no-cache\r\n" + "\r\n", + url, httpversion, host, portstr, bodysize, action); +#ifdef DEBUG + /*printf("SOAP request : headersize=%d bodysize=%d\n", + headerssize, bodysize); + */ + printf("SOAP request : POST %s HTTP/%s - Host: %s%s\n", + url, httpversion, host, portstr); + printf("SOAPAction: \"%s\" - Content-Length: %d\n", action, bodysize); + printf("Headers :\n%s", headerbuf); + printf("Body :\n%s\n", body); +#endif + return httpWrite(fd, body, bodysize, headerbuf, headerssize); +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h new file mode 100644 index 0000000..696725f --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minisoap.h @@ -0,0 +1,15 @@ +/* $Id: minisoap.h,v 1.4 2010/04/12 20:39:41 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ +#ifndef __MINISOAP_H__ +#define __MINISOAP_H__ + +/*int httpWrite(int, const char *, int, const char *);*/ +int soapPostSubmit(int, const char *, const char *, unsigned short, + const char *, const char *, const char *); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c new file mode 100644 index 0000000..e61c1cd --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.c @@ -0,0 +1,138 @@ +/* $Id: minissdpc.c,v 1.14 2010/11/25 09:57:25 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2009 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +/*#include <syslog.h>*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#ifndef WIN32 +#include <unistd.h> +#include <sys/types.h> +#else +#define ssize_t int +#endif + +#if defined(WIN32) || defined(__amigaos__) || defined(__amigaos4__) +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <winsock.h> +#include <stdint.h> +#endif +#if defined(__amigaos__) || defined(__amigaos4__) +#include <sys/socket.h> +#endif +#if defined(__amigaos__) +#define uint16_t unsigned short +#endif +/* Hack */ +#define UNIX_PATH_LEN 108 +struct sockaddr_un { + uint16_t sun_family; + char sun_path[UNIX_PATH_LEN]; +}; +#else +#include <sys/socket.h> +#include <sys/un.h> +#endif + +#include "minissdpc.h" +#include "miniupnpc.h" + +#include "codelength.h" + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = NULL; + unsigned char buffer[2048]; + ssize_t n; + unsigned char * p; + unsigned char * url; + unsigned int i; + unsigned int urlsize, stsize, usnsize, l; + int s; + struct sockaddr_un addr; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if(s < 0) + { + /*syslog(LOG_ERR, "socket(unix): %m");*/ + perror("socket(unix)"); + return NULL; + } + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, socketpath, sizeof(addr.sun_path)); + /* TODO : check if we need to handle the EINTR */ + if(connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) < 0) + { + /*syslog(LOG_WARNING, "connect(\"%s\"): %m", socketpath);*/ + close(s); + return NULL; + } + stsize = strlen(devtype); + buffer[0] = 1; /* request type 1 : request devices/services by type */ + p = buffer + 1; + l = stsize; CODELENGTH(l, p); + if(p + stsize > buffer + sizeof(buffer)) + { + /* devtype is too long ! */ + close(s); + return NULL; + } + memcpy(p, devtype, stsize); + p += stsize; + if(write(s, buffer, p - buffer) < 0) + { + /*syslog(LOG_ERR, "write(): %m");*/ + perror("minissdpc.c: write()"); + close(s); + return NULL; + } + n = read(s, buffer, sizeof(buffer)); + if(n<=0) + { + perror("minissdpc.c: read()"); + close(s); + return NULL; + } + p = buffer + 1; + for(i = 0; i < buffer[0]; i++) + { + if(p+2>=buffer+sizeof(buffer)) + break; + DECODELENGTH(urlsize, p); + if(p+urlsize+2>=buffer+sizeof(buffer)) + break; + url = p; + p += urlsize; + DECODELENGTH(stsize, p); + if(p+stsize+2>=buffer+sizeof(buffer)) + break; + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + memcpy(tmp->buffer, url, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->buffer + urlsize + 1, p, stsize); + p += stsize; + tmp->buffer[urlsize+1+stsize] = '\0'; + devlist = tmp; + /* added for compatibility with recent versions of MiniSSDPd + * >= 2007/12/19 */ + DECODELENGTH(usnsize, p); + p += usnsize; + if(p>buffer + sizeof(buffer)) + break; + } + close(s); + return devlist; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h new file mode 100644 index 0000000..25e91ce --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minissdpc.h @@ -0,0 +1,15 @@ +/* $Id: minissdpc.h,v 1.1 2007/08/31 15:15:33 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2005-2007 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __MINISSDPC_H__ +#define __MINISSDPC_H__ + +struct UPNPDev * +getDevicesFromMiniSSDPD(const char * devtype, const char * socketpath); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c new file mode 100644 index 0000000..bd46a24 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.c @@ -0,0 +1,906 @@ +/* $Id: miniupnpc.c,v 1.95 2011/05/15 21:42:26 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2005-2011 Thomas Bernard + * This software is subjet to the conditions detailed in the + * provided LICENSE file. */ +#define __EXTENSIONS__ 1 +#if !defined(MACOSX) && !defined(__sun) +#if !defined(_XOPEN_SOURCE) && !defined(__OpenBSD__) && !defined(__NetBSD__) +#ifndef __cplusplus +#define _XOPEN_SOURCE 600 +#endif +#endif +#ifndef __BSD_VISIBLE +#define __BSD_VISIBLE 1 +#endif +#endif + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#ifdef WIN32 +/* Win32 Specific includes and defines */ +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#include <iphlpapi.h> +#define snprintf _snprintf +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#define MAXHOSTNAMELEN 64 +#else /* #ifdef WIN32 */ +/* Standard POSIX includes */ +#include <unistd.h> +#if defined(__amigaos__) && !defined(__amigaos4__) +/* Amiga OS 3 specific stuff */ +#define socklen_t int +#else +#include <sys/select.h> +#endif +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/param.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <net/if.h> +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include <poll.h> +#endif +#include <strings.h> +#include <errno.h> +#define closesocket close +#endif /* #else WIN32 */ +#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT +#include <sys/time.h> +#endif +#if defined(__amigaos__) || defined(__amigaos4__) +/* Amiga OS specific stuff */ +#define TIMEVAL struct timeval +#endif + +#include "miniupnpc.h" +#include "minissdpc.h" +#include "miniwget.h" +#include "minisoap.h" +#include "minixml.h" +#include "upnpcommands.h" +#include "connecthostport.h" +#include "receivedata.h" + +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#define SOAPPREFIX "s" +#define SERVICEPREFIX "u" +#define SERVICEPREFIX2 'u' + +/* root description parsing */ +LIBSPEC void parserootdesc(const char * buffer, int bufsize, struct IGDdatas * data) +{ + struct xmlparser parser; + /* xmlparser object */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = data; + parser.starteltfunc = IGDstartelt; + parser.endeltfunc = IGDendelt; + parser.datafunc = IGDdata; + parser.attfunc = 0; + parsexml(&parser); +#ifdef DEBUG + printIGD(data); +#endif +} + +/* simpleUPnPcommand2 : + * not so simple ! + * return values : + * pointer - OK + * NULL - error */ +char * simpleUPnPcommand2(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize, const char * httpversion) +{ + char hostname[MAXHOSTNAMELEN+1]; + unsigned short port = 0; + char * path; + char soapact[128]; + char soapbody[2048]; + char * buf; + int n; + + *bufsize = 0; + snprintf(soapact, sizeof(soapact), "%s#%s", service, action); + if(args==NULL) + { + /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), + "<?xml version=\"1.0\"?>\r\n" + "<" SOAPPREFIX ":Envelope " + "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " + SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<" SOAPPREFIX ":Body>" + "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" + "</" SERVICEPREFIX ":%s>" + "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" + "\r\n", action, service, action); + } + else + { + char * p; + const char * pe, * pv; + int soapbodylen; + soapbodylen = snprintf(soapbody, sizeof(soapbody), + "<?xml version=\"1.0\"?>\r\n" + "<" SOAPPREFIX ":Envelope " + "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " + SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<" SOAPPREFIX ":Body>" + "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", + action, service); + p = soapbody + soapbodylen; + while(args->elt) + { + /* check that we are never overflowing the string... */ + if(soapbody + sizeof(soapbody) <= p + 100) + { + /* we keep a margin of at least 100 bytes */ + return NULL; + } + *(p++) = '<'; + pe = args->elt; + while(*pe) + *(p++) = *(pe++); + *(p++) = '>'; + if((pv = args->val)) + { + while(*pv) + *(p++) = *(pv++); + } + *(p++) = '<'; + *(p++) = '/'; + pe = args->elt; + while(*pe) + *(p++) = *(pe++); + *(p++) = '>'; + args++; + } + *(p++) = '<'; + *(p++) = '/'; + *(p++) = SERVICEPREFIX2; + *(p++) = ':'; + pe = action; + while(*pe) + *(p++) = *(pe++); + strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", + soapbody + sizeof(soapbody) - p); + } + if(!parseURL(url, hostname, &port, &path)) return NULL; + if(s<0) + { + s = connecthostport(hostname, port); + if(s < 0) + { + return NULL; + } + } + + n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); + if(n<=0) { +#ifdef DEBUG + printf("Error sending SOAP request\n"); +#endif + closesocket(s); + return NULL; + } + + buf = getHTTPResponse(s, bufsize); +#ifdef DEBUG + if(*bufsize > 0 && buf) + { + printf("SOAP Response :\n%.*s\n", *bufsize, buf); + } +#endif + closesocket(s); + return buf; +} + +/* simpleUPnPcommand : + * not so simple ! + * return values : + * pointer - OK + * NULL - error */ +char * simpleUPnPcommand(int s, const char * url, const char * service, + const char * action, struct UPNParg * args, + int * bufsize) +{ + char * buf; + + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); +/* + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.0"); + if (!buf || *bufsize == 0) + { +#if DEBUG + printf("Error or no result from SOAP request; retrying with HTTP/1.1\n"); +#endif + buf = simpleUPnPcommand2(s, url, service, action, args, bufsize, "1.1"); + } +*/ + return buf; +} + +/* parseMSEARCHReply() + * the last 4 arguments are filled during the parsing : + * - location/locationsize : "location:" field of the SSDP reply packet + * - st/stsize : "st:" field of the SSDP reply packet. + * The strings are NOT null terminated */ +static void +parseMSEARCHReply(const char * reply, int size, + const char * * location, int * locationsize, + const char * * st, int * stsize) +{ + int a, b, i; + i = 0; + a = i; /* start of the line */ + b = 0; /* end of the "header" (position of the colon) */ + while(i<size) + { + switch(reply[i]) + { + case ':': + if(b==0) + { + b = i; /* end of the "header" */ + /*for(j=a; j<b; j++) + { + putchar(reply[j]); + } + */ + } + break; + case '\x0a': + case '\x0d': + if(b!=0) + { + /*for(j=b+1; j<i; j++) + { + putchar(reply[j]); + } + putchar('\n');*/ + /* skip the colon and white spaces */ + do { b++; } while(reply[b]==' '); + if(0==strncasecmp(reply+a, "location", 8)) + { + *location = reply+b; + *locationsize = i-b; + } + else if(0==strncasecmp(reply+a, "st", 2)) + { + *st = reply+b; + *stsize = i-b; + } + b = 0; + } + a = i+1; + break; + default: + break; + } + i++; + } +} + +/* port upnp discover : SSDP protocol */ +#define PORT 1900 +#define XSTR(s) STR(s) +#define STR(s) #s +#define UPNP_MCAST_ADDR "239.255.255.250" +/* for IPv6 */ +#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ +#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ + +/* upnpDiscover() : + * return a chained list of all devices found or NULL if + * no devices was found. + * It is up to the caller to free the chained list + * delay is in millisecond (poll) */ +LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error) +{ + struct UPNPDev * tmp; + struct UPNPDev * devlist = 0; + int opt = 1; + static const char MSearchMsgFmt[] = + "M-SEARCH * HTTP/1.1\r\n" + "HOST: %s:" XSTR(PORT) "\r\n" + "ST: %s\r\n" + "MAN: \"ssdp:discover\"\r\n" + "MX: %u\r\n" + "\r\n"; + static const char * const deviceList[] = { +#if 0 + "urn:schemas-upnp-org:device:InternetGatewayDevice:2", + "urn:schemas-upnp-org:service:WANIPConnection:2", +#endif + "urn:schemas-upnp-org:device:InternetGatewayDevice:1", + "urn:schemas-upnp-org:service:WANIPConnection:1", + "urn:schemas-upnp-org:service:WANPPPConnection:1", + "upnp:rootdevice", + 0 + }; + int deviceIndex = 0; + char bufr[1536]; /* reception and emission buffer */ + int sudp; + int n; + struct sockaddr_storage sockudp_r; + unsigned int mx; +#ifdef NO_GETADDRINFO + struct sockaddr_storage sockudp_w; +#else + int rv; + struct addrinfo hints, *servinfo, *p; +#endif +#ifdef WIN32 + MIB_IPFORWARDROW ip_forward; +#endif + int linklocal = 1; + + if(error) + *error = UPNPDISCOVER_UNKNOWN_ERROR; +#if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) + /* first try to get infos from minissdpd ! */ + if(!minissdpdsock) + minissdpdsock = "/var/run/minissdpd.sock"; + while(!devlist && deviceList[deviceIndex]) { + devlist = getDevicesFromMiniSSDPD(deviceList[deviceIndex], + minissdpdsock); + /* We return what we have found if it was not only a rootdevice */ + if(devlist && !strstr(deviceList[deviceIndex], "rootdevice")) { + if(error) + *error = UPNPDISCOVER_SUCCESS; + return devlist; + } + deviceIndex++; + } + deviceIndex = 0; +#endif + /* fallback to direct discovery */ +#ifdef WIN32 + sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, IPPROTO_UDP); +#else + sudp = socket(ipv6 ? PF_INET6 : PF_INET, SOCK_DGRAM, 0); +#endif + if(sudp < 0) + { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("socket"); + return NULL; + } + /* reception */ + memset(&sockudp_r, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_r; + p->sin6_family = AF_INET6; + if(sameport) + p->sin6_port = htons(PORT); + p->sin6_addr = in6addr_any; /* in6addr_any is not available with MinGW32 3.4.2 */ + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_r; + p->sin_family = AF_INET; + if(sameport) + p->sin_port = htons(PORT); + p->sin_addr.s_addr = INADDR_ANY; + } +#ifdef WIN32 +/* This code could help us to use the right Network interface for + * SSDP multicast traffic */ +/* Get IP associated with the index given in the ip_forward struct + * in order to give this ip to setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF) */ + if(!ipv6 + && (GetBestRoute(inet_addr("223.255.255.255"), 0, &ip_forward) == NO_ERROR)) { + DWORD dwRetVal = 0; + PMIB_IPADDRTABLE pIPAddrTable; + DWORD dwSize = 0; +#ifdef DEBUG + IN_ADDR IPAddr; +#endif + int i; +#ifdef DEBUG + printf("ifIndex=%lu nextHop=%lx \n", ip_forward.dwForwardIfIndex, ip_forward.dwForwardNextHop); +#endif + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(sizeof (MIB_IPADDRTABLE)); + if (GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) { + free(pIPAddrTable); + pIPAddrTable = (MIB_IPADDRTABLE *) malloc(dwSize); + } + if(pIPAddrTable) { + dwRetVal = GetIpAddrTable( pIPAddrTable, &dwSize, 0 ); +#ifdef DEBUG + printf("\tNum Entries: %ld\n", pIPAddrTable->dwNumEntries); +#endif + for (i=0; i < (int) pIPAddrTable->dwNumEntries; i++) { +#ifdef DEBUG + printf("\n\tInterface Index[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwIndex); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr; + printf("\tIP Address[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask; + printf("\tSubnet Mask[%d]: \t%s\n", i, inet_ntoa(IPAddr) ); + IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr; + printf("\tBroadCast[%d]: \t%s (%ld)\n", i, inet_ntoa(IPAddr), pIPAddrTable->table[i].dwBCastAddr); + printf("\tReassembly size[%d]:\t%ld\n", i, pIPAddrTable->table[i].dwReasmSize); + printf("\tType and State[%d]:", i); + printf("\n"); +#endif + if (pIPAddrTable->table[i].dwIndex == ip_forward.dwForwardIfIndex) { + /* Set the address of this interface to be used */ + struct in_addr mc_if; + memset(&mc_if, 0, sizeof(mc_if)); + mc_if.s_addr = pIPAddrTable->table[i].dwAddr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) { + PRINT_SOCKET_ERROR("setsockopt"); + } + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = pIPAddrTable->table[i].dwAddr; +#ifndef DEBUG + break; +#endif + } + } + free(pIPAddrTable); + pIPAddrTable = NULL; + } + } +#endif + +#ifdef WIN32 + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof (opt)) < 0) +#else + if (setsockopt(sudp, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt)) < 0) +#endif + { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("setsockopt"); + return NULL; + } + + if(multicastif) + { + if(ipv6) { +#if !defined(WIN32) + /* according to MSDN, if_nametoindex() is supported since + * MS Windows Vista and MS Windows Server 2008. + * http://msdn.microsoft.com/en-us/library/bb408409%28v=vs.85%29.aspx */ + unsigned int ifindex = if_nametoindex(multicastif); /* eth0, etc. */ + if(setsockopt(sudp, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(&ifindex)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } +#else +#ifdef DEBUG + printf("Setting of multicast interface not supported in IPv6 under Windows.\n"); +#endif +#endif + } else { + struct in_addr mc_if; + mc_if.s_addr = inet_addr(multicastif); /* ex: 192.168.x.x */ + ((struct sockaddr_in *)&sockudp_r)->sin_addr.s_addr = mc_if.s_addr; + if(setsockopt(sudp, IPPROTO_IP, IP_MULTICAST_IF, (const char *)&mc_if, sizeof(mc_if)) < 0) + { + PRINT_SOCKET_ERROR("setsockopt"); + } + } + } + + /* Avant d'envoyer le paquet on bind pour recevoir la reponse */ + if (bind(sudp, (const struct sockaddr *)&sockudp_r, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) != 0) + { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("bind"); + closesocket(sudp); + return NULL; + } + + if(error) + *error = UPNPDISCOVER_SUCCESS; + /* Calculating maximum response time in seconds */ + mx = ((unsigned int)delay) / 1000u; + /* receiving SSDP response packet */ + for(n = 0; deviceList[deviceIndex]; deviceIndex++) + { + if(n == 0) + { + /* sending the SSDP M-SEARCH packet */ + n = snprintf(bufr, sizeof(bufr), + MSearchMsgFmt, + ipv6 ? + (linklocal ? "[" UPNP_MCAST_LL_ADDR "]" : "[" UPNP_MCAST_SL_ADDR "]") + : UPNP_MCAST_ADDR, + deviceList[deviceIndex], mx); +#ifdef DEBUG + printf("Sending %s", bufr); +#endif +#ifdef NO_GETADDRINFO + /* the following code is not using getaddrinfo */ + /* emission */ + memset(&sockudp_w, 0, sizeof(struct sockaddr_storage)); + if(ipv6) { + struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockudp_w; + p->sin6_family = AF_INET6; + p->sin6_port = htons(PORT); + inet_pton(AF_INET6, + linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR, + &(p->sin6_addr)); + } else { + struct sockaddr_in * p = (struct sockaddr_in *)&sockudp_w; + p->sin_family = AF_INET; + p->sin_port = htons(PORT); + p->sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR); + } + n = sendto(sudp, bufr, n, 0, + &sockudp_w, + ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)); + if (n < 0) { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + PRINT_SOCKET_ERROR("sendto"); + break; + } +#else /* #ifdef NO_GETADDRINFO */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // AF_INET6 or AF_INET + hints.ai_socktype = SOCK_DGRAM; + /*hints.ai_flags = */ + if ((rv = getaddrinfo(ipv6 + ? (linklocal ? UPNP_MCAST_LL_ADDR : UPNP_MCAST_SL_ADDR) + : UPNP_MCAST_ADDR, + XSTR(PORT), &hints, &servinfo)) != 0) { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; +#ifdef WIN32 + fprintf(stderr, "getaddrinfo() failed: %d\n", rv); +#else + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); +#endif + break; + } + for(p = servinfo; p; p = p->ai_next) { + n = sendto(sudp, bufr, n, 0, p->ai_addr, p->ai_addrlen); + if (n < 0) { + PRINT_SOCKET_ERROR("sendto"); + continue; + } + } + freeaddrinfo(servinfo); + if(n < 0) { + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + break; + } +#endif /* #ifdef NO_GETADDRINFO */ + } + /* Waiting for SSDP REPLY packet to M-SEARCH */ + n = receivedata(sudp, bufr, sizeof(bufr), delay); + if (n < 0) { + /* error */ + if(error) + *error = UPNPDISCOVER_SOCKET_ERROR; + break; + } else if (n == 0) { + /* no data or Time Out */ + if (devlist) { + /* no more device type to look for... */ + if(error) + *error = UPNPDISCOVER_SUCCESS; + break; + } + if(ipv6) { + if(linklocal) { + linklocal = 0; + --deviceIndex; + } else { + linklocal = 1; + } + } + } else { + const char * descURL=NULL; + int urlsize=0; + const char * st=NULL; + int stsize=0; + /*printf("%d byte(s) :\n%s\n", n, bufr);*/ /* affichage du message */ + parseMSEARCHReply(bufr, n, &descURL, &urlsize, &st, &stsize); + if(st&&descURL) + { +#ifdef DEBUG + printf("M-SEARCH Reply:\nST: %.*s\nLocation: %.*s\n", + stsize, st, urlsize, descURL); +#endif + for(tmp=devlist; tmp; tmp = tmp->pNext) { + if(memcmp(tmp->descURL, descURL, urlsize) == 0 && + tmp->descURL[urlsize] == '\0' && + memcmp(tmp->st, st, stsize) == 0 && + tmp->st[stsize] == '\0') + break; + } + /* at the exit of the loop above, tmp is null if + * no duplicate device was found */ + if(tmp) + continue; + tmp = (struct UPNPDev *)malloc(sizeof(struct UPNPDev)+urlsize+stsize); + if(!tmp) { + /* memory allocation error */ + if(error) + *error = UPNPDISCOVER_MEMORY_ERROR; + break; + } + tmp->pNext = devlist; + tmp->descURL = tmp->buffer; + tmp->st = tmp->buffer + 1 + urlsize; + memcpy(tmp->buffer, descURL, urlsize); + tmp->buffer[urlsize] = '\0'; + memcpy(tmp->buffer + urlsize + 1, st, stsize); + tmp->buffer[urlsize+1+stsize] = '\0'; + devlist = tmp; + } + } + } + closesocket(sudp); + return devlist; +} + +/* freeUPNPDevlist() should be used to + * free the chained list returned by upnpDiscover() */ +LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist) +{ + struct UPNPDev * next; + while(devlist) + { + next = devlist->pNext; + free(devlist); + devlist = next; + } +} + +static void +url_cpy_or_cat(char * dst, const char * src, int n) +{ + if( (src[0] == 'h') + &&(src[1] == 't') + &&(src[2] == 't') + &&(src[3] == 'p') + &&(src[4] == ':') + &&(src[5] == '/') + &&(src[6] == '/')) + { + strncpy(dst, src, n); + } + else + { + int l = strlen(dst); + if(src[0] != '/') + dst[l++] = '/'; + if(l<=n) + strncpy(dst + l, src, n - l); + } +} + +/* Prepare the Urls for usage... + */ +LIBSPEC void GetUPNPUrls(struct UPNPUrls * urls, struct IGDdatas * data, + const char * descURL) +{ + char * p; + int n1, n2, n3, n4; + n1 = strlen(data->urlbase); + if(n1==0) + n1 = strlen(descURL); + n1 += 2; /* 1 byte more for Null terminator, 1 byte for '/' if needed */ + n2 = n1; n3 = n1; n4 = n1; + n1 += strlen(data->first.scpdurl); + n2 += strlen(data->first.controlurl); + n3 += strlen(data->CIF.controlurl); + n4 += strlen(data->IPv6FC.controlurl); + + urls->ipcondescURL = (char *)malloc(n1); + urls->controlURL = (char *)malloc(n2); + urls->controlURL_CIF = (char *)malloc(n3); + urls->controlURL_6FC = (char *)malloc(n4); + /* maintenant on chope la desc du WANIPConnection */ + if(data->urlbase[0] != '\0') + strncpy(urls->ipcondescURL, data->urlbase, n1); + else + strncpy(urls->ipcondescURL, descURL, n1); + p = strchr(urls->ipcondescURL+7, '/'); + if(p) p[0] = '\0'; + strncpy(urls->controlURL, urls->ipcondescURL, n2); + strncpy(urls->controlURL_CIF, urls->ipcondescURL, n3); + strncpy(urls->controlURL_6FC, urls->ipcondescURL, n4); + + url_cpy_or_cat(urls->ipcondescURL, data->first.scpdurl, n1); + + url_cpy_or_cat(urls->controlURL, data->first.controlurl, n2); + + url_cpy_or_cat(urls->controlURL_CIF, data->CIF.controlurl, n3); + + url_cpy_or_cat(urls->controlURL_6FC, data->IPv6FC.controlurl, n4); + +#ifdef DEBUG + printf("urls->ipcondescURL='%s' %u n1=%d\n", urls->ipcondescURL, + (unsigned)strlen(urls->ipcondescURL), n1); + printf("urls->controlURL='%s' %u n2=%d\n", urls->controlURL, + (unsigned)strlen(urls->controlURL), n2); + printf("urls->controlURL_CIF='%s' %u n3=%d\n", urls->controlURL_CIF, + (unsigned)strlen(urls->controlURL_CIF), n3); + printf("urls->controlURL_6FC='%s' %u n4=%d\n", urls->controlURL_6FC, + (unsigned)strlen(urls->controlURL_6FC), n4); +#endif +} + +LIBSPEC void +FreeUPNPUrls(struct UPNPUrls * urls) +{ + if(!urls) + return; + free(urls->controlURL); + urls->controlURL = 0; + free(urls->ipcondescURL); + urls->ipcondescURL = 0; + free(urls->controlURL_CIF); + urls->controlURL_CIF = 0; + free(urls->controlURL_6FC); + urls->controlURL_6FC = 0; +} + +int +UPNPIGD_IsConnected(struct UPNPUrls * urls, struct IGDdatas * data) +{ + char status[64]; + unsigned int uptime; + status[0] = '\0'; + UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, + status, &uptime, NULL); + if(0 == strcmp("Connected", status)) + { + return 1; + } + else + return 0; +} + + +/* UPNP_GetValidIGD() : + * return values : + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any non zero return case, the urls and data structures + * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen) +{ + char * descXML; + int descXMLsize = 0; + struct UPNPDev * dev; + int ndev = 0; + int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ + if(!devlist) + { +#ifdef DEBUG + printf("Empty devlist\n"); +#endif + return 0; + } + for(state = 1; state <= 3; state++) + { + for(dev = devlist; dev; dev = dev->pNext) + { + /* we should choose an internet gateway device. + * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ + descXML = miniwget_getaddr(dev->descURL, &descXMLsize, + lanaddr, lanaddrlen); + if(descXML) + { + ndev++; + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(descXML, descXMLsize, data); + free(descXML); + descXML = NULL; + if(0==strcmp(data->CIF.servicetype, + "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") + || state >= 3 ) + { + GetUPNPUrls(urls, data, dev->descURL); + +#ifdef DEBUG + printf("UPNPIGD_IsConnected(%s) = %d\n", + urls->controlURL, + UPNPIGD_IsConnected(urls, data)); +#endif + if((state >= 2) || UPNPIGD_IsConnected(urls, data)) + return state; + FreeUPNPUrls(urls); + if(data->second.servicetype[0] != '\0') { +#ifdef DEBUG + printf("We tried %s, now we try %s !\n", + data->first.servicetype, data->second.servicetype); +#endif + /* swaping WANPPPConnection and WANIPConnection ! */ + memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); + memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); + memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); + GetUPNPUrls(urls, data, dev->descURL); +#ifdef DEBUG + printf("UPNPIGD_IsConnected(%s) = %d\n", + urls->controlURL, + UPNPIGD_IsConnected(urls, data)); +#endif + if((state >= 2) || UPNPIGD_IsConnected(urls, data)) + return state; + FreeUPNPUrls(urls); + } + } + memset(data, 0, sizeof(struct IGDdatas)); + } +#ifdef DEBUG + else + { + printf("error getting XML description %s\n", dev->descURL); + } +#endif + } + } + return 0; +} + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + * 0 - Not ok + * 1 - OK */ +int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen) +{ + char * descXML; + int descXMLsize = 0; + descXML = miniwget_getaddr(rootdescurl, &descXMLsize, + lanaddr, lanaddrlen); + if(descXML) { + memset(data, 0, sizeof(struct IGDdatas)); + memset(urls, 0, sizeof(struct UPNPUrls)); + parserootdesc(descXML, descXMLsize, data); + free(descXML); + descXML = NULL; + GetUPNPUrls(urls, data, rootdescurl); + return 1; + } else { + return 0; + } +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h new file mode 100644 index 0000000..50df017 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpc.h @@ -0,0 +1,121 @@ +/* $Id: miniupnpc.h,v 1.23 2011/04/11 08:21:46 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ + * Author: Thomas Bernard + * Copyright (c) 2005-2011 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __MINIUPNPC_H__ +#define __MINIUPNPC_H__ + +#include "declspec.h" +#include "igd_desc_parse.h" + +/* error codes : */ +#define UPNPDISCOVER_SUCCESS (0) +#define UPNPDISCOVER_UNKNOWN_ERROR (-1) +#define UPNPDISCOVER_SOCKET_ERROR (-101) +#define UPNPDISCOVER_MEMORY_ERROR (-102) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structures definitions : */ +struct UPNParg { const char * elt; const char * val; }; + +char * +simpleUPnPcommand(int, const char *, const char *, + const char *, struct UPNParg *, + int *); + +struct UPNPDev { + struct UPNPDev * pNext; + char * descURL; + char * st; + char buffer[2]; +}; + +/* upnpDiscover() + * discover UPnP devices on the network. + * The discovered devices are returned as a chained list. + * It is up to the caller to free the list with freeUPNPDevlist(). + * delay (in millisecond) is the maximum time for waiting any device + * response. + * If available, device list will be obtained from MiniSSDPd. + * Default path for minissdpd socket will be used if minissdpdsock argument + * is NULL. + * If multicastif is not NULL, it will be used instead of the default + * multicast interface for sending SSDP discover packets. + * If sameport is not null, SSDP packets will be sent from the source port + * 1900 (same as destination port) otherwise system assign a source port. */ +LIBSPEC struct UPNPDev * +upnpDiscover(int delay, const char * multicastif, + const char * minissdpdsock, int sameport, + int ipv6, + int * error); +/* freeUPNPDevlist() + * free list returned by upnpDiscover() */ +LIBSPEC void freeUPNPDevlist(struct UPNPDev * devlist); + +/* parserootdesc() : + * parse root XML description of a UPnP device and fill the IGDdatas + * structure. */ +LIBSPEC void parserootdesc(const char *, int, struct IGDdatas *); + +/* structure used to get fast access to urls + * controlURL: controlURL of the WANIPConnection + * ipcondescURL: url of the description of the WANIPConnection + * controlURL_CIF: controlURL of the WANCommonInterfaceConfig + * controlURL_6FC: controlURL of the WANIPv6FirewallControl + */ +struct UPNPUrls { + char * controlURL; + char * ipcondescURL; + char * controlURL_CIF; + char * controlURL_6FC; +}; + +/* UPNP_GetValidIGD() : + * return values : + * 0 = NO IGD found + * 1 = A valid connected IGD has been found + * 2 = A valid IGD has been found but it reported as + * not connected + * 3 = an UPnP device has been found but was not recognized as an IGD + * + * In any non zero return case, the urls and data structures + * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to + * free allocated memory. + */ +LIBSPEC int +UPNP_GetValidIGD(struct UPNPDev * devlist, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +/* UPNP_GetIGDFromUrl() + * Used when skipping the discovery process. + * return value : + * 0 - Not ok + * 1 - OK */ +LIBSPEC int +UPNP_GetIGDFromUrl(const char * rootdescurl, + struct UPNPUrls * urls, + struct IGDdatas * data, + char * lanaddr, int lanaddrlen); + +LIBSPEC void GetUPNPUrls(struct UPNPUrls *, struct IGDdatas *, const char *); + +LIBSPEC void FreeUPNPUrls(struct UPNPUrls *); + +/* return 0 or 1 */ +LIBSPEC int UPNPIGD_IsConnected(struct UPNPUrls *, struct IGDdatas *); + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h new file mode 100644 index 0000000..86081c3 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniupnpctypes.h @@ -0,0 +1,19 @@ +/* $Id: miniupnpctypes.h,v 1.1 2011/02/15 11:10:40 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef __MINIUPNPCTYPES_H__ +#define __MINIUPNPCTYPES_H__ + +#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) +#define UNSIGNED_INTEGER unsigned long long +#define STRTOUI strtoull +#else +#define UNSIGNED_INTEGER unsigned int +#define STRTOUI strtoul +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c new file mode 100644 index 0000000..87f6155 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.c @@ -0,0 +1,522 @@ +/* $Id: miniwget.c,v 1.52 2011/06/17 22:59:42 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#define MAXHOSTNAMELEN 64 +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define snprintf _snprintf +#define socklen_t int +#ifndef strncasecmp +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#define strncasecmp _memicmp +#else /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#define strncasecmp memicmp +#endif /* defined(_MSC_VER) && (_MSC_VER >= 1400) */ +#endif /* #ifndef strncasecmp */ +#else /* #ifdef WIN32 */ +#include <unistd.h> +#include <sys/param.h> +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/select.h> +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netdb.h> +#define closesocket close +/* defining MINIUPNPC_IGNORE_EINTR enable the ignore of interruptions + * during the connect() call */ +#define MINIUPNPC_IGNORE_EINTR +#endif /* #else WIN32 */ +#if defined(__sun) || defined(sun) +#define MIN(x,y) (((x)<(y))?(x):(y)) +#endif + +#include "miniupnpcstrings.h" +#include "miniwget.h" +#include "connecthostport.h" +#include "receivedata.h" + +/* + * Read a HTTP response from a socket. + * Process Content-Length and Transfer-encoding headers. + * return a pointer to the content buffer, which length is saved + * to the length parameter. + */ +void * +getHTTPResponse(int s, int * size) +{ + char buf[2048]; + int n; + int endofheaders = 0; + int chunked = 0; + int content_length = -1; + unsigned int chunksize = 0; + unsigned int bytestocopy = 0; + /* buffers : */ + char * header_buf; + int header_buf_len = 2048; + int header_buf_used = 0; + char * content_buf; + int content_buf_len = 2048; + int content_buf_used = 0; + char chunksize_buf[32]; + int chunksize_buf_index; + + header_buf = malloc(header_buf_len); + content_buf = malloc(content_buf_len); + chunksize_buf[0] = '\0'; + chunksize_buf_index = 0; + + while((n = receivedata(s, buf, 2048, 5000)) > 0) + { + if(endofheaders == 0) + { + int i; + int linestart=0; + int colon=0; + int valuestart=0; + if(header_buf_used + n > header_buf_len) { + header_buf = realloc(header_buf, header_buf_used + n); + header_buf_len = header_buf_used + n; + } + memcpy(header_buf + header_buf_used, buf, n); + header_buf_used += n; + /* search for CR LF CR LF (end of headers) + * recognize also LF LF */ + i = 0; + while(i < (header_buf_used-1) && (endofheaders == 0)) { + if(header_buf[i] == '\r') { + i++; + if(header_buf[i] == '\n') { + i++; + if(i < header_buf_used && header_buf[i] == '\r') { + i++; + if(i < header_buf_used && header_buf[i] == '\n') { + endofheaders = i+1; + } + } + } + } else if(header_buf[i] == '\n') { + i++; + if(header_buf[i] == '\n') { + endofheaders = i+1; + } + } + i++; + } + if(endofheaders == 0) + continue; + /* parse header lines */ + for(i = 0; i < endofheaders - 1; i++) { + if(colon <= linestart && header_buf[i]==':') + { + colon = i; + while(i < (endofheaders-1) + && (header_buf[i+1] == ' ' || header_buf[i+1] == '\t')) + i++; + valuestart = i + 1; + } + /* detecting end of line */ + else if(header_buf[i]=='\r' || header_buf[i]=='\n') + { + if(colon > linestart && valuestart > colon) + { +#ifdef DEBUG + printf("header='%.*s', value='%.*s'\n", + colon-linestart, header_buf+linestart, + i-valuestart, header_buf+valuestart); +#endif + if(0==strncasecmp(header_buf+linestart, "content-length", colon-linestart)) + { + content_length = atoi(header_buf+valuestart); +#ifdef DEBUG + printf("Content-Length: %d\n", content_length); +#endif + } + else if(0==strncasecmp(header_buf+linestart, "transfer-encoding", colon-linestart) + && 0==strncasecmp(header_buf+valuestart, "chunked", 7)) + { +#ifdef DEBUG + printf("chunked transfer-encoding!\n"); +#endif + chunked = 1; + } + } + while(header_buf[i]=='\r' || header_buf[i] == '\n') + i++; + linestart = i; + colon = linestart; + valuestart = 0; + } + } + /* copy the remaining of the received data back to buf */ + n = header_buf_used - endofheaders; + memcpy(buf, header_buf + endofheaders, n); + /* if(headers) */ + } + if(endofheaders) + { + /* content */ + if(chunked) + { + int i = 0; + while(i < n) + { + if(chunksize == 0) + { + /* reading chunk size */ + if(chunksize_buf_index == 0) { + /* skipping any leading CR LF */ + if(i<n && buf[i] == '\r') i++; + if(i<n && buf[i] == '\n') i++; + } + while(i<n && isxdigit(buf[i]) + && chunksize_buf_index < (sizeof(chunksize_buf)-1)) + { + chunksize_buf[chunksize_buf_index++] = buf[i]; + chunksize_buf[chunksize_buf_index] = '\0'; + i++; + } + while(i<n && buf[i] != '\r' && buf[i] != '\n') + i++; /* discarding chunk-extension */ + if(i<n && buf[i] == '\r') i++; + if(i<n && buf[i] == '\n') { + int j; + for(j = 0; j < chunksize_buf_index; j++) { + if(chunksize_buf[j] >= '0' + && chunksize_buf[j] <= '9') + chunksize = (chunksize << 4) + (chunksize_buf[j] - '0'); + else + chunksize = (chunksize << 4) + ((chunksize_buf[j] | 32) - 'a' + 10); + } + chunksize_buf[0] = '\0'; + chunksize_buf_index = 0; + i++; + } else { + /* not finished to get chunksize */ + continue; + } +#ifdef DEBUG + printf("chunksize = %u (%x)\n", chunksize, chunksize); +#endif + if(chunksize == 0) + { +#ifdef DEBUG + printf("end of HTTP content - %d %d\n", i, n); + /*printf("'%.*s'\n", n-i, buf+i);*/ +#endif + goto end_of_stream; + } + } + bytestocopy = ((int)chunksize < n - i)?chunksize:(n - i); + if((int)(content_buf_used + bytestocopy) > content_buf_len) + { + if(content_length >= content_buf_used + (int)bytestocopy) { + content_buf_len = content_length; + } else { + content_buf_len = content_buf_used + (int)bytestocopy; + } + content_buf = (char *)realloc((void *)content_buf, + content_buf_len); + } + memcpy(content_buf + content_buf_used, buf + i, bytestocopy); + content_buf_used += bytestocopy; + i += bytestocopy; + chunksize -= bytestocopy; + } + } + else + { + /* not chunked */ + if(content_length > 0 + && (content_buf_used + n) > content_length) { + /* skipping additional bytes */ + n = content_length - content_buf_used; + } + if(content_buf_used + n > content_buf_len) + { + if(content_length >= content_buf_used + n) { + content_buf_len = content_length; + } else { + content_buf_len = content_buf_used + n; + } + content_buf = (char *)realloc((void *)content_buf, + content_buf_len); + } + memcpy(content_buf + content_buf_used, buf, n); + content_buf_used += n; + } + } + /* use the Content-Length header value if available */ + if(content_length > 0 && content_buf_used >= content_length) + { +#ifdef DEBUG + printf("End of HTTP content\n"); +#endif + break; + } + } +end_of_stream: + free(header_buf); header_buf = NULL; + *size = content_buf_used; + if(content_buf_used == 0) + { + free(content_buf); + content_buf = NULL; + } + return content_buf; +} + +/* miniwget3() : + * do all the work. + * Return NULL if something failed. */ +static void * +miniwget3(const char * url, const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len, + const char * httpversion) +{ + char buf[2048]; + int s; + int n; + int len; + int sent; + void * content; + + *size = 0; + s = connecthostport(host, port); + if(s < 0) + return NULL; + + /* get address for caller ! */ + if(addr_str) + { + struct sockaddr_storage saddr; + socklen_t saddrlen; + + saddrlen = sizeof(saddr); + if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) + { + perror("getsockname"); + } + else + { +#if defined(__amigaos__) && !defined(__amigaos4__) + /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); + * But his function make a string with the port : nn.nn.nn.nn:port */ +/* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), + NULL, addr_str, (DWORD *)&addr_str_len)) + { + printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); + }*/ + /* the following code is only compatible with ip v4 addresses */ + strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); +#else +#if 0 + if(saddr.sa_family == AF_INET6) { + inet_ntop(AF_INET6, + &(((struct sockaddr_in6 *)&saddr)->sin6_addr), + addr_str, addr_str_len); + } else { + inet_ntop(AF_INET, + &(((struct sockaddr_in *)&saddr)->sin_addr), + addr_str, addr_str_len); + } +#endif + /* getnameinfo return ip v6 address with the scope identifier + * such as : 2a01:e35:8b2b:7330::%4281128194 */ + n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, + addr_str, addr_str_len, + NULL, 0, + NI_NUMERICHOST | NI_NUMERICSERV); + if(n != 0) { +#ifdef WIN32 + fprintf(stderr, "getnameinfo() failed : %d\n", n); +#else + fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); +#endif + } +#endif + } +#ifdef DEBUG + printf("address miniwget : %s\n", addr_str); +#endif + } + + len = snprintf(buf, sizeof(buf), + "GET %s HTTP/%s\r\n" + "Host: %s:%d\r\n" + "Connection: Close\r\n" + "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" + + "\r\n", + path, httpversion, host, port); + sent = 0; + /* sending the HTTP request */ + while(sent < len) + { + n = send(s, buf+sent, len-sent, 0); + if(n < 0) + { + perror("send"); + closesocket(s); + return NULL; + } + else + { + sent += n; + } + } + content = getHTTPResponse(s, size); + closesocket(s); + return content; +} + +/* miniwget2() : + * Call miniwget3(); retry with HTTP/1.1 if 1.0 fails. */ +static void * +miniwget2(const char * url, const char * host, + unsigned short port, const char * path, + int * size, char * addr_str, int addr_str_len) +{ + char * respbuffer; + + respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); +/* + respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.0"); + if (*size == 0) + { +#ifdef DEBUG + printf("Retrying with HTTP/1.1\n"); +#endif + free(respbuffer); + respbuffer = miniwget3(url, host, port, path, size, addr_str, addr_str_len, "1.1"); + } +*/ + return respbuffer; +} + + + + +/* parseURL() + * arguments : + * url : source string not modified + * hostname : hostname destination string (size of MAXHOSTNAMELEN+1) + * port : port (destination) + * path : pointer to the path part of the URL + * + * Return values : + * 0 - Failure + * 1 - Success */ +int parseURL(const char * url, char * hostname, unsigned short * port, char * * path) +{ + char * p1, *p2, *p3; + if(!url) + return 0; + p1 = strstr(url, "://"); + if(!p1) + return 0; + p1 += 3; + if( (url[0]!='h') || (url[1]!='t') + ||(url[2]!='t') || (url[3]!='p')) + return 0; + memset(hostname, 0, MAXHOSTNAMELEN + 1); + if(*p1 == '[') + { + /* IP v6 : http://[2a00:1450:8002::6a]/path/abc */ + p2 = strchr(p1, ']'); + p3 = strchr(p1, '/'); + if(p2 && p3) + { + p2++; + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); + if(*p2 == ':') + { + *port = 0; + p2++; + while( (*p2 >= '0') && (*p2 <= '9')) + { + *port *= 10; + *port += (unsigned short)(*p2 - '0'); + p2++; + } + } + else + { + *port = 80; + } + *path = p3; + return 1; + } + } + p2 = strchr(p1, ':'); + p3 = strchr(p1, '/'); + if(!p3) + return 0; + if(!p2 || (p2>p3)) + { + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); + *port = 80; + } + else + { + strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); + *port = 0; + p2++; + while( (*p2 >= '0') && (*p2 <= '9')) + { + *port *= 10; + *port += (unsigned short)(*p2 - '0'); + p2++; + } + } + *path = p3; + return 1; +} + +void * miniwget(const char * url, int * size) +{ + unsigned short port; + char * path; + /* protocol://host:port/chemin */ + char hostname[MAXHOSTNAMELEN+1]; + *size = 0; + if(!parseURL(url, hostname, &port, &path)) + return NULL; +#ifdef DEBUG + printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); +#endif + return miniwget2(url, hostname, port, path, size, 0, 0); +} + +void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen) +{ + unsigned short port; + char * path; + /* protocol://host:port/chemin */ + char hostname[MAXHOSTNAMELEN+1]; + *size = 0; + if(addr) + addr[0] = '\0'; + if(!parseURL(url, hostname, &port, &path)) + return NULL; +#ifdef DEBUG + printf("parsed url : hostname='%s' port=%hu path='%s'\n", hostname, port, path); +#endif + return miniwget2(url, hostname, port, path, size, addr, addrlen); +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h new file mode 100644 index 0000000..8314b40 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/miniwget.h @@ -0,0 +1,30 @@ +/* $Id: miniwget.h,v 1.6 2010/12/09 16:11:33 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef __MINIWGET_H__ +#define __MINIWGET_H__ + +#include "declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +LIBSPEC void * getHTTPResponse(int s, int * size); + +LIBSPEC void * miniwget(const char *, int *); + +LIBSPEC void * miniwget_getaddr(const char *, int *, char *, int); + +int parseURL(const char *, char *, unsigned short *, char * *); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c new file mode 100644 index 0000000..8b5594c --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.c @@ -0,0 +1,216 @@ +/* $Id: minixml.c,v 1.9 2011/02/07 13:44:57 nanard Exp $ */ +/* minixml.c : the minimum size a xml parser can be ! */ +/* Project : miniupnp + * webpage: http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author : Thomas Bernard + +Copyright (c) 2005-2011, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ +#include <string.h> +#include "minixml.h" + +/* parseatt : used to parse the argument list + * return 0 (false) in case of success and -1 (true) if the end + * of the xmlbuffer is reached. */ +static int parseatt(struct xmlparser * p) +{ + const char * attname; + int attnamelen; + const char * attvalue; + int attvaluelen; + while(p->xml < p->xmlend) + { + if(*p->xml=='/' || *p->xml=='>') + return 0; + if( !IS_WHITE_SPACE(*p->xml) ) + { + char sep; + attname = p->xml; + attnamelen = 0; + while(*p->xml!='=' && !IS_WHITE_SPACE(*p->xml) ) + { + attnamelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + while(*(p->xml++) != '=') + { + if(p->xml >= p->xmlend) + return -1; + } + while(IS_WHITE_SPACE(*p->xml)) + { + p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + sep = *p->xml; + if(sep=='\'' || sep=='\"') + { + p->xml++; + if(p->xml >= p->xmlend) + return -1; + attvalue = p->xml; + attvaluelen = 0; + while(*p->xml != sep) + { + attvaluelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + } + else + { + attvalue = p->xml; + attvaluelen = 0; + while( !IS_WHITE_SPACE(*p->xml) + && *p->xml != '>' && *p->xml != '/') + { + attvaluelen++; p->xml++; + if(p->xml >= p->xmlend) + return -1; + } + } + /*printf("%.*s='%.*s'\n", + attnamelen, attname, attvaluelen, attvalue);*/ + if(p->attfunc) + p->attfunc(p->data, attname, attnamelen, attvalue, attvaluelen); + } + p->xml++; + } + return -1; +} + +/* parseelt parse the xml stream and + * call the callback functions when needed... */ +static void parseelt(struct xmlparser * p) +{ + int i; + const char * elementname; + while(p->xml < (p->xmlend - 1)) + { + if((p->xml)[0]=='<' && (p->xml)[1]!='?') + { + i = 0; elementname = ++p->xml; + while( !IS_WHITE_SPACE(*p->xml) + && (*p->xml!='>') && (*p->xml!='/') + ) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + /* to ignore namespace : */ + if(*p->xml==':') + { + i = 0; + elementname = ++p->xml; + } + } + if(i>0) + { + if(p->starteltfunc) + p->starteltfunc(p->data, elementname, i); + if(parseatt(p)) + return; + if(*p->xml!='/') + { + const char * data; + i = 0; data = ++p->xml; + if (p->xml >= p->xmlend) + return; + while( IS_WHITE_SPACE(*p->xml) ) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + } + if(memcmp(p->xml, "<![CDATA[", 9) == 0) + { + /* CDATA handling */ + p->xml += 9; + data = p->xml; + i = 0; + while(memcmp(p->xml, "]]>", 3) != 0) + { + i++; p->xml++; + if ((p->xml + 3) >= p->xmlend) + return; + } + if(i>0 && p->datafunc) + p->datafunc(p->data, data, i); + while(*p->xml!='<') + { + p->xml++; + if (p->xml >= p->xmlend) + return; + } + } + else + { + while(*p->xml!='<') + { + i++; p->xml++; + if ((p->xml + 1) >= p->xmlend) + return; + } + if(i>0 && p->datafunc && *(p->xml + 1) == '/') + p->datafunc(p->data, data, i); + } + } + } + else if(*p->xml == '/') + { + i = 0; elementname = ++p->xml; + if (p->xml >= p->xmlend) + return; + while((*p->xml != '>')) + { + i++; p->xml++; + if (p->xml >= p->xmlend) + return; + } + if(p->endeltfunc) + p->endeltfunc(p->data, elementname, i); + p->xml++; + } + } + else + { + p->xml++; + } + } +} + +/* the parser must be initialized before calling this function */ +void parsexml(struct xmlparser * parser) +{ + parser->xml = parser->xmlstart; + parser->xmlend = parser->xmlstart + parser->xmlsize; + parseelt(parser); +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h new file mode 100644 index 0000000..857c70e --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixml.h @@ -0,0 +1,37 @@ +/* $Id: minixml.h,v 1.6 2006/11/30 11:47:21 nanard Exp $ */ +/* minimal xml parser + * + * Project : miniupnp + * Website : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#ifndef __MINIXML_H__ +#define __MINIXML_H__ +#define IS_WHITE_SPACE(c) ((c==' ') || (c=='\t') || (c=='\r') || (c=='\n')) + +/* if a callback function pointer is set to NULL, + * the function is not called */ +struct xmlparser { + const char *xmlstart; + const char *xmlend; + const char *xml; /* pointer to current character */ + int xmlsize; + void * data; + void (*starteltfunc) (void *, const char *, int); + void (*endeltfunc) (void *, const char *, int); + void (*datafunc) (void *, const char *, int); + void (*attfunc) (void *, const char *, int, const char *, int); +}; + +/* parsexml() + * the xmlparser structure must be initialized before the call + * the following structure members have to be initialized : + * xmlstart, xmlsize, data, *func + * xml is for internal usage, xmlend is computed automatically */ +void parsexml(struct xmlparser *); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c new file mode 100644 index 0000000..766211b --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/minixmlvalid.c @@ -0,0 +1,156 @@ +/* $Id: minixmlvalid.c,v 1.4 2011/02/07 13:44:57 nanard Exp $ */ +/* MiniUPnP Project + * http://miniupnp.tuxfamily.org/ or http://miniupnp.free.fr/ + * minixmlvalid.c : + * validation program for the minixml parser + * + * (c) 2006-2011 Thomas Bernard */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "minixml.h" + +/* xml event structure */ +struct event { + enum { ELTSTART, ELTEND, ATT, CHARDATA } type; + const char * data; + int len; +}; + +struct eventlist { + int n; + struct event * events; +}; + +/* compare 2 xml event lists + * return 0 if the two lists are equals */ +int evtlistcmp(struct eventlist * a, struct eventlist * b) +{ + int i; + struct event * ae, * be; + if(a->n != b->n) + { + printf("event number not matching : %d != %d\n", a->n, b->n); + //return 1; + } + for(i=0; i<a->n; i++) + { + ae = a->events + i; + be = b->events + i; + if( (ae->type != be->type) + ||(ae->len != be->len) + ||memcmp(ae->data, be->data, ae->len)) + { + printf("Found a difference : %d '%.*s' != %d '%.*s'\n", + ae->type, ae->len, ae->data, + be->type, be->len, be->data); + return 1; + } + } + return 0; +} + +/* Test data */ +static const char xmldata[] = +"<xmlroot>\n" +" <elt1 att1=\"attvalue1\" att2=\"attvalue2\">" +"character data" +"</elt1> \n \t" +"<elt1b/>" +"<elt1>\n<![CDATA[ <html>stuff !\n ]]> \n</elt1>\n" +"<elt2a> \t<elt2b>chardata1</elt2b><elt2b> chardata2 </elt2b></elt2a>" +"</xmlroot>"; + +static const struct event evtref[] = +{ + {ELTSTART, "xmlroot", 7}, + {ELTSTART, "elt1", 4}, + /* attributes */ + {CHARDATA, "character data", 14}, + {ELTEND, "elt1", 4}, + {ELTSTART, "elt1b", 5}, + {ELTSTART, "elt1", 4}, + {CHARDATA, " <html>stuff !\n ", 16}, + {ELTEND, "elt1", 4}, + {ELTSTART, "elt2a", 5}, + {ELTSTART, "elt2b", 5}, + {CHARDATA, "chardata1", 9}, + {ELTEND, "elt2b", 5}, + {ELTSTART, "elt2b", 5}, + {CHARDATA, " chardata2 ", 11}, + {ELTEND, "elt2b", 5}, + {ELTEND, "elt2a", 5}, + {ELTEND, "xmlroot", 7} +}; + +void startelt(void * data, const char * p, int l) +{ + struct eventlist * evtlist = data; + struct event * evt; + evt = evtlist->events + evtlist->n; + /*printf("startelt : %.*s\n", l, p);*/ + evt->type = ELTSTART; + evt->data = p; + evt->len = l; + evtlist->n++; +} + +void endelt(void * data, const char * p, int l) +{ + struct eventlist * evtlist = data; + struct event * evt; + evt = evtlist->events + evtlist->n; + /*printf("endelt : %.*s\n", l, p);*/ + evt->type = ELTEND; + evt->data = p; + evt->len = l; + evtlist->n++; +} + +void chardata(void * data, const char * p, int l) +{ + struct eventlist * evtlist = data; + struct event * evt; + evt = evtlist->events + evtlist->n; + /*printf("chardata : '%.*s'\n", l, p);*/ + evt->type = CHARDATA; + evt->data = p; + evt->len = l; + evtlist->n++; +} + +int testxmlparser(const char * xml, int size) +{ + int r; + struct eventlist evtlist; + struct eventlist evtlistref; + struct xmlparser parser; + evtlist.n = 0; + evtlist.events = malloc(sizeof(struct event)*100); + memset(&parser, 0, sizeof(parser)); + parser.xmlstart = xml; + parser.xmlsize = size; + parser.data = &evtlist; + parser.starteltfunc = startelt; + parser.endeltfunc = endelt; + parser.datafunc = chardata; + parsexml(&parser); + printf("%d events\n", evtlist.n); + /* compare */ + evtlistref.n = sizeof(evtref)/sizeof(struct event); + evtlistref.events = (struct event *)evtref; + r = evtlistcmp(&evtlistref, &evtlist); + free(evtlist.events); + return r; +} + +int main(int argc, char * * argv) +{ + int r; + r = testxmlparser(xmldata, sizeof(xmldata)-1); + if(r) + printf("minixml validation test failed\n"); + return r; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c new file mode 100644 index 0000000..e09e80f --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.c @@ -0,0 +1,157 @@ +/* $Id: portlistingparse.c,v 1.4 2011/03/18 11:02:17 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#include <string.h> +#include <stdlib.h> +#include "portlistingparse.h" +#include "minixml.h" + +/* list of the elements */ +static const struct { + const portMappingElt code; + const char * const str; +} elements[] = { + { PortMappingEntry, "PortMappingEntry"}, + { NewRemoteHost, "NewRemoteHost"}, + { NewExternalPort, "NewExternalPort"}, + { NewProtocol, "NewProtocol"}, + { NewInternalPort, "NewInternalPort"}, + { NewInternalClient, "NewInternalClient"}, + { NewEnabled, "NewEnabled"}, + { NewDescription, "NewDescription"}, + { NewLeaseTime, "NewLeaseTime"}, + { PortMappingEltNone, NULL} +}; + +/* Helper function */ +static UNSIGNED_INTEGER +atoui(const char * p, int l) +{ + UNSIGNED_INTEGER r = 0; + while(l > 0 && *p) + { + if(*p >= '0' && *p <= '9') + r = r*10 + (*p - '0'); + else + break; + p++; + l--; + } + return r; +} + +/* Start element handler */ +static void +startelt(void * d, const char * name, int l) +{ + int i; + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pdata->curelt = PortMappingEltNone; + for(i = 0; elements[i].str; i++) + { + if(memcmp(name, elements[i].str, l) == 0) + { + pdata->curelt = elements[i].code; + break; + } + } + if(pdata->curelt == PortMappingEntry) + { + struct PortMapping * pm; + pm = calloc(1, sizeof(struct PortMapping)); + LIST_INSERT_HEAD( &(pdata->head), pm, entries); + } +} + +/* End element handler */ +static void +endelt(void * d, const char * name, int l) +{ + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pdata->curelt = PortMappingEltNone; +} + +/* Data handler */ +static void +data(void * d, const char * data, int l) +{ + struct PortMapping * pm; + struct PortMappingParserData * pdata = (struct PortMappingParserData *)d; + pm = pdata->head.lh_first; + if(!pm) + return; + if(l > 63) + l = 63; + switch(pdata->curelt) + { + case NewRemoteHost: + memcpy(pm->remoteHost, data, l); + pm->remoteHost[l] = '\0'; + break; + case NewExternalPort: + pm->externalPort = (unsigned short)atoui(data, l); + break; + case NewProtocol: + if(l > 3) + l = 3; + memcpy(pm->protocol, data, l); + pm->protocol[l] = '\0'; + break; + case NewInternalPort: + pm->internalPort = (unsigned short)atoui(data, l); + break; + case NewInternalClient: + memcpy(pm->internalClient, data, l); + pm->internalClient[l] = '\0'; + break; + case NewEnabled: + pm->enabled = (unsigned char)atoui(data, l); + break; + case NewDescription: + memcpy(pm->description, data, l); + pm->description[l] = '\0'; + break; + case NewLeaseTime: + pm->leaseTime = atoui(data, l); + break; + default: + break; + } +} + + +/* Parse the PortMappingList XML document for IGD version 2 + */ +void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata) +{ + struct xmlparser parser; + + memset(pdata, 0, sizeof(struct PortMappingParserData)); + LIST_INIT(&(pdata->head)); + /* init xmlparser */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = pdata; + parser.starteltfunc = startelt; + parser.endeltfunc = endelt; + parser.datafunc = data; + parser.attfunc = 0; + parsexml(&parser); +} + +void +FreePortListing(struct PortMappingParserData * pdata) +{ + struct PortMapping * pm; + while((pm = pdata->head.lh_first) != NULL) + { + LIST_REMOVE(pm, entries); + free(pm); + } +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h new file mode 100644 index 0000000..1852478 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/portlistingparse.h @@ -0,0 +1,71 @@ +/* $Id: portlistingparse.h,v 1.4 2011/02/15 23:03:56 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ +#ifndef __PORTLISTINGPARSE_H__ +#define __PORTLISTINGPARSE_H__ + +#include "declspec.h" +/* for the definition of UNSIGNED_INTEGER */ +#include "miniupnpctypes.h" + +#if defined(NO_SYS_QUEUE_H) || defined(WIN32) || defined(__HAIKU__) +#include "bsdqueue.h" +#else +#include <sys/queue.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* sample of PortMappingEntry : + <p:PortMappingEntry> + <p:NewRemoteHost>202.233.2.1</p:NewRemoteHost> + <p:NewExternalPort>2345</p:NewExternalPort> + <p:NewProtocol>TCP</p:NewProtocol> + <p:NewInternalPort>2345</p:NewInternalPort> + <p:NewInternalClient>192.168.1.137</p:NewInternalClient> + <p:NewEnabled>1</p:NewEnabled> + <p:NewDescription>dooom</p:NewDescription> + <p:NewLeaseTime>345</p:NewLeaseTime> + </p:PortMappingEntry> + */ +typedef enum { PortMappingEltNone, + PortMappingEntry, NewRemoteHost, + NewExternalPort, NewProtocol, + NewInternalPort, NewInternalClient, + NewEnabled, NewDescription, + NewLeaseTime } portMappingElt; + +struct PortMapping { + LIST_ENTRY(PortMapping) entries; + UNSIGNED_INTEGER leaseTime; + unsigned short externalPort; + unsigned short internalPort; + char remoteHost[64]; + char internalClient[64]; + char description[64]; + char protocol[4]; + unsigned char enabled; +}; + +struct PortMappingParserData { + LIST_HEAD(portmappinglisthead, PortMapping) head; + portMappingElt curelt; +}; + +LIBSPEC void +ParsePortListing(const char * buffer, int bufsize, + struct PortMappingParserData * pdata); + +LIBSPEC void +FreePortListing(struct PortMappingParserData * pdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c new file mode 100644 index 0000000..a1eadfc --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.c @@ -0,0 +1,81 @@ +/* $Id: receivedata.c,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include <stdio.h> +#ifdef WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#else +#include <unistd.h> +#if defined(__amigaos__) && !defined(__amigaos4__) +#define socklen_t int +#else /* #if defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/select.h> +#endif /* #else defined(__amigaos__) && !defined(__amigaos4__) */ +#include <sys/socket.h> +#if !defined(__amigaos__) && !defined(__amigaos4__) +#include <poll.h> +#endif +#include <errno.h> +#define MINIUPNPC_IGNORE_EINTR +#endif + +#ifdef WIN32 +#define PRINT_SOCKET_ERROR(x) printf("Socket error: %s, %d\n", x, WSAGetLastError()); +#else +#define PRINT_SOCKET_ERROR(x) perror(x) +#endif + +#include "receivedata.h" + +int +receivedata(int socket, char * data, int length, int timeout) +{ + int n; +#if !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) + /* using poll */ + struct pollfd fds[1]; /* for the poll */ +#ifdef MINIUPNPC_IGNORE_EINTR + do { +#endif + fds[0].fd = socket; + fds[0].events = POLLIN; + n = poll(fds, 1, timeout); +#ifdef MINIUPNPC_IGNORE_EINTR + } while(n < 0 && errno == EINTR); +#endif + if(n < 0) { + PRINT_SOCKET_ERROR("poll"); + return -1; + } else if(n == 0) { + /* timeout */ + return 0; + } +#else /* !defined(WIN32) && !defined(__amigaos__) && !defined(__amigaos4__) */ + /* using select under WIN32 and amigaos */ + fd_set socketSet; + TIMEVAL timeval; + FD_ZERO(&socketSet); + FD_SET(socket, &socketSet); + timeval.tv_sec = timeout / 1000; + timeval.tv_usec = (timeout % 1000) * 1000; + n = select(FD_SETSIZE, &socketSet, NULL, NULL, &timeval); + if(n < 0) { + PRINT_SOCKET_ERROR("select"); + return -1; + } else if(n == 0) { + return 0; + } +#endif + n = recv(socket, data, length, 0); + if(n<0) { + PRINT_SOCKET_ERROR("recv"); + } + return n; +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h new file mode 100644 index 0000000..7a551b9 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/receivedata.h @@ -0,0 +1,17 @@ +/* $Id: receivedata.h,v 1.1 2011/04/11 08:21:47 nanard Exp $ */ +/* Project: miniupnp + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * Author: Thomas Bernard + * Copyright (c) 2011 Thomas Bernard + * This software is subjects to the conditions detailed + * in the LICENCE file provided within this distribution */ +#ifndef __RECEIVEDATA_H__ +#define __RECEIVEDATA_H__ + +/* Reads data from the specified socket. + * Returns the number of bytes read if successful, zero if no bytes were + * read or if we timed out. Returns negative if there was an error. */ +int receivedata(int socket, char * data, int length, int timeout); + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c new file mode 100644 index 0000000..b136d9d --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpc.c @@ -0,0 +1,683 @@ +/* $Id: upnpc.c,v 1.88 2011/06/17 23:31:01 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#ifdef WIN32 +#include <winsock2.h> +#define snprintf _snprintf +#endif +#include "miniwget.h" +#include "miniupnpc.h" +#include "upnpcommands.h" +#include "upnperrors.h" + +/* protofix() checks if protocol is "UDP" or "TCP" + * returns NULL if not */ +const char * protofix(const char * proto) +{ + static const char proto_tcp[4] = { 'T', 'C', 'P', 0}; + static const char proto_udp[4] = { 'U', 'D', 'P', 0}; + int i, b; + for(i=0, b=1; i<4; i++) + b = b && ( (proto[i] == proto_tcp[i]) + || (proto[i] == (proto_tcp[i] | 32)) ); + if(b) + return proto_tcp; + for(i=0, b=1; i<4; i++) + b = b && ( (proto[i] == proto_udp[i]) + || (proto[i] == (proto_udp[i] | 32)) ); + if(b) + return proto_udp; + return 0; +} + +static void DisplayInfos(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + char externalIPAddress[40]; + char connectionType[64]; + char status[64]; + char lastconnerr[64]; + unsigned int uptime; + unsigned int brUp, brDown; + time_t timenow, timestarted; + int r; + UPNP_GetConnectionTypeInfo(urls->controlURL, + data->first.servicetype, + connectionType); + if(connectionType[0]) + printf("Connection Type : %s\n", connectionType); + else + printf("GetConnectionTypeInfo failed.\n"); + UPNP_GetStatusInfo(urls->controlURL, data->first.servicetype, + status, &uptime, lastconnerr); + printf("Status : %s, uptime=%us, LastConnectionError : %s\n", + status, uptime, lastconnerr); + timenow = time(NULL); + timestarted = timenow - uptime; + printf(" Time started : %s", ctime(×tarted)); + UPNP_GetLinkLayerMaxBitRates(urls->controlURL_CIF, data->CIF.servicetype, + &brDown, &brUp); + printf("MaxBitRateDown : %u bps", brDown); + if(brDown >= 1000000) { + printf(" (%u.%u Mbps)", brDown / 1000000, (brDown / 100000) % 10); + } else if(brDown >= 1000) { + printf(" (%u Kbps)", brDown / 1000); + } + printf(" MaxBitRateUp %u bps", brUp); + if(brUp >= 1000000) { + printf(" (%u.%u Mbps)", brUp / 1000000, (brUp / 100000) % 10); + } else if(brUp >= 1000) { + printf(" (%u Kbps)", brUp / 1000); + } + printf("\n"); + r = UPNP_GetExternalIPAddress(urls->controlURL, + data->first.servicetype, + externalIPAddress); + if(r != UPNPCOMMAND_SUCCESS) + printf("GetExternalIPAddress() returned %d\n", r); + if(externalIPAddress[0]) + printf("ExternalIPAddress = %s\n", externalIPAddress); + else + printf("GetExternalIPAddress failed.\n"); +} + +static void GetConnectionStatus(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + unsigned int bytessent, bytesreceived, packetsreceived, packetssent; + DisplayInfos(urls, data); + bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); + bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); + packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); + packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); + printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); + printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); +} + +static void ListRedirections(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + int r; + int i = 0; + char index[6]; + char intClient[40]; + char intPort[6]; + char extPort[6]; + char protocol[4]; + char desc[80]; + char enabled[6]; + char rHost[64]; + char duration[16]; + /*unsigned int num=0; + UPNP_GetPortMappingNumberOfEntries(urls->controlURL, data->servicetype, &num); + printf("PortMappingNumberOfEntries : %u\n", num);*/ + do { + snprintf(index, 6, "%d", i); + rHost[0] = '\0'; enabled[0] = '\0'; + duration[0] = '\0'; desc[0] = '\0'; + extPort[0] = '\0'; intPort[0] = '\0'; intClient[0] = '\0'; + r = UPNP_GetGenericPortMappingEntry(urls->controlURL, + data->first.servicetype, + index, + extPort, intClient, intPort, + protocol, desc, enabled, + rHost, duration); + if(r==0) + /* + printf("%02d - %s %s->%s:%s\tenabled=%s leaseDuration=%s\n" + " desc='%s' rHost='%s'\n", + i, protocol, extPort, intClient, intPort, + enabled, duration, + desc, rHost); + */ + printf("%2d %s %5s->%s:%-5s '%s' '%s' %s\n", + i, protocol, extPort, intClient, intPort, + desc, rHost, duration); + else + printf("GetGenericPortMappingEntry() returned %d (%s)\n", + r, strupnperror(r)); + i++; + } while(r==0); +} + +static void NewListRedirections(struct UPNPUrls * urls, + struct IGDdatas * data) +{ + int r; + int i = 0; + struct PortMappingParserData pdata; + struct PortMapping * pm; + + memset(&pdata, 0, sizeof(struct PortMappingParserData)); + r = UPNP_GetListOfPortMappings(urls->controlURL, + data->first.servicetype, + "0", + "65535", + "TCP", + "1000", + &pdata); + if(r == UPNPCOMMAND_SUCCESS) + { + for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost, + (unsigned)pm->leaseTime); + i++; + } + FreePortListing(&pdata); + } + else + { + printf("GetListOfPortMappings() returned %d (%s)\n", + r, strupnperror(r)); + } + r = UPNP_GetListOfPortMappings(urls->controlURL, + data->first.servicetype, + "0", + "65535", + "UDP", + "1000", + &pdata); + if(r == UPNPCOMMAND_SUCCESS) + { + for(pm = pdata.head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s' %u\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost, + (unsigned)pm->leaseTime); + i++; + } + FreePortListing(&pdata); + } + else + { + printf("GetListOfPortMappings() returned %d (%s)\n", + r, strupnperror(r)); + } +} + +/* Test function + * 1 - get connection type + * 2 - get extenal ip address + * 3 - Add port mapping + * 4 - get this port mapping from the IGD */ +static void SetRedirectAndTest(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * iaddr, + const char * iport, + const char * eport, + const char * proto, + const char * leaseDuration) +{ + char externalIPAddress[40]; + char intClient[40]; + char intPort[6]; + char duration[16]; + int r; + + if(!iaddr || !iport || !eport || !proto) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "invalid protocol\n"); + return; + } + + UPNP_GetExternalIPAddress(urls->controlURL, + data->first.servicetype, + externalIPAddress); + if(externalIPAddress[0]) + printf("ExternalIPAddress = %s\n", externalIPAddress); + else + printf("GetExternalIPAddress failed.\n"); + + r = UPNP_AddPortMapping(urls->controlURL, data->first.servicetype, + eport, iport, iaddr, 0, proto, 0, leaseDuration); + if(r!=UPNPCOMMAND_SUCCESS) + printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", + eport, iport, iaddr, r, strupnperror(r)); + + r = UPNP_GetSpecificPortMappingEntry(urls->controlURL, + data->first.servicetype, + eport, proto, + intClient, intPort, NULL/*desc*/, + NULL/*enabled*/, duration); + if(r!=UPNPCOMMAND_SUCCESS) + printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", + r, strupnperror(r)); + + if(intClient[0]) { + printf("InternalIP:Port = %s:%s\n", intClient, intPort); + printf("external %s:%s %s is redirected to internal %s:%s (duration=%s)\n", + externalIPAddress, eport, proto, intClient, intPort, duration); + } +} + +static void +RemoveRedirect(struct UPNPUrls * urls, + struct IGDdatas * data, + const char * eport, + const char * proto) +{ + int r; + if(!proto || !eport) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "protocol invalid\n"); + return; + } + r = UPNP_DeletePortMapping(urls->controlURL, data->first.servicetype, eport, proto, 0); + printf("UPNP_DeletePortMapping() returned : %d\n", r); +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +static void GetFirewallStatus(struct UPNPUrls * urls, struct IGDdatas * data) +{ + unsigned int bytessent, bytesreceived, packetsreceived, packetssent; + int firewallEnabled = 0, inboundPinholeAllowed = 0; + + UPNP_GetFirewallStatus(urls->controlURL_6FC, data->IPv6FC.servicetype, &firewallEnabled, &inboundPinholeAllowed); + printf("FirewallEnabled: %d & Inbound Pinhole Allowed: %d\n", firewallEnabled, inboundPinholeAllowed); + printf("GetFirewallStatus:\n Firewall Enabled: %s\n Inbound Pinhole Allowed: %s\n", (firewallEnabled)? "Yes":"No", (inboundPinholeAllowed)? "Yes":"No"); + + bytessent = UPNP_GetTotalBytesSent(urls->controlURL_CIF, data->CIF.servicetype); + bytesreceived = UPNP_GetTotalBytesReceived(urls->controlURL_CIF, data->CIF.servicetype); + packetssent = UPNP_GetTotalPacketsSent(urls->controlURL_CIF, data->CIF.servicetype); + packetsreceived = UPNP_GetTotalPacketsReceived(urls->controlURL_CIF, data->CIF.servicetype); + printf("Bytes: Sent: %8u\tRecv: %8u\n", bytessent, bytesreceived); + printf("Packets: Sent: %8u\tRecv: %8u\n", packetssent, packetsreceived); +} + +/* Test function + * 1 - Add pinhole + * 2 - Check if pinhole is working from the IGD side */ +static void SetPinholeAndTest(struct UPNPUrls * urls, struct IGDdatas * data, + const char * remoteaddr, const char * eport, + const char * intaddr, const char * iport, + const char * proto, const char * lease_time) +{ + char uniqueID[8]; + //int isWorking = 0; + int r; + + if(!intaddr || !remoteaddr || !iport || !eport || !proto || !lease_time) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + /*proto = protofix(proto); + if(!proto) + { + fprintf(stderr, "invalid protocol\n"); + return; + }*/ + r = UPNP_AddPinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, lease_time, uniqueID); + if(r!=UPNPCOMMAND_SUCCESS) + printf("AddPinhole([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", + intaddr, iport, remoteaddr, eport, r, strupnperror(r)); + else + { + printf("AddPinhole: ([%s]:%s -> [%s]:%s) / Pinhole ID = %s\n", intaddr, iport, remoteaddr, eport, uniqueID); + /*r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->servicetype_6FC, uniqueID, &isWorking); + if(r!=UPNPCOMMAND_SUCCESS) + printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); + printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No");*/ + } +} + +/* Test function + * 1 - Check if pinhole is working from the IGD side + * 2 - Update pinhole */ +static void GetPinholeAndUpdate(struct UPNPUrls * urls, struct IGDdatas * data, + const char * uniqueID, const char * lease_time) +{ + int isWorking = 0; + int r; + + if(!uniqueID || !lease_time) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); + printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); + if(r!=UPNPCOMMAND_SUCCESS) + printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); + if(isWorking || r==709) + { + r = UPNP_UpdatePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, lease_time); + printf("UpdatePinhole: Pinhole ID = %s with Lease Time: %s\n", uniqueID, lease_time); + if(r!=UPNPCOMMAND_SUCCESS) + printf("UpdatePinhole: ID (%s) failed with code %d (%s)\n", uniqueID, r, strupnperror(r)); + } +} + +/* Test function + * Get pinhole timeout + */ +static void GetPinholeOutboundTimeout(struct UPNPUrls * urls, struct IGDdatas * data, + const char * remoteaddr, const char * eport, + const char * intaddr, const char * iport, + const char * proto) +{ + int timeout = 0; + int r; + + if(!intaddr || !remoteaddr || !iport || !eport || !proto) + { + fprintf(stderr, "Wrong arguments\n"); + return; + } + + r = UPNP_GetOutboundPinholeTimeout(urls->controlURL_6FC, data->IPv6FC.servicetype, remoteaddr, eport, intaddr, iport, proto, &timeout); + if(r!=UPNPCOMMAND_SUCCESS) + printf("GetOutboundPinholeTimeout([%s]:%s -> [%s]:%s) failed with code %d (%s)\n", + intaddr, iport, remoteaddr, eport, r, strupnperror(r)); + else + printf("GetOutboundPinholeTimeout: ([%s]:%s -> [%s]:%s) / Timeout = %d\n", intaddr, iport, remoteaddr, eport, timeout); +} + +static void +GetPinholePackets(struct UPNPUrls * urls, + struct IGDdatas * data, const char * uniqueID) +{ + int r, pinholePackets = 0; + if(!uniqueID) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + r = UPNP_GetPinholePackets(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &pinholePackets); + if(r!=UPNPCOMMAND_SUCCESS) + printf("GetPinholePackets() failed with code %d (%s)\n", r, strupnperror(r)); + else + printf("GetPinholePackets: Pinhole ID = %s / PinholePackets = %d\n", uniqueID, pinholePackets); +} + +static void +CheckPinhole(struct UPNPUrls * urls, + struct IGDdatas * data, const char * uniqueID) +{ + int r, isWorking = 0; + if(!uniqueID) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + r = UPNP_CheckPinholeWorking(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID, &isWorking); + if(r!=UPNPCOMMAND_SUCCESS) + printf("CheckPinholeWorking() failed with code %d (%s)\n", r, strupnperror(r)); + else + printf("CheckPinholeWorking: Pinhole ID = %s / IsWorking = %s\n", uniqueID, (isWorking)? "Yes":"No"); +} + +static void +RemovePinhole(struct UPNPUrls * urls, + struct IGDdatas * data, const char * uniqueID) +{ + int r; + if(!uniqueID) + { + fprintf(stderr, "invalid arguments\n"); + return; + } + r = UPNP_DeletePinhole(urls->controlURL_6FC, data->IPv6FC.servicetype, uniqueID); + printf("UPNP_DeletePinhole() returned : %d\n", r); +} + + +/* sample upnp client program */ +int main(int argc, char ** argv) +{ + char command = 0; + char ** commandargv = 0; + int commandargc = 0; + struct UPNPDev * devlist = 0; + char lanaddr[64]; /* my ip address on the LAN */ + int i; + const char * rootdescurl = 0; + const char * multicastif = 0; + const char * minissdpdpath = 0; + int retcode = 0; + int error = 0; + int ipv6 = 0; + +#ifdef WIN32 + WSADATA wsaData; + int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if(nResult != NO_ERROR) + { + fprintf(stderr, "WSAStartup() failed.\n"); + return -1; + } +#endif + printf("upnpc : miniupnpc library test client. (c) 2006-2011 Thomas Bernard\n"); + printf("Go to http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/\n" + "for more information.\n"); + /* command line processing */ + for(i=1; i<argc; i++) + { + if(argv[i][0] == '-') + { + if(argv[i][1] == 'u') + rootdescurl = argv[++i]; + else if(argv[i][1] == 'm') + multicastif = argv[++i]; + else if(argv[i][1] == 'p') + minissdpdpath = argv[++i]; + else if(argv[i][1] == '6') + ipv6 = 1; + else + { + command = argv[i][1]; + i++; + commandargv = argv + i; + commandargc = argc - i; + break; + } + } + else + { + fprintf(stderr, "option '%s' invalid\n", argv[i]); + } + } + + if(!command || (command == 'a' && commandargc<4) + || (command == 'd' && argc<2) + || (command == 'r' && argc<2) + || (command == 'A' && commandargc<6) + || (command == 'U' && commandargc<2) + || (command == 'D' && commandargc<1)) + { + fprintf(stderr, "Usage :\t%s [options] -a ip port external_port protocol [duration]\n\t\tAdd port redirection\n", argv[0]); + fprintf(stderr, " \t%s [options] -d external_port protocol [port2 protocol2] [...]\n\t\tDelete port redirection\n", argv[0]); + fprintf(stderr, " \t%s [options] -s\n\t\tGet Connection status\n", argv[0]); + fprintf(stderr, " \t%s [options] -l\n\t\tList redirections\n", argv[0]); + fprintf(stderr, " \t%s [options] -L\n\t\tList redirections (using GetListOfPortMappings, IGD v2)\n", argv[0]); + fprintf(stderr, " \t%s [options] -r port1 protocol1 [port2 protocol2] [...]\n\t\tAdd all redirections to the current host\n", argv[0]); + fprintf(stderr, " \t%s [options] -A remote_ip remote_port internal_ip internal_port protocol lease_time\n\t\tAdd Pinhole (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -U uniqueID new_lease_time\n\t\tUpdate Pinhole (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -C uniqueID\n\t\tCheck if Pinhole is Working (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -K uniqueID\n\t\tGet Number of packets going through the rule (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -D uniqueID\n\t\tDelete Pinhole (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -S\n\t\tGet Firewall status (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -G remote_ip remote_port internal_ip internal_port protocol\n\t\tGet Outbound Pinhole Timeout (for IGD:2 only)\n", argv[0]); + fprintf(stderr, " \t%s [options] -P\n\t\tGet Presentation url\n", argv[0]); + fprintf(stderr, "\nprotocol is UDP or TCP\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -6 : use ip v6 instead of ip v4.\n"); + fprintf(stderr, " -u url : bypass discovery process by providing the XML root description url.\n"); + fprintf(stderr, " -m address/interface : provide ip address (ip v4) or interface name (ip v6) to use for sending SSDP multicast packets.\n"); + fprintf(stderr, " -p path : use this path for MiniSSDPd socket.\n"); + return 1; + } + + if( rootdescurl + || (devlist = upnpDiscover(2000, multicastif, minissdpdpath, + 0/*sameport*/, ipv6, &error))) + { + struct UPNPDev * device; + struct UPNPUrls urls; + struct IGDdatas data; + if(devlist) + { + printf("List of UPNP devices found on the network :\n"); + for(device = devlist; device; device = device->pNext) + { + printf(" desc: %s\n st: %s\n\n", + device->descURL, device->st); + } + } + else + { + printf("upnpDiscover() error code=%d\n", error); + } + i = 1; + if( (rootdescurl && UPNP_GetIGDFromUrl(rootdescurl, &urls, &data, lanaddr, sizeof(lanaddr))) + || (i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)))) + { + switch(i) { + case 1: + printf("Found valid IGD : %s\n", urls.controlURL); + break; + case 2: + printf("Found a (not connected?) IGD : %s\n", urls.controlURL); + printf("Trying to continue anyway\n"); + break; + case 3: + printf("UPnP device found. Is it an IGD ? : %s\n", urls.controlURL); + printf("Trying to continue anyway\n"); + break; + default: + printf("Found device (igd ?) : %s\n", urls.controlURL); + printf("Trying to continue anyway\n"); + } + printf("Local LAN ip address : %s\n", lanaddr); + #if 0 + printf("getting \"%s\"\n", urls.ipcondescURL); + descXML = miniwget(urls.ipcondescURL, &descXMLsize); + if(descXML) + { + /*fwrite(descXML, 1, descXMLsize, stdout);*/ + free(descXML); descXML = NULL; + } + #endif + + switch(command) + { + case 'l': + DisplayInfos(&urls, &data); + ListRedirections(&urls, &data); + break; + case 'L': + NewListRedirections(&urls, &data); + break; + case 'a': + SetRedirectAndTest(&urls, &data, + commandargv[0], commandargv[1], + commandargv[2], commandargv[3], + (commandargc > 4)?commandargv[4]:"0"); + break; + case 'd': + for(i=0; i<commandargc; i+=2) + { + RemoveRedirect(&urls, &data, commandargv[i], commandargv[i+1]); + } + break; + case 's': + GetConnectionStatus(&urls, &data); + break; + case 'r': + for(i=0; i<commandargc; i+=2) + { + /*printf("port %s protocol %s\n", argv[i], argv[i+1]);*/ + SetRedirectAndTest(&urls, &data, + lanaddr, commandargv[i], + commandargv[i], commandargv[i+1], "0"); + } + break; + case 'A': + SetPinholeAndTest(&urls, &data, + commandargv[0], commandargv[1], + commandargv[2], commandargv[3], + commandargv[4], commandargv[5]); + break; + case 'U': + GetPinholeAndUpdate(&urls, &data, + commandargv[0], commandargv[1]); + break; + case 'C': + for(i=0; i<commandargc; i++) + { + CheckPinhole(&urls, &data, commandargv[i]); + } + break; + case 'K': + for(i=0; i<commandargc; i++) + { + GetPinholePackets(&urls, &data, commandargv[i]); + } + break; + case 'D': + for(i=0; i<commandargc; i++) + { + RemovePinhole(&urls, &data, commandargv[i]); + } + break; + case 'S': + GetFirewallStatus(&urls, &data); + break; + case 'G': + GetPinholeOutboundTimeout(&urls, &data, + commandargv[0], commandargv[1], + commandargv[2], commandargv[3], + commandargv[4]); + break; + case 'P': + printf("Presentation URL found:\n"); + printf(" %s\n", data.presentationurl); + break; + default: + fprintf(stderr, "Unknown switch -%c\n", command); + retcode = 1; + } + + FreeUPNPUrls(&urls); + } + else + { + fprintf(stderr, "No valid UPNP Internet Gateway Device found.\n"); + retcode = 1; + } + freeUPNPDevlist(devlist); devlist = 0; + } + else + { + fprintf(stderr, "No IGD UPnP Device found on the network !\n"); + retcode = 1; + } + return retcode; +} + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c new file mode 100644 index 0000000..1114759 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.c @@ -0,0 +1,1097 @@ +/* $Id: upnpcommands.c,v 1.37 2011/06/04 15:56:23 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas Bernard + * Copyright (c) 2005-2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided in this distribution. + * */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "upnpcommands.h" +#include "miniupnpc.h" +#include "portlistingparse.h" + +static UNSIGNED_INTEGER +my_atoui(const char * s) +{ + return s ? ((UNSIGNED_INTEGER)STRTOUI(s, NULL, 0)) : 0; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalBytesSent", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalBytesSent"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalBytesReceived", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalBytesReceived"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalPacketsSent", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalPacketsSent"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* + * */ +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + unsigned int r = 0; + char * p; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetTotalPacketsReceived", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewTotalPacketsReceived"); + r = my_atoui(p); + ClearNameValueList(&pdata); + return r; +} + +/* UPNP_GetStatusInfo() call the corresponding UPNP method + * returns the current status and uptime */ +LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + char * up; + char * err; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!status && !uptime) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetStatusInfo", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + /*DisplayNameValueList(buffer, bufsize);*/ + free(buffer); buffer = NULL; + up = GetValueFromNameValueList(&pdata, "NewUptime"); + p = GetValueFromNameValueList(&pdata, "NewConnectionStatus"); + err = GetValueFromNameValueList(&pdata, "NewLastConnectionError"); + if(p && up) + ret = UPNPCOMMAND_SUCCESS; + + if(status) { + if(p){ + strncpy(status, p, 64 ); + status[63] = '\0'; + }else + status[0]= '\0'; + } + + if(uptime) { + if(up) + sscanf(up,"%u",uptime); + else + uptime = 0; + } + + if(lastconnerror) { + if(err) { + strncpy(lastconnerror, err, 64 ); + lastconnerror[63] = '\0'; + } else + lastconnerror[0] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetConnectionTypeInfo() call the corresponding UPNP method + * returns the connection type */ +LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!connectionType) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetConnectionTypeInfo", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "NewConnectionType"); + /*p = GetValueFromNameValueList(&pdata, "NewPossibleConnectionTypes");*/ + /* PossibleConnectionTypes will have several values.... */ + if(p) { + strncpy(connectionType, p, 64 ); + connectionType[63] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + connectionType[0] = '\0'; + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetLinkLayerMaxBitRate() call the corresponding UPNP method. + * Returns 2 values: Downloadlink bandwidth and Uplink bandwidth. + * One of the values can be null + * Note : GetLinkLayerMaxBitRates belongs to WANPPPConnection:1 only + * We can use the GetCommonLinkProperties from WANCommonInterfaceConfig:1 */ +LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char * controlURL, + const char * servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + char * down; + char * up; + char * p; + + if(!bitrateDown && !bitrateUp) + return UPNPCOMMAND_INVALID_ARGS; + + /* shouldn't we use GetCommonLinkProperties ? */ + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetCommonLinkProperties", 0, &bufsize))) { + /*"GetLinkLayerMaxBitRates", 0, &bufsize);*/ + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + /*down = GetValueFromNameValueList(&pdata, "NewDownstreamMaxBitRate");*/ + /*up = GetValueFromNameValueList(&pdata, "NewUpstreamMaxBitRate");*/ + down = GetValueFromNameValueList(&pdata, "NewLayer1DownstreamMaxBitRate"); + up = GetValueFromNameValueList(&pdata, "NewLayer1UpstreamMaxBitRate"); + /*GetValueFromNameValueList(&pdata, "NewWANAccessType");*/ + /*GetValueFromNameValueList(&pdata, "NewPhysicalLinkStatus");*/ + if(down && up) + ret = UPNPCOMMAND_SUCCESS; + + if(bitrateDown) { + if(down) + sscanf(down,"%u",bitrateDown); + else + *bitrateDown = 0; + } + + if(bitrateUp) { + if(up) + sscanf(up,"%u",bitrateUp); + else + *bitrateUp = 0; + } + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + */ +LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!extIpAdd || !controlURL || !servicetype) + return UPNPCOMMAND_INVALID_ARGS; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetExternalIPAddress", 0, &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + /*printf("external ip = %s\n", GetValueFromNameValueList(&pdata, "NewExternalIPAddress") );*/ + p = GetValueFromNameValueList(&pdata, "NewExternalIPAddress"); + if(p) { + strncpy(extIpAdd, p, 16 ); + extIpAdd[15] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + extIpAdd[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration) +{ + struct UPNParg * AddPortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!inPort || !inClient || !proto || !extPort) + return UPNPCOMMAND_INVALID_ARGS; + + AddPortMappingArgs = calloc(9, sizeof(struct UPNParg)); + AddPortMappingArgs[0].elt = "NewRemoteHost"; + AddPortMappingArgs[0].val = remoteHost; + AddPortMappingArgs[1].elt = "NewExternalPort"; + AddPortMappingArgs[1].val = extPort; + AddPortMappingArgs[2].elt = "NewProtocol"; + AddPortMappingArgs[2].val = proto; + AddPortMappingArgs[3].elt = "NewInternalPort"; + AddPortMappingArgs[3].val = inPort; + AddPortMappingArgs[4].elt = "NewInternalClient"; + AddPortMappingArgs[4].val = inClient; + AddPortMappingArgs[5].elt = "NewEnabled"; + AddPortMappingArgs[5].val = "1"; + AddPortMappingArgs[6].elt = "NewPortMappingDescription"; + AddPortMappingArgs[6].val = desc?desc:"libminiupnpc"; + AddPortMappingArgs[7].elt = "NewLeaseDuration"; + AddPortMappingArgs[7].val = leaseDuration?leaseDuration:"0"; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPortMapping", AddPortMappingArgs, + &bufsize))) { + free(AddPortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + /*buffer[bufsize] = '\0';*/ + /*puts(buffer);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(AddPortMappingArgs); + return ret; +} + +LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost) +{ + /*struct NameValueParserData pdata;*/ + struct UPNParg * DeletePortMappingArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!extPort || !proto) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePortMappingArgs = calloc(4, sizeof(struct UPNParg)); + DeletePortMappingArgs[0].elt = "NewRemoteHost"; + DeletePortMappingArgs[0].val = remoteHost; + DeletePortMappingArgs[1].elt = "NewExternalPort"; + DeletePortMappingArgs[1].val = extPort; + DeletePortMappingArgs[2].elt = "NewProtocol"; + DeletePortMappingArgs[2].val = proto; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePortMapping", + DeletePortMappingArgs, &bufsize))) { + free(DeletePortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } else { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(DeletePortMappingArgs); + return ret; +} + +LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPortMappingArgs; + char * buffer; + int bufsize; + char * p; + int r = UPNPCOMMAND_UNKNOWN_ERROR; + if(!index) + return UPNPCOMMAND_INVALID_ARGS; + intClient[0] = '\0'; + intPort[0] = '\0'; + GetPortMappingArgs = calloc(2, sizeof(struct UPNParg)); + GetPortMappingArgs[0].elt = "NewPortMappingIndex"; + GetPortMappingArgs[0].val = index; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetGenericPortMappingEntry", + GetPortMappingArgs, &bufsize))) { + free(GetPortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewRemoteHost"); + if(p && rHost) + { + strncpy(rHost, p, 64); + rHost[63] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewExternalPort"); + if(p && extPort) + { + strncpy(extPort, p, 6); + extPort[5] = '\0'; + r = UPNPCOMMAND_SUCCESS; + } + p = GetValueFromNameValueList(&pdata, "NewProtocol"); + if(p && protocol) + { + strncpy(protocol, p, 4); + protocol[3] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewInternalClient"); + if(p && intClient) + { + strncpy(intClient, p, 16); + intClient[15] = '\0'; + r = 0; + } + p = GetValueFromNameValueList(&pdata, "NewInternalPort"); + if(p && intPort) + { + strncpy(intPort, p, 6); + intPort[5] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewEnabled"); + if(p && enabled) + { + strncpy(enabled, p, 4); + enabled[3] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); + if(p && desc) + { + strncpy(desc, p, 80); + desc[79] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); + if(p && duration) + { + strncpy(duration, p, 16); + duration[15] = '\0'; + } + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + r = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &r); + } + ClearNameValueList(&pdata); + free(GetPortMappingArgs); + return r; +} + +LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char * controlURL, + const char * servicetype, + unsigned int * numEntries) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char* p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetPortMappingNumberOfEntries", 0, + &bufsize))) { + return UPNPCOMMAND_HTTP_ERROR; + } +#ifdef DEBUG + DisplayNameValueList(buffer, bufsize); +#endif + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewPortMappingNumberOfEntries"); + if(numEntries && p) { + *numEntries = 0; + sscanf(p, "%u", numEntries); + ret = UPNPCOMMAND_SUCCESS; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + return ret; +} + +/* UPNP_GetSpecificPortMappingEntry retrieves an existing port mapping + * the result is returned in the intClient and intPort strings + * please provide 16 and 6 bytes of data */ +LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPortMappingArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!intPort || !intClient || !extPort || !proto) + return UPNPCOMMAND_INVALID_ARGS; + + GetPortMappingArgs = calloc(4, sizeof(struct UPNParg)); + GetPortMappingArgs[0].elt = "NewRemoteHost"; + /* TODO : add remote host ? */ + GetPortMappingArgs[1].elt = "NewExternalPort"; + GetPortMappingArgs[1].val = extPort; + GetPortMappingArgs[2].elt = "NewProtocol"; + GetPortMappingArgs[2].val = proto; + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetSpecificPortMappingEntry", + GetPortMappingArgs, &bufsize))) { + free(GetPortMappingArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "NewInternalClient"); + if(p) { + strncpy(intClient, p, 16); + intClient[15] = '\0'; + ret = UPNPCOMMAND_SUCCESS; + } else + intClient[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "NewInternalPort"); + if(p) { + strncpy(intPort, p, 6); + intPort[5] = '\0'; + } else + intPort[0] = '\0'; + + p = GetValueFromNameValueList(&pdata, "NewEnabled"); + if(p && enabled) { + strncpy(enabled, p, 4); + enabled[3] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "NewPortMappingDescription"); + if(p && desc) { + strncpy(desc, p, 80); + desc[79] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "NewLeaseDuration"); + if(p && leaseDuration) + { + strncpy(leaseDuration, p, 16); + leaseDuration[15] = '\0'; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + free(GetPortMappingArgs); + return ret; +} + +/* UPNP_GetListOfPortMappings() + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data) +{ + struct NameValueParserData pdata; + struct UPNParg * GetListOfPortMappingsArgs; + const char * p; + char * buffer; + int bufsize; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!startPort || !endPort || !protocol) + return UPNPCOMMAND_INVALID_ARGS; + + GetListOfPortMappingsArgs = calloc(6, sizeof(struct UPNParg)); + GetListOfPortMappingsArgs[0].elt = "NewStartPort"; + GetListOfPortMappingsArgs[0].val = startPort; + GetListOfPortMappingsArgs[1].elt = "NewEndPort"; + GetListOfPortMappingsArgs[1].val = endPort; + GetListOfPortMappingsArgs[2].elt = "NewProtocol"; + GetListOfPortMappingsArgs[2].val = protocol; + GetListOfPortMappingsArgs[3].elt = "NewManage"; + GetListOfPortMappingsArgs[3].val = "1"; + GetListOfPortMappingsArgs[4].elt = "NewNumberOfPorts"; + GetListOfPortMappingsArgs[4].val = numberOfPorts?numberOfPorts:"1000"; + + if(!(buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetListOfPortMappings", + GetListOfPortMappingsArgs, &bufsize))) { + free(GetListOfPortMappingsArgs); + return UPNPCOMMAND_HTTP_ERROR; + } + free(GetListOfPortMappingsArgs); + + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + /*p = GetValueFromNameValueList(&pdata, "NewPortListing");*/ + /*if(p) { + printf("NewPortListing : %s\n", p); + }*/ + /*printf("NewPortListing(%d chars) : %s\n", + pdata.portListingLength, pdata.portListing);*/ + if(pdata.portListing) + { + /*struct PortMapping * pm; + int i = 0;*/ + ParsePortListing(pdata.portListing, pdata.portListingLength, + data); + ret = UPNPCOMMAND_SUCCESS; + /* + for(pm = data->head.lh_first; pm != NULL; pm = pm->entries.le_next) + { + printf("%2d %s %5hu->%s:%-5hu '%s' '%s'\n", + i, pm->protocol, pm->externalPort, pm->internalClient, + pm->internalPort, + pm->description, pm->remoteHost); + i++; + } + */ + /*FreePortListing(&data);*/ + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + + //printf("%.*s", bufsize, buffer); + + return ret; +} + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed) +{ + struct NameValueParserData pdata; + char * buffer; + int bufsize; + char * fe, *ipa, *p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!firewallEnabled && !inboundPinholeAllowed) + return UPNPCOMMAND_INVALID_ARGS; + + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetFirewallStatus", 0, &bufsize); + if(!buffer) { + return UPNPCOMMAND_HTTP_ERROR; + } + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + fe = GetValueFromNameValueList(&pdata, "FirewallEnabled"); + ipa = GetValueFromNameValueList(&pdata, "InboundPinholeAllowed"); + if(ipa && fe) + ret = UPNPCOMMAND_SUCCESS; + if(fe) + *firewallEnabled = my_atoui(fe); + /*else + *firewallEnabled = 0;*/ + if(ipa) + *inboundPinholeAllowed = my_atoui(ipa); + /*else + *inboundPinholeAllowed = 0;*/ + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + ClearNameValueList(&pdata); + return ret; +} + +LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout) +{ + struct UPNParg * GetOutboundPinholeTimeoutArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + char * p; + int ret; + + if(!intPort || !intClient || !proto || !remotePort || !remoteHost) + return UPNPCOMMAND_INVALID_ARGS; + + GetOutboundPinholeTimeoutArgs = calloc(6, sizeof(struct UPNParg)); + GetOutboundPinholeTimeoutArgs[0].elt = "RemoteHost"; + GetOutboundPinholeTimeoutArgs[0].val = remoteHost; + GetOutboundPinholeTimeoutArgs[1].elt = "RemotePort"; + GetOutboundPinholeTimeoutArgs[1].val = remotePort; + GetOutboundPinholeTimeoutArgs[2].elt = "Protocol"; + GetOutboundPinholeTimeoutArgs[2].val = proto; + GetOutboundPinholeTimeoutArgs[3].elt = "InternalPort"; + GetOutboundPinholeTimeoutArgs[3].val = intPort; + GetOutboundPinholeTimeoutArgs[4].elt = "InternalClient"; + GetOutboundPinholeTimeoutArgs[4].val = intClient; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetOutboundPinholeTimeout", GetOutboundPinholeTimeoutArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + p = GetValueFromNameValueList(&pdata, "OutboundPinholeTimeout"); + if(p) + *opTimeout = my_atoui(p); + } + ClearNameValueList(&pdata); + free(GetOutboundPinholeTimeoutArgs); + return ret; +} + +LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID) +{ + struct UPNParg * AddPinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + char * p; + int ret; + + if(!intPort || !intClient || !proto || !remoteHost || !remotePort || !leaseTime) + return UPNPCOMMAND_INVALID_ARGS; + + AddPinholeArgs = calloc(7, sizeof(struct UPNParg)); + // RemoteHost can be wilcarded + if(strncmp(remoteHost, "empty", 5)==0) + { + AddPinholeArgs[0].elt = "RemoteHost"; + AddPinholeArgs[0].val = ""; + } + else + { + AddPinholeArgs[0].elt = "RemoteHost"; + AddPinholeArgs[0].val = remoteHost; + } + AddPinholeArgs[1].elt = "RemotePort"; + AddPinholeArgs[1].val = remotePort; + AddPinholeArgs[2].elt = "Protocol"; + AddPinholeArgs[2].val = proto; + AddPinholeArgs[3].elt = "InternalPort"; + AddPinholeArgs[3].val = intPort; + if(strncmp(intClient, "empty", 5)==0) + { + AddPinholeArgs[4].elt = "InternalClient"; + AddPinholeArgs[4].val = ""; + } + else + { + AddPinholeArgs[4].elt = "InternalClient"; + AddPinholeArgs[4].val = intClient; + } + AddPinholeArgs[5].elt = "LeaseTime"; + AddPinholeArgs[5].val = leaseTime; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "AddPinhole", AddPinholeArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + p = GetValueFromNameValueList(&pdata, "UniqueID"); + if(p) + { + strncpy(uniqueID, p, 8); + uniqueID[7] = '\0'; + } + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + //printf("AddPortMapping errorCode = '%s'\n", resVal); + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(AddPinholeArgs); + return ret; +} + +LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime) +{ + struct UPNParg * UpdatePinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!uniqueID || !leaseTime) + return UPNPCOMMAND_INVALID_ARGS; + + UpdatePinholeArgs = calloc(3, sizeof(struct UPNParg)); + UpdatePinholeArgs[0].elt = "UniqueID"; + UpdatePinholeArgs[0].val = uniqueID; + UpdatePinholeArgs[1].elt = "NewLeaseTime"; + UpdatePinholeArgs[1].val = leaseTime; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "UpdatePinhole", UpdatePinholeArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + /*printf("AddPortMapping errorCode = '%s'\n", resVal); */ + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(UpdatePinholeArgs); + return ret; +} + +LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID) +{ + /*struct NameValueParserData pdata;*/ + struct UPNParg * DeletePinholeArgs; + char * buffer; + int bufsize; + struct NameValueParserData pdata; + const char * resVal; + int ret; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + DeletePinholeArgs = calloc(2, sizeof(struct UPNParg)); + DeletePinholeArgs[0].elt = "UniqueID"; + DeletePinholeArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "DeletePinhole", DeletePinholeArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + /*DisplayNameValueList(buffer, bufsize);*/ + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + resVal = GetValueFromNameValueList(&pdata, "errorCode"); + if(resVal) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(resVal, "%d", &ret); + } + else + { + ret = UPNPCOMMAND_SUCCESS; + } + ClearNameValueList(&pdata); + free(DeletePinholeArgs); + return ret; +} + +LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking) +{ + struct NameValueParserData pdata; + struct UPNParg * CheckPinholeWorkingArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + CheckPinholeWorkingArgs = calloc(4, sizeof(struct UPNParg)); + CheckPinholeWorkingArgs[0].elt = "UniqueID"; + CheckPinholeWorkingArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "CheckPinholeWorking", CheckPinholeWorkingArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "IsWorking"); + if(p) + { + *isWorking=my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; + } + else + *isWorking = 0; + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + free(CheckPinholeWorkingArgs); + return ret; +} + +LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets) +{ + struct NameValueParserData pdata; + struct UPNParg * GetPinholePacketsArgs; + char * buffer; + int bufsize; + char * p; + int ret = UPNPCOMMAND_UNKNOWN_ERROR; + + if(!uniqueID) + return UPNPCOMMAND_INVALID_ARGS; + + GetPinholePacketsArgs = calloc(4, sizeof(struct UPNParg)); + GetPinholePacketsArgs[0].elt = "UniqueID"; + GetPinholePacketsArgs[0].val = uniqueID; + buffer = simpleUPnPcommand(-1, controlURL, servicetype, + "GetPinholePackets", GetPinholePacketsArgs, &bufsize); + if(!buffer) + return UPNPCOMMAND_HTTP_ERROR; + ParseNameValue(buffer, bufsize, &pdata); + free(buffer); buffer = NULL; + + p = GetValueFromNameValueList(&pdata, "PinholePackets"); + if(p) + { + *packets=my_atoui(p); + ret = UPNPCOMMAND_SUCCESS; + } + + p = GetValueFromNameValueList(&pdata, "errorCode"); + if(p) + { + ret = UPNPCOMMAND_UNKNOWN_ERROR; + sscanf(p, "%d", &ret); + } + + ClearNameValueList(&pdata); + free(GetPinholePacketsArgs); + return ret; +} + + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h new file mode 100644 index 0000000..66d95e0 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpcommands.h @@ -0,0 +1,271 @@ +/* $Id: upnpcommands.h,v 1.23 2011/04/11 09:14:00 nanard Exp $ */ +/* Miniupnp project : http://miniupnp.free.fr/ + * Author : Thomas Bernard + * Copyright (c) 2005-2011 Thomas Bernard + * This software is subject to the conditions detailed in the + * LICENCE file provided within this distribution */ +#ifndef __UPNPCOMMANDS_H__ +#define __UPNPCOMMANDS_H__ + +#include "upnpreplyparse.h" +#include "portlistingparse.h" +#include "declspec.h" +#include "miniupnpctypes.h" + +/* MiniUPnPc return codes : */ +#define UPNPCOMMAND_SUCCESS (0) +#define UPNPCOMMAND_UNKNOWN_ERROR (-1) +#define UPNPCOMMAND_INVALID_ARGS (-2) +#define UPNPCOMMAND_HTTP_ERROR (-3) + +#ifdef __cplusplus +extern "C" { +#endif + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesSent(const char * controlURL, + const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalBytesReceived(const char * controlURL, + const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsSent(const char * controlURL, + const char * servicetype); + +LIBSPEC UNSIGNED_INTEGER +UPNP_GetTotalPacketsReceived(const char * controlURL, + const char * servicetype); + +/* UPNP_GetStatusInfo() + * status and lastconnerror are 64 byte buffers + * Return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +LIBSPEC int +UPNP_GetStatusInfo(const char * controlURL, + const char * servicetype, + char * status, + unsigned int * uptime, + char * lastconnerror); + +/* UPNP_GetConnectionTypeInfo() + * argument connectionType is a 64 character buffer + * Return Values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error code */ +LIBSPEC int +UPNP_GetConnectionTypeInfo(const char * controlURL, + const char * servicetype, + char * connectionType); + +/* UPNP_GetExternalIPAddress() call the corresponding UPNP method. + * if the third arg is not null the value is copied to it. + * at least 16 bytes must be available + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR Either an UPnP error code or an unknown error. + * + * possible UPnP Errors : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. */ +LIBSPEC int +UPNP_GetExternalIPAddress(const char * controlURL, + const char * servicetype, + char * extIpAdd); + +/* UPNP_GetLinkLayerMaxBitRates() + * call WANCommonInterfaceConfig:1#GetCommonLinkProperties + * + * return values : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +LIBSPEC int +UPNP_GetLinkLayerMaxBitRates(const char* controlURL, + const char* servicetype, + unsigned int * bitrateDown, + unsigned int * bitrateUp); + +/* UPNP_AddPortMapping() + * if desc is NULL, it will be defaulted to "libminiupnpc" + * remoteHost is usually NULL because IGD don't support it. + * + * Return values : + * 0 : SUCCESS + * NON ZERO : ERROR. Either an UPnP error code or an unknown error. + * + * List of possible UPnP errors for AddPortMapping : + * errorCode errorDescription (short) - Description (long) + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 501 Action Failed - See UPnP Device Architecture section on Control. + * 715 WildCardNotPermittedInSrcIP - The source IP address cannot be + * wild-carded + * 716 WildCardNotPermittedInExtPort - The external port cannot be wild-carded + * 718 ConflictInMappingEntry - The port mapping entry specified conflicts + * with a mapping assigned previously to another client + * 724 SamePortValuesRequired - Internal and External port values + * must be the same + * 725 OnlyPermanentLeasesSupported - The NAT implementation only supports + * permanent lease times on port mappings + * 726 RemoteHostOnlySupportsWildcard - RemoteHost must be a wildcard + * and cannot be a specific IP address or DNS name + * 727 ExternalPortOnlySupportsWildcard - ExternalPort must be a wildcard and + * cannot be a specific port value */ +LIBSPEC int +UPNP_AddPortMapping(const char * controlURL, const char * servicetype, + const char * extPort, + const char * inPort, + const char * inClient, + const char * desc, + const char * proto, + const char * remoteHost, + const char * leaseDuration); + +/* UPNP_DeletePortMapping() + * Use same argument values as what was used for AddPortMapping(). + * remoteHost is usually NULL because IGD don't support it. + * Return Values : + * 0 : SUCCESS + * NON ZERO : error. Either an UPnP error code or an undefined error. + * + * List of possible UPnP errors for DeletePortMapping : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 714 NoSuchEntryInArray - The specified value does not exist in the array */ +LIBSPEC int +UPNP_DeletePortMapping(const char * controlURL, const char * servicetype, + const char * extPort, const char * proto, + const char * remoteHost); + +/* UPNP_GetPortMappingNumberOfEntries() + * not supported by all routers */ +LIBSPEC int +UPNP_GetPortMappingNumberOfEntries(const char* controlURL, + const char* servicetype, + unsigned int * num); + +/* UPNP_GetSpecificPortMappingEntry() + * retrieves an existing port mapping + * params : + * in extPort + * in proto + * out intClient (16 bytes) + * out intPort (6 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out leaseDuration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. */ +LIBSPEC int +UPNP_GetSpecificPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * extPort, + const char * proto, + char * intClient, + char * intPort, + char * desc, + char * enabled, + char * leaseDuration); + +/* UPNP_GetGenericPortMappingEntry() + * params : + * in index + * out extPort (6 bytes) + * out intClient (16 bytes) + * out intPort (6 bytes) + * out protocol (4 bytes) + * out desc (80 bytes) + * out enabled (4 bytes) + * out rHost (64 bytes) + * out duration (16 bytes) + * + * return value : + * UPNPCOMMAND_SUCCESS, UPNPCOMMAND_INVALID_ARGS, UPNPCOMMAND_UNKNOWN_ERROR + * or a UPnP Error Code. + * + * Possible UPNP Error codes : + * 402 Invalid Args - See UPnP Device Architecture section on Control. + * 713 SpecifiedArrayIndexInvalid - The specified array index is out of bounds + */ +LIBSPEC int +UPNP_GetGenericPortMappingEntry(const char * controlURL, + const char * servicetype, + const char * index, + char * extPort, + char * intClient, + char * intPort, + char * protocol, + char * desc, + char * enabled, + char * rHost, + char * duration); + +/* UPNP_GetListOfPortMappings() Available in IGD v2 + * + * + * Possible UPNP Error codes : + * 606 Action not Authorized + * 730 PortMappingNotFound - no port mapping is found in the specified range. + * 733 InconsistantParameters - NewStartPort and NewEndPort values are not + * consistent. + */ +LIBSPEC int +UPNP_GetListOfPortMappings(const char * controlURL, + const char * servicetype, + const char * startPort, + const char * endPort, + const char * protocol, + const char * numberOfPorts, + struct PortMappingParserData * data); + +/* IGD:2, functions for service WANIPv6FirewallControl:1 */ +LIBSPEC int +UPNP_GetFirewallStatus(const char * controlURL, + const char * servicetype, + int * firewallEnabled, + int * inboundPinholeAllowed); + +LIBSPEC int +UPNP_GetOutboundPinholeTimeout(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + int * opTimeout); + +LIBSPEC int +UPNP_AddPinhole(const char * controlURL, const char * servicetype, + const char * remoteHost, + const char * remotePort, + const char * intClient, + const char * intPort, + const char * proto, + const char * leaseTime, + char * uniqueID); + +LIBSPEC int +UPNP_UpdatePinhole(const char * controlURL, const char * servicetype, + const char * uniqueID, + const char * leaseTime); + +LIBSPEC int +UPNP_DeletePinhole(const char * controlURL, const char * servicetype, const char * uniqueID); + +LIBSPEC int +UPNP_CheckPinholeWorking(const char * controlURL, const char * servicetype, + const char * uniqueID, int * isWorking); + +LIBSPEC int +UPNP_GetPinholePackets(const char * controlURL, const char * servicetype, + const char * uniqueID, int * packets); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c new file mode 100644 index 0000000..a48ae10 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.c @@ -0,0 +1,103 @@ +/* $Id: upnperrors.c,v 1.5 2011/04/10 11:19:36 nanard Exp $ */ +/* Project : miniupnp + * Author : Thomas BERNARD + * copyright (c) 2007 Thomas Bernard + * All Right reserved. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#include <string.h> +#include "upnperrors.h" +#include "upnpcommands.h" +#include "miniupnpc.h" + +const char * strupnperror(int err) +{ + const char * s = NULL; + switch(err) { + case UPNPCOMMAND_SUCCESS: + s = "Success"; + break; + case UPNPCOMMAND_UNKNOWN_ERROR: + s = "Miniupnpc Unknown Error"; + break; + case UPNPCOMMAND_INVALID_ARGS: + s = "Miniupnpc Invalid Arguments"; + break; + case UPNPDISCOVER_SOCKET_ERROR: + s = "Miniupnpc Socket error"; + break; + case UPNPDISCOVER_MEMORY_ERROR: + s = "Miniupnpc Memory allocation error"; + break; + case 401: + s = "Invalid Action"; + break; + case 402: + s = "Invalid Args"; + break; + case 501: + s = "Action Failed"; + break; + case 606: + s = "Action not authorized"; + break; + case 701: + s = "PinholeSpaceExhausted"; + break; + case 702: + s = "FirewallDisabled"; + break; + case 703: + s = "InboundPinholeNotAllowed"; + break; + case 704: + s = "NoSuchEntry"; + break; + case 705: + s = "ProtocolNotSupported"; + break; + case 706: + s = "InternalPortWildcardingNotAllowed"; + break; + case 707: + s = "ProtocolWildcardingNotAllowed"; + break; + case 708: + s = "WildcardNotPermittedInSrcIP"; + break; + case 709: + s = "NoPacketSent"; + break; + case 713: + s = "SpecifiedArrayIndexInvalid"; + break; + case 714: + s = "NoSuchEntryInArray"; + break; + case 715: + s = "WildCardNotPermittedInSrcIP"; + break; + case 716: + s = "WildCardNotPermittedInExtPort"; + break; + case 718: + s = "ConflictInMappingEntry"; + break; + case 724: + s = "SamePortValuesRequired"; + break; + case 725: + s = "OnlyPermanentLeasesSupported"; + break; + case 726: + s = "RemoteHostOnlySupportsWildcard"; + break; + case 727: + s = "ExternalPortOnlySupportsWildcard"; + break; + default: + s = NULL; + } + return s; +} diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h new file mode 100644 index 0000000..2c544c9 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnperrors.h @@ -0,0 +1,26 @@ +/* $Id: upnperrors.h,v 1.2 2008/07/02 23:31:15 nanard Exp $ */ +/* (c) 2007 Thomas Bernard + * All rights reserved. + * MiniUPnP Project. + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * This software is subjet to the conditions detailed in the + * provided LICENCE file. */ +#ifndef __UPNPERRORS_H__ +#define __UPNPERRORS_H__ + +#include "declspec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* strupnperror() + * Return a string description of the UPnP error code + * or NULL for undefinded errors */ +LIBSPEC const char * strupnperror(int err); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c new file mode 100644 index 0000000..482030b --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.c @@ -0,0 +1,152 @@ +/* $Id: upnpreplyparse.c,v 1.11 2011/02/07 16:17:06 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2011 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "upnpreplyparse.h" +#include "minixml.h" + +static void +NameValueParserStartElt(void * d, const char * name, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + if(l>63) + l = 63; + memcpy(data->curelt, name, l); + data->curelt[l] = '\0'; +} + +static void +NameValueParserGetData(void * d, const char * datas, int l) +{ + struct NameValueParserData * data = (struct NameValueParserData *)d; + struct NameValue * nv; + if(strcmp(data->curelt, "NewPortListing") == 0) + { + /* specific case for NewPortListing which is a XML Document */ + data->portListing = malloc(l + 1); + if(!data->portListing) + { + /* malloc error */ + return; + } + memcpy(data->portListing, datas, l); + data->portListing[l] = '\0'; + data->portListingLength = l; + } + else + { + /* standard case. Limited to 63 chars strings */ + nv = malloc(sizeof(struct NameValue)); + if(l>63) + l = 63; + strncpy(nv->name, data->curelt, 64); + nv->name[63] = '\0'; + memcpy(nv->value, datas, l); + nv->value[l] = '\0'; + LIST_INSERT_HEAD( &(data->head), nv, entries); + } +} + +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data) +{ + struct xmlparser parser; + LIST_INIT(&(data->head)); + data->portListing = NULL; + data->portListingLength = 0; + /* init xmlparser object */ + parser.xmlstart = buffer; + parser.xmlsize = bufsize; + parser.data = data; + parser.starteltfunc = NameValueParserStartElt; + parser.endeltfunc = 0; + parser.datafunc = NameValueParserGetData; + parser.attfunc = 0; + parsexml(&parser); +} + +void +ClearNameValueList(struct NameValueParserData * pdata) +{ + struct NameValue * nv; + if(pdata->portListing) + { + free(pdata->portListing); + pdata->portListing = NULL; + pdata->portListingLength = 0; + } + while((nv = pdata->head.lh_first) != NULL) + { + LIST_REMOVE(nv, entries); + free(nv); + } +} + +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name) +{ + struct NameValue * nv; + char * p = NULL; + for(nv = pdata->head.lh_first; + (nv != NULL) && (p == NULL); + nv = nv->entries.le_next) + { + if(strcmp(nv->name, Name) == 0) + p = nv->value; + } + return p; +} + +#if 0 +/* useless now that minixml ignores namespaces by itself */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name) +{ + struct NameValue * nv; + char * p = NULL; + char * pname; + for(nv = pdata->head.lh_first; + (nv != NULL) && (p == NULL); + nv = nv->entries.le_next) + { + pname = strrchr(nv->name, ':'); + if(pname) + pname++; + else + pname = nv->name; + if(strcmp(pname, Name)==0) + p = nv->value; + } + return p; +} +#endif + +/* debug all-in-one function + * do parsing then display to stdout */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize) +{ + struct NameValueParserData pdata; + struct NameValue * nv; + ParseNameValue(buffer, bufsize, &pdata); + for(nv = pdata.head.lh_first; + nv != NULL; + nv = nv->entries.le_next) + { + printf("%s = %s\n", nv->name, nv->value); + } + ClearNameValueList(&pdata); +} +#endif + diff --git a/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h new file mode 100644 index 0000000..267ea87 --- /dev/null +++ b/3rdParty/LibMiniUPnPc/src/miniupnpc/upnpreplyparse.h @@ -0,0 +1,64 @@ +/* $Id: upnpreplyparse.h,v 1.11 2011/02/07 16:17:06 nanard Exp $ */ +/* MiniUPnP project + * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ + * (c) 2006-2011 Thomas Bernard + * This software is subject to the conditions detailed + * in the LICENCE file provided within the distribution */ + +#ifndef __UPNPREPLYPARSE_H__ +#define __UPNPREPLYPARSE_H__ + +#if defined(NO_SYS_QUEUE_H) || defined(WIN32) || defined(__HAIKU__) +#include "bsdqueue.h" +#else +#include <sys/queue.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +struct NameValue { + LIST_ENTRY(NameValue) entries; + char name[64]; + char value[64]; +}; + +struct NameValueParserData { + LIST_HEAD(listhead, NameValue) head; + char curelt[64]; + char * portListing; + int portListingLength; +}; + +/* ParseNameValue() */ +void +ParseNameValue(const char * buffer, int bufsize, + struct NameValueParserData * data); + +/* ClearNameValueList() */ +void +ClearNameValueList(struct NameValueParserData * pdata); + +/* GetValueFromNameValueList() */ +char * +GetValueFromNameValueList(struct NameValueParserData * pdata, + const char * Name); + +/* GetValueFromNameValueListIgnoreNS() */ +char * +GetValueFromNameValueListIgnoreNS(struct NameValueParserData * pdata, + const char * Name); + +/* DisplayNameValueList() */ +#ifdef DEBUG +void +DisplayNameValueList(char * buffer, int bufsize); +#endif + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/3rdParty/LibNATPMP/SConscript b/3rdParty/LibNATPMP/SConscript new file mode 100644 index 0000000..2cf745a --- /dev/null +++ b/3rdParty/LibNATPMP/SConscript @@ -0,0 +1,51 @@ +Import(["env", "conf_env"]) + +if env.get("LIBNATPMP_BUNDLED", False) : + +################################################################################ +# Module flags +################################################################################ + + if env["SCONS_STAGE"] == "flags" : + env["LIBNATPMP_FLAGS"] = { + "CPPPATH": [Dir("src/libnatpmp")], + "LIBPATH": [Dir(".")], + "LIBS": ["Swiften_NATPMP"], + "INTERNAL_CPPDEFINES": ["STATICLIB"], + } + #if env["PLATFORM"] == "win32" : + # env["LIBIDN_FLAGS"]["CPPPATH"] += [Dir("stubs/win32")] + # if env["MSVC_VERSION"][:3] == "9.0" : + # env["LIBIDN_FLAGS"]["CPPPATH"] += [Dir("stubs/win32/VC2008")] + +################################################################################ +# Build +################################################################################ + + if env["SCONS_STAGE"] == "build" : + myenv = env.Clone() + myenv.Append(CPPPATH = ["src"]) + # Remove warn flags + myenv.Replace(CCFLAGS = [flag for flag in env["CCFLAGS"] if flag not in ["-W", "-Wall"]]) + + myenv.Append(CCFLAGS = ["-DNDEBUG", "-DSTATICLIB"]) + + #if myenv["PLATFORM"] != "win32": + # myenv.Append(CCFLAGS = ["-DMINIUPNPC_SET_SOCKET_TIMEOUT"]) + + if myenv["PLATFORM"] == "darwin": + myenv.Append(CCFLAGS = ["-DMACOSX", "-D_DARWIN_C_SOURCE"]) + + if myenv["PLATFORM"] == "win32": + myenv.Append(CCFLAGS = ["-DWIN32"]) + + src_files = [ + "src/libnatpmp/getgateway.c", + "src/libnatpmp/natpmp.c", + "src/libnatpmp/natpmpc.c", + ] + + if myenv["PLATFORM"] == "win32": + src_files += ["src/libnatpmp/wingettimeofday.c"] + + myenv.StaticLibrary("Swiften_NATPMP", src_files) diff --git a/3rdParty/LibNATPMP/src/libnatpmp/LICENSE b/3rdParty/LibNATPMP/src/libnatpmp/LICENSE new file mode 100644 index 0000000..14db2fe --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2007-2009, Thomas BERNARD +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/3rdParty/LibNATPMP/src/libnatpmp/Makefile b/3rdParty/LibNATPMP/src/libnatpmp/Makefile new file mode 100644 index 0000000..b523e53 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/Makefile @@ -0,0 +1,97 @@ +# $Id: Makefile,v 1.16 2011/01/03 17:31:03 nanard Exp $ +# This Makefile is designed for use with GNU make +# libnatpmp +# (c) 2007-2011 Thomas Bernard +# http://miniupnp.free.fr/libnatpmp.html + +OS = $(shell uname -s) +CC = gcc +INSTALL = install + +# APIVERSION is used in soname +APIVERSION = 1 +LDFLAGS = --no-undefined +CFLAGS = -O -fPIC -Wall -DENABLE_STRNATPMPERR + +LIBOBJS = natpmp.o getgateway.o + +OBJS = $(LIBOBJS) testgetgateway.o natpmpc.o + +STATICLIB = libnatpmp.a +ifeq ($(OS), Darwin) + SHAREDLIB = libnatpmp.dynlib + SONAME = $(basename $(SHAREDLIB)).$(APIVERSION).dylib + CFLAGS := -DMACOSX -D_DARWIN_C_SOURCE $(CFLAGS) +else + SHAREDLIB = libnatpmp.so + SONAME = $(SHAREDLIB).$(APIVERSION) +endif + +HEADERS = natpmp.h + +EXECUTABLES = testgetgateway natpmpc-shared natpmpc-static + +INSTALLPREFIX ?= $(PREFIX)/usr +INSTALLDIRINC = $(INSTALLPREFIX)/include +INSTALLDIRLIB = $(INSTALLPREFIX)/lib +INSTALLDIRBIN = $(INSTALLPREFIX)/bin + +.PHONY: all clean depend install cleaninstall installpythonmodule + +all: $(STATICLIB) $(SHAREDLIB) $(EXECUTABLES) + +pythonmodule: $(STATICLIB) libnatpmpmodule.c setup.py + python setup.py build + touch $@ + +installpythonmodule: pythonmodule + python setup.py install + +clean: + $(RM) $(OBJS) $(EXECUTABLES) $(STATICLIB) $(SHAREDLIB) + $(RM) pythonmodule + $(RM) -r build/ dist/ + +depend: + makedepend -f$(MAKEFILE_LIST) -Y $(OBJS:.o=.c) 2>/dev/null + +install: $(HEADERS) $(STATICLIB) $(SHAREDLIB) natpmpc-shared + $(INSTALL) -d $(INSTALLDIRINC) + $(INSTALL) -m 644 $(HEADERS) $(INSTALLDIRINC) + $(INSTALL) -d $(INSTALLDIRLIB) + $(INSTALL) -m 644 $(STATICLIB) $(INSTALLDIRLIB) + $(INSTALL) -m 644 $(SHAREDLIB) $(INSTALLDIRLIB)/$(SONAME) + $(INSTALL) -d $(INSTALLDIRBIN) + $(INSTALL) -m 755 natpmpc-shared $(INSTALLDIRBIN)/natpmpc + ln -s -f $(SONAME) $(INSTALLDIRLIB)/$(SHAREDLIB) + +cleaninstall: + $(RM) $(addprefix $(INSTALLDIRINC), $(HEADERS)) + $(RM) $(INSTALLDIRLIB)/$(SONAME) + $(RM) $(INSTALLDIRLIB)/$(SHAREDLIB) + $(RM) $(INSTALLDIRLIB)/$(STATICLIB) + +testgetgateway: testgetgateway.o getgateway.o + +natpmpc-static: natpmpc.o $(STATICLIB) + $(CC) -o $@ $^ + +natpmpc-shared: natpmpc.o $(SHAREDLIB) + $(CC) -o $@ $^ + +$(STATICLIB): $(LIBOBJS) + $(AR) crs $@ $? + +$(SHAREDLIB): $(LIBOBJS) +ifeq ($(OS), Darwin) + $(CC) -dynamiclib -Wl,-install_name,$(SONAME) -o $@ $^ +else + $(CC) -shared -Wl,-soname,$(SONAME) -o $@ $^ +endif + +# DO NOT DELETE + +natpmp.o: natpmp.h getgateway.h declspec.h +getgateway.o: getgateway.h declspec.h +testgetgateway.o: getgateway.h declspec.h +natpmpc.o: natpmp.h diff --git a/3rdParty/LibNATPMP/src/libnatpmp/declspec.h b/3rdParty/LibNATPMP/src/libnatpmp/declspec.h new file mode 100644 index 0000000..ea479d1 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/declspec.h @@ -0,0 +1,15 @@ +#ifndef __DECLSPEC_H__ +#define __DECLSPEC_H__ + +#if defined(WIN32) && !defined(STATICLIB) + #ifdef NATPMP_EXPORTS + #define LIBSPEC __declspec(dllexport) + #else + #define LIBSPEC __declspec(dllimport) + #endif +#else + #define LIBSPEC +#endif + +#endif + diff --git a/3rdParty/LibNATPMP/src/libnatpmp/getgateway.c b/3rdParty/LibNATPMP/src/libnatpmp/getgateway.c new file mode 100644 index 0000000..bcde3ad --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/getgateway.c @@ -0,0 +1,554 @@ +/* $Id: getgateway.c,v 1.19 2009/12/19 15:20:45 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007-2009, Thomas BERNARD <miniupnp@free.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <stdio.h> +#include <ctype.h> +#ifndef WIN32 +#include <netinet/in.h> +#endif +#if !defined(_MSC_VER) +#include <sys/param.h> +#endif +/* There is no portable method to get the default route gateway. + * So below are four (or five ?) differents functions implementing this. + * Parsing /proc/net/route is for linux. + * sysctl is the way to access such informations on BSD systems. + * Many systems should provide route information through raw PF_ROUTE + * sockets. + * In MS Windows, default gateway is found by looking into the registry + * or by using GetBestRoute(). */ +#ifdef __linux__ +#define USE_PROC_NET_ROUTE +#undef USE_SOCKET_ROUTE +#undef USE_SYSCTL_NET_ROUTE +#endif + +#ifdef BSD +#undef USE_PROC_NET_ROUTE +#define USE_SOCKET_ROUTE +#undef USE_SYSCTL_NET_ROUTE +#endif + +#ifdef __APPLE__ +#undef USE_PROC_NET_ROUTE +#undef USE_SOCKET_ROUTE +#define USE_SYSCTL_NET_ROUTE +#endif + +#if (defined(sun) && defined(__SVR4)) +#undef USE_PROC_NET_ROUTE +#define USE_SOCKET_ROUTE +#undef USE_SYSCTL_NET_ROUTE +#endif + +#ifdef WIN32 +#undef USE_PROC_NET_ROUTE +#undef USE_SOCKET_ROUTE +#undef USE_SYSCTL_NET_ROUTE +//#define USE_WIN32_CODE +#define USE_WIN32_CODE_2 +#endif + +#ifdef __CYGWIN__ +#undef USE_PROC_NET_ROUTE +#undef USE_SOCKET_ROUTE +#undef USE_SYSCTL_NET_ROUTE +#define USE_WIN32_CODE +#include <stdarg.h> +#include <w32api/windef.h> +#include <w32api/winbase.h> +#include <w32api/winreg.h> +#endif + +#ifdef __HAIKU__ +#include <stdlib.h> +#include <unistd.h> +#include <net/if.h> +#include <sys/sockio.h> +#define USE_HAIKU_CODE +#endif + +#ifdef USE_SYSCTL_NET_ROUTE +#include <stdlib.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <net/route.h> +#endif +#ifdef USE_SOCKET_ROUTE +#include <unistd.h> +#include <string.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/route.h> +#endif + +#ifdef USE_WIN32_CODE +#include <unknwn.h> +#include <winreg.h> +#define MAX_KEY_LENGTH 255 +#define MAX_VALUE_LENGTH 16383 +#endif + +#ifdef USE_WIN32_CODE_2 +#include <windows.h> +#include <iphlpapi.h> +#endif + +#include "getgateway.h" + +#ifndef WIN32 +#define SUCCESS (0) +#define FAILED (-1) +#endif + +#ifdef USE_PROC_NET_ROUTE +/* + parse /proc/net/route which is as follow : + +Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT +wlan0 0001A8C0 00000000 0001 0 0 0 00FFFFFF 0 0 0 +eth0 0000FEA9 00000000 0001 0 0 0 0000FFFF 0 0 0 +wlan0 00000000 0101A8C0 0003 0 0 0 00000000 0 0 0 +eth0 00000000 00000000 0001 0 0 1000 00000000 0 0 0 + + One header line, and then one line by route by route table entry. +*/ +int getdefaultgateway(in_addr_t * addr) +{ + unsigned long d, g; + char buf[256]; + int line = 0; + FILE * f; + char * p; + f = fopen("/proc/net/route", "r"); + if(!f) + return FAILED; + while(fgets(buf, sizeof(buf), f)) { + if(line > 0) { /* skip the first line */ + p = buf; + /* skip the interface name */ + while(*p && !isspace(*p)) + p++; + while(*p && isspace(*p)) + p++; + if(sscanf(p, "%lx%lx", &d, &g)==2) { + if(d == 0 && g != 0) { /* default */ + *addr = g; + fclose(f); + return SUCCESS; + } + } + } + line++; + } + /* default route not found ! */ + if(f) + fclose(f); + return FAILED; +} +#endif /* #ifdef USE_PROC_NET_ROUTE */ + + +#ifdef USE_SYSCTL_NET_ROUTE + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +int getdefaultgateway(in_addr_t * addr) +{ +#if 0 + /* net.route.0.inet.dump.0.0 ? */ + int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, + NET_RT_DUMP, 0, 0/*tableid*/}; +#endif + /* net.route.0.inet.flags.gateway */ + int mib[] = {CTL_NET, PF_ROUTE, 0, AF_INET, + NET_RT_FLAGS, RTF_GATEWAY}; + size_t l; + char * buf, * p; + struct rt_msghdr * rt; + struct sockaddr * sa; + struct sockaddr * sa_tab[RTAX_MAX]; + int i; + int r = FAILED; + if(sysctl(mib, sizeof(mib)/sizeof(int), 0, &l, 0, 0) < 0) { + return FAILED; + } + if(l>0) { + buf = malloc(l); + if(sysctl(mib, sizeof(mib)/sizeof(int), buf, &l, 0, 0) < 0) { + free(buf); + return FAILED; + } + for(p=buf; p<buf+l; p+=rt->rtm_msglen) { + rt = (struct rt_msghdr *)p; + sa = (struct sockaddr *)(rt + 1); + for(i=0; i<RTAX_MAX; i++) { + if(rt->rtm_addrs & (1 << i)) { + sa_tab[i] = sa; + sa = (struct sockaddr *)((char *)sa + ROUNDUP(sa->sa_len)); + } else { + sa_tab[i] = NULL; + } + } + if( ((rt->rtm_addrs & (RTA_DST|RTA_GATEWAY)) == (RTA_DST|RTA_GATEWAY)) + && sa_tab[RTAX_DST]->sa_family == AF_INET + && sa_tab[RTAX_GATEWAY]->sa_family == AF_INET) { + if(((struct sockaddr_in *)sa_tab[RTAX_DST])->sin_addr.s_addr == 0) { + *addr = ((struct sockaddr_in *)(sa_tab[RTAX_GATEWAY]))->sin_addr.s_addr; + r = SUCCESS; + } + } + } + free(buf); + } + return r; +} +#endif /* #ifdef USE_SYSCTL_NET_ROUTE */ + + +#ifdef USE_SOCKET_ROUTE +/* Thanks to Darren Kenny for this code */ +#define NEXTADDR(w, u) \ + if (rtm_addrs & (w)) {\ + l = sizeof(struct sockaddr); memmove(cp, &(u), l); cp += l;\ + } + +#define rtm m_rtmsg.m_rtm + +struct { + struct rt_msghdr m_rtm; + char m_space[512]; +} m_rtmsg; + +int getdefaultgateway(in_addr_t *addr) +{ + int s, seq, l, rtm_addrs, i; + pid_t pid; + struct sockaddr so_dst, so_mask; + char *cp = m_rtmsg.m_space; + struct sockaddr *gate = NULL, *sa; + struct rt_msghdr *msg_hdr; + + pid = getpid(); + seq = 0; + rtm_addrs = RTA_DST | RTA_NETMASK; + + memset(&so_dst, 0, sizeof(so_dst)); + memset(&so_mask, 0, sizeof(so_mask)); + memset(&rtm, 0, sizeof(struct rt_msghdr)); + + rtm.rtm_type = RTM_GET; + rtm.rtm_flags = RTF_UP | RTF_GATEWAY; + rtm.rtm_version = RTM_VERSION; + rtm.rtm_seq = ++seq; + rtm.rtm_addrs = rtm_addrs; + + so_dst.sa_family = AF_INET; + so_mask.sa_family = AF_INET; + + NEXTADDR(RTA_DST, so_dst); + NEXTADDR(RTA_NETMASK, so_mask); + + rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; + + s = socket(PF_ROUTE, SOCK_RAW, 0); + + if (write(s, (char *)&m_rtmsg, l) < 0) { + close(s); + return FAILED; + } + + do { + l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid)); + + close(s); + + msg_hdr = &rtm; + + cp = ((char *)(msg_hdr + 1)); + if (msg_hdr->rtm_addrs) { + for (i = 1; i; i <<= 1) + if (i & msg_hdr->rtm_addrs) { + sa = (struct sockaddr *)cp; + if (i == RTA_GATEWAY ) + gate = sa; + + cp += sizeof(struct sockaddr); + } + } else { + return FAILED; + } + + + if (gate != NULL ) { + *addr = ((struct sockaddr_in *)gate)->sin_addr.s_addr; + return SUCCESS; + } else { + return FAILED; + } +} +#endif /* #ifdef USE_SOCKET_ROUTE */ + +#ifdef USE_WIN32_CODE +LIBSPEC int getdefaultgateway(in_addr_t * addr) +{ + HKEY networkCardsKey; + HKEY networkCardKey; + HKEY interfacesKey; + HKEY interfaceKey; + DWORD i = 0; + DWORD numSubKeys = 0; + TCHAR keyName[MAX_KEY_LENGTH]; + DWORD keyNameLength = MAX_KEY_LENGTH; + TCHAR keyValue[MAX_VALUE_LENGTH]; + DWORD keyValueLength = MAX_VALUE_LENGTH; + DWORD keyValueType = REG_SZ; + TCHAR gatewayValue[MAX_VALUE_LENGTH]; + DWORD gatewayValueLength = MAX_VALUE_LENGTH; + DWORD gatewayValueType = REG_MULTI_SZ; + int done = 0; + + //const char * networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; + //const char * interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; +#ifdef UNICODE + LPCTSTR networkCardsPath = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; + LPCTSTR interfacesPath = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; +#define STR_SERVICENAME L"ServiceName" +#define STR_DHCPDEFAULTGATEWAY L"DhcpDefaultGateway" +#define STR_DEFAULTGATEWAY L"DefaultGateway" +#else + LPCTSTR networkCardsPath = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\NetworkCards"; + LPCTSTR interfacesPath = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; +#define STR_SERVICENAME "ServiceName" +#define STR_DHCPDEFAULTGATEWAY "DhcpDefaultGateway" +#define STR_DEFAULTGATEWAY "DefaultGateway" +#endif + // The windows registry lists its primary network devices in the following location: + // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkCards + // + // Each network device has its own subfolder, named with an index, with various properties: + // -NetworkCards + // -5 + // -Description = Broadcom 802.11n Network Adapter + // -ServiceName = {E35A72F8-5065-4097-8DFE-C7790774EE4D} + // -8 + // -Description = Marvell Yukon 88E8058 PCI-E Gigabit Ethernet Controller + // -ServiceName = {86226414-5545-4335-A9D1-5BD7120119AD} + // + // The above service name is the name of a subfolder within: + // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces + // + // There may be more subfolders in this interfaces path than listed in the network cards path above: + // -Interfaces + // -{3a539854-6a70-11db-887c-806e6f6e6963} + // -DhcpIPAddress = 0.0.0.0 + // -[more] + // -{E35A72F8-5065-4097-8DFE-C7790774EE4D} + // -DhcpIPAddress = 10.0.1.4 + // -DhcpDefaultGateway = 10.0.1.1 + // -[more] + // -{86226414-5545-4335-A9D1-5BD7120119AD} + // -DhcpIpAddress = 10.0.1.5 + // -DhcpDefaultGateay = 10.0.1.1 + // -[more] + // + // In order to extract this information, we enumerate each network card, and extract the ServiceName value. + // This is then used to open the interface subfolder, and attempt to extract a DhcpDefaultGateway value. + // Once one is found, we're done. + // + // It may be possible to simply enumerate the interface folders until we find one with a DhcpDefaultGateway value. + // However, the technique used is the technique most cited on the web, and we assume it to be more correct. + + if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predifined key + networkCardsPath, // Name of registry subkey to open + 0, // Reserved - must be zero + KEY_READ, // Mask - desired access rights + &networkCardsKey)) // Pointer to output key + { + // Unable to open network cards keys + return -1; + } + + if(ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Open registry key or predefined key + interfacesPath, // Name of registry subkey to open + 0, // Reserved - must be zero + KEY_READ, // Mask - desired access rights + &interfacesKey)) // Pointer to output key + { + // Unable to open interfaces key + RegCloseKey(networkCardsKey); + return -1; + } + + // Figure out how many subfolders are within the NetworkCards folder + RegQueryInfoKey(networkCardsKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + //printf( "Number of subkeys: %u\n", (unsigned int)numSubKeys); + + // Enumrate through each subfolder within the NetworkCards folder + for(i = 0; i < numSubKeys && !done; i++) + { + keyNameLength = MAX_KEY_LENGTH; + if(ERROR_SUCCESS == RegEnumKeyEx(networkCardsKey, // Open registry key + i, // Index of subkey to retrieve + keyName, // Buffer that receives the name of the subkey + &keyNameLength, // Variable that receives the size of the above buffer + NULL, // Reserved - must be NULL + NULL, // Buffer that receives the class string + NULL, // Variable that receives the size of the above buffer + NULL)) // Variable that receives the last write time of subkey + { + if(RegOpenKeyEx(networkCardsKey, keyName, 0, KEY_READ, &networkCardKey) == ERROR_SUCCESS) + { + keyValueLength = MAX_VALUE_LENGTH; + if(ERROR_SUCCESS == RegQueryValueEx(networkCardKey, // Open registry key + STR_SERVICENAME, // Name of key to query + NULL, // Reserved - must be NULL + &keyValueType, // Receives value type + (LPBYTE)keyValue, // Receives value + &keyValueLength)) // Receives value length in bytes + { +// printf("keyValue: %s\n", keyValue); + if(RegOpenKeyEx(interfacesKey, keyValue, 0, KEY_READ, &interfaceKey) == ERROR_SUCCESS) + { + gatewayValueLength = MAX_VALUE_LENGTH; + if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key + STR_DHCPDEFAULTGATEWAY, // Name of key to query + NULL, // Reserved - must be NULL + &gatewayValueType, // Receives value type + (LPBYTE)gatewayValue, // Receives value + &gatewayValueLength)) // Receives value length in bytes + { + // Check to make sure it's a string + if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) + { + //printf("gatewayValue: %s\n", gatewayValue); + done = 1; + } + } + else if(ERROR_SUCCESS == RegQueryValueEx(interfaceKey, // Open registry key + STR_DEFAULTGATEWAY, // Name of key to query + NULL, // Reserved - must be NULL + &gatewayValueType, // Receives value type + (LPBYTE)gatewayValue,// Receives value + &gatewayValueLength)) // Receives value length in bytes + { + // Check to make sure it's a string + if((gatewayValueType == REG_MULTI_SZ || gatewayValueType == REG_SZ) && (gatewayValueLength > 1)) + { + //printf("gatewayValue: %s\n", gatewayValue); + done = 1; + } + } + RegCloseKey(interfaceKey); + } + } + RegCloseKey(networkCardKey); + } + } + } + + RegCloseKey(interfacesKey); + RegCloseKey(networkCardsKey); + + if(done) + { +#if UNICODE + char tmp[32]; + for(i = 0; i < 32; i++) { + tmp[i] = (char)gatewayValue[i]; + if(!tmp[i]) + break; + } + tmp[31] = '\0'; + *addr = inet_addr(tmp); +#else + *addr = inet_addr(gatewayValue); +#endif + return 0; + } + + return -1; +} +#endif /* #ifdef USE_WIN32_CODE */ + +#ifdef USE_WIN32_CODE_2 +int getdefaultgateway(in_addr_t *addr) +{ + MIB_IPFORWARDROW ip_forward; + memset(&ip_forward, 0, sizeof(ip_forward)); + if(GetBestRoute(inet_addr("0.0.0.0"), 0, &ip_forward) != NO_ERROR) + return -1; + *addr = ip_forward.dwForwardNextHop; + return 0; +} +#endif /* #ifdef USE_WIN32_CODE_2 */ + +#ifdef USE_HAIKU_CODE +int getdefaultgateway(in_addr_t *addr) +{ + int fd, ret = -1; + struct ifconf config; + void *buffer = NULL; + struct ifreq *interface; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return -1; + } + if (ioctl(fd, SIOCGRTSIZE, &config, sizeof(config)) != 0) { + goto fail; + } + if (config.ifc_value < 1) { + goto fail; /* No routes */ + } + if ((buffer = malloc(config.ifc_value)) == NULL) { + goto fail; + } + config.ifc_len = config.ifc_value; + config.ifc_buf = buffer; + if (ioctl(fd, SIOCGRTTABLE, &config, sizeof(config)) != 0) { + goto fail; + } + for (interface = buffer; + (uint8_t *)interface < (uint8_t *)buffer + config.ifc_len; ) { + struct route_entry route = interface->ifr_route; + int intfSize; + if (route.flags & (RTF_GATEWAY | RTF_DEFAULT)) { + *addr = ((struct sockaddr_in *)route.gateway)->sin_addr.s_addr; + ret = 0; + break; + } + intfSize = sizeof(route) + IF_NAMESIZE; + if (route.destination != NULL) { + intfSize += route.destination->sa_len; + } + if (route.mask != NULL) { + intfSize += route.mask->sa_len; + } + if (route.gateway != NULL) { + intfSize += route.gateway->sa_len; + } + interface = (struct ifreq *)((uint8_t *)interface + intfSize); + } +fail: + free(buffer); + close(fd); + return ret; +} +#endif /* #ifdef USE_HAIKU_CODE */ + + diff --git a/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h b/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h new file mode 100644 index 0000000..9432528 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/getgateway.h @@ -0,0 +1,36 @@ +/* $Id: getgateway.h,v 1.4 2009/12/19 12:00:00 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007, Thomas BERNARD <miniupnp@free.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef __GETGATEWAY_H__ +#define __GETGATEWAY_H__ + +#ifdef WIN32 +#if !defined(_MSC_VER) +#include <stdint.h> +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +#endif +#define in_addr_t uint32_t +#endif +#include "declspec.h" + +/* getdefaultgateway() : + * return value : + * 0 : success + * -1 : failure */ +LIBSPEC int getdefaultgateway(in_addr_t * addr); + +#endif diff --git a/3rdParty/LibNATPMP/src/libnatpmp/natpmp.c b/3rdParty/LibNATPMP/src/libnatpmp/natpmp.c new file mode 100644 index 0000000..53869c3 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/natpmp.c @@ -0,0 +1,350 @@ +/* $Id: natpmp.c,v 1.13 2011/01/03 17:31:03 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007-2011, Thomas BERNARD <miniupnp@free.fr> + * http://miniupnp.free.fr/libnatpmp.html + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef __linux__ +#define _BSD_SOURCE 1 +#endif +#include <string.h> +#include <time.h> +#if !defined(_MSC_VER) +#include <sys/time.h> +#endif +#ifdef WIN32 +#include <errno.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#include <io.h> +#define EWOULDBLOCK WSAEWOULDBLOCK +#define ECONNREFUSED WSAECONNREFUSED +#include "wingettimeofday.h" +#else +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> +#define closesocket close +#endif +#include "natpmp.h" +#include "getgateway.h" + +LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw) +{ +#ifdef WIN32 + u_long ioctlArg = 1; +#else + int flags; +#endif + struct sockaddr_in addr; + if(!p) + return NATPMP_ERR_INVALIDARGS; + memset(p, 0, sizeof(natpmp_t)); + p->s = socket(PF_INET, SOCK_DGRAM, 0); + if(p->s < 0) + return NATPMP_ERR_SOCKETERROR; +#ifdef WIN32 + if(ioctlsocket(p->s, FIONBIO, &ioctlArg) == SOCKET_ERROR) + return NATPMP_ERR_FCNTLERROR; +#else + if((flags = fcntl(p->s, F_GETFL, 0)) < 0) + return NATPMP_ERR_FCNTLERROR; + if(fcntl(p->s, F_SETFL, flags | O_NONBLOCK) < 0) + return NATPMP_ERR_FCNTLERROR; +#endif + + if(forcegw) { + p->gateway = forcedgw; + } else { + if(getdefaultgateway(&(p->gateway)) < 0) + return NATPMP_ERR_CANNOTGETGATEWAY; + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(NATPMP_PORT); + addr.sin_addr.s_addr = p->gateway; + if(connect(p->s, (struct sockaddr *)&addr, sizeof(addr)) < 0) + return NATPMP_ERR_CONNECTERR; + return 0; +} + +LIBSPEC int closenatpmp(natpmp_t * p) +{ + if(!p) + return NATPMP_ERR_INVALIDARGS; + if(closesocket(p->s) < 0) + return NATPMP_ERR_CLOSEERR; + return 0; +} + +int sendpendingrequest(natpmp_t * p) +{ + int r; +/* struct sockaddr_in addr;*/ + if(!p) + return NATPMP_ERR_INVALIDARGS; +/* memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(NATPMP_PORT); + addr.sin_addr.s_addr = p->gateway; + r = (int)sendto(p->s, p->pending_request, p->pending_request_len, 0, + (struct sockaddr *)&addr, sizeof(addr));*/ + r = (int)send(p->s, p->pending_request, p->pending_request_len, 0); + return (r<0) ? NATPMP_ERR_SENDERR : r; +} + +int sendnatpmprequest(natpmp_t * p) +{ + int n; + if(!p) + return NATPMP_ERR_INVALIDARGS; + /* TODO : check if no request is allready pending */ + p->has_pending_request = 1; + p->try_number = 1; + n = sendpendingrequest(p); + gettimeofday(&p->retry_time, NULL); // check errors ! + p->retry_time.tv_usec += 250000; /* add 250ms */ + if(p->retry_time.tv_usec >= 1000000) { + p->retry_time.tv_usec -= 1000000; + p->retry_time.tv_sec++; + } + return n; +} + +LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout) +{ + struct timeval now; + if(!p || !timeout) + return NATPMP_ERR_INVALIDARGS; + if(!p->has_pending_request) + return NATPMP_ERR_NOPENDINGREQ; + if(gettimeofday(&now, NULL) < 0) + return NATPMP_ERR_GETTIMEOFDAYERR; + timeout->tv_sec = p->retry_time.tv_sec - now.tv_sec; + timeout->tv_usec = p->retry_time.tv_usec - now.tv_usec; + if(timeout->tv_usec < 0) { + timeout->tv_usec += 1000000; + timeout->tv_sec--; + } + return 0; +} + +LIBSPEC int sendpublicaddressrequest(natpmp_t * p) +{ + if(!p) + return NATPMP_ERR_INVALIDARGS; + //static const unsigned char request[] = { 0, 0 }; + p->pending_request[0] = 0; + p->pending_request[1] = 0; + p->pending_request_len = 2; + // TODO: return 0 instead of sizeof(request) ?? + return sendnatpmprequest(p); +} + +LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, + uint16_t privateport, uint16_t publicport, + uint32_t lifetime) +{ + if(!p || (protocol!=NATPMP_PROTOCOL_TCP && protocol!=NATPMP_PROTOCOL_UDP)) + return NATPMP_ERR_INVALIDARGS; + p->pending_request[0] = 0; + p->pending_request[1] = protocol; + p->pending_request[2] = 0; + p->pending_request[3] = 0; + *((uint16_t *)(p->pending_request + 4)) = htons(privateport); + *((uint16_t *)(p->pending_request + 6)) = htons(publicport); + *((uint32_t *)(p->pending_request + 8)) = htonl(lifetime); + p->pending_request_len = 12; + return sendnatpmprequest(p); +} + +LIBSPEC int readnatpmpresponse(natpmp_t * p, natpmpresp_t * response) +{ + unsigned char buf[16]; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int n; + if(!p) + return NATPMP_ERR_INVALIDARGS; + n = recvfrom(p->s, buf, sizeof(buf), 0, + (struct sockaddr *)&addr, &addrlen); + if(n<0) + switch(errno) { + /*case EAGAIN:*/ + case EWOULDBLOCK: + n = NATPMP_TRYAGAIN; + break; + case ECONNREFUSED: + n = NATPMP_ERR_NOGATEWAYSUPPORT; + break; + default: + n = NATPMP_ERR_RECVFROM; + } + /* check that addr is correct (= gateway) */ + else if(addr.sin_addr.s_addr != p->gateway) + n = NATPMP_ERR_WRONGPACKETSOURCE; + else { + response->resultcode = ntohs(*((uint16_t *)(buf + 2))); + response->epoch = ntohl(*((uint32_t *)(buf + 4))); + if(buf[0] != 0) + n = NATPMP_ERR_UNSUPPORTEDVERSION; + else if(buf[1] < 128 || buf[1] > 130) + n = NATPMP_ERR_UNSUPPORTEDOPCODE; + else if(response->resultcode != 0) { + switch(response->resultcode) { + case 1: + n = NATPMP_ERR_UNSUPPORTEDVERSION; + break; + case 2: + n = NATPMP_ERR_NOTAUTHORIZED; + break; + case 3: + n = NATPMP_ERR_NETWORKFAILURE; + break; + case 4: + n = NATPMP_ERR_OUTOFRESOURCES; + break; + case 5: + n = NATPMP_ERR_UNSUPPORTEDOPCODE; + break; + default: + n = NATPMP_ERR_UNDEFINEDERROR; + } + } else { + response->type = buf[1] & 0x7f; + if(buf[1] == 128) + //response->publicaddress.addr = *((uint32_t *)(buf + 8)); + response->pnu.publicaddress.addr.s_addr = *((uint32_t *)(buf + 8)); + else { + response->pnu.newportmapping.privateport = ntohs(*((uint16_t *)(buf + 8))); + response->pnu.newportmapping.mappedpublicport = ntohs(*((uint16_t *)(buf + 10))); + response->pnu.newportmapping.lifetime = ntohl(*((uint32_t *)(buf + 12))); + } + n = 0; + } + } + return n; +} + +int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response) +{ + int n; + if(!p || !response) + return NATPMP_ERR_INVALIDARGS; + if(!p->has_pending_request) + return NATPMP_ERR_NOPENDINGREQ; + n = readnatpmpresponse(p, response); + if(n<0) { + if(n==NATPMP_TRYAGAIN) { + struct timeval now; + gettimeofday(&now, NULL); // check errors ! + if(timercmp(&now, &p->retry_time, >=)) { + int delay, r; + if(p->try_number >= 9) { + return NATPMP_ERR_NOGATEWAYSUPPORT; + } + /*printf("retry! %d\n", p->try_number);*/ + delay = 250 * (1<<p->try_number); // ms + /*for(i=0; i<p->try_number; i++) + delay += delay;*/ + p->retry_time.tv_sec += (delay / 1000); + p->retry_time.tv_usec += (delay % 1000) * 1000; + if(p->retry_time.tv_usec >= 1000000) { + p->retry_time.tv_usec -= 1000000; + p->retry_time.tv_sec++; + } + p->try_number++; + r = sendpendingrequest(p); + if(r<0) + return r; + } + } + } else { + p->has_pending_request = 0; + } + return n; +} + +#ifdef ENABLE_STRNATPMPERR +LIBSPEC const char * strnatpmperr(int r) +{ + const char * s; + switch(r) { + case NATPMP_ERR_INVALIDARGS: + s = "invalid arguments"; + break; + case NATPMP_ERR_SOCKETERROR: + s = "socket() failed"; + break; + case NATPMP_ERR_CANNOTGETGATEWAY: + s = "cannot get default gateway ip address"; + break; + case NATPMP_ERR_CLOSEERR: +#ifdef WIN32 + s = "closesocket() failed"; +#else + s = "close() failed"; +#endif + break; + case NATPMP_ERR_RECVFROM: + s = "recvfrom() failed"; + break; + case NATPMP_ERR_NOPENDINGREQ: + s = "no pending request"; + break; + case NATPMP_ERR_NOGATEWAYSUPPORT: + s = "the gateway does not support nat-pmp"; + break; + case NATPMP_ERR_CONNECTERR: + s = "connect() failed"; + break; + case NATPMP_ERR_WRONGPACKETSOURCE: + s = "packet not received from the default gateway"; + break; + case NATPMP_ERR_SENDERR: + s = "send() failed"; + break; + case NATPMP_ERR_FCNTLERROR: + s = "fcntl() failed"; + break; + case NATPMP_ERR_GETTIMEOFDAYERR: + s = "gettimeofday() failed"; + break; + case NATPMP_ERR_UNSUPPORTEDVERSION: + s = "unsupported nat-pmp version error from server"; + break; + case NATPMP_ERR_UNSUPPORTEDOPCODE: + s = "unsupported nat-pmp opcode error from server"; + break; + case NATPMP_ERR_UNDEFINEDERROR: + s = "undefined nat-pmp server error"; + break; + case NATPMP_ERR_NOTAUTHORIZED: + s = "not authorized"; + break; + case NATPMP_ERR_NETWORKFAILURE: + s = "network failure"; + break; + case NATPMP_ERR_OUTOFRESOURCES: + s = "nat-pmp server out of resources"; + break; + default: + s = "Unknown libnatpmp error"; + } + return s; +} +#endif + diff --git a/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h b/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h new file mode 100644 index 0000000..1175b58 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/natpmp.h @@ -0,0 +1,203 @@ +/* $Id: natpmp.h,v 1.14 2011/01/03 17:31:03 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007-2011, Thomas BERNARD <miniupnp@free.fr> + * http://miniupnp.free.fr/libnatpmp.html + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef __NATPMP_H__ +#define __NATPMP_H__ + +/* NAT-PMP Port as defined by the NAT-PMP draft */ +#define NATPMP_PORT (5351) + +#include <time.h> +#if !defined(_MSC_VER) +#include <sys/time.h> +#endif +#ifdef WIN32 +#include <winsock2.h> +#if !defined(_MSC_VER) || _MSC_VER >= 1600 +#include <stdint.h> +#else +typedef unsigned long uint32_t; +typedef unsigned short uint16_t; +#endif +#define in_addr_t uint32_t +#include "declspec.h" +#else +#define LIBSPEC +#include <netinet/in.h> +#endif + +typedef struct { + int s; /* socket */ + in_addr_t gateway; /* default gateway (IPv4) */ + int has_pending_request; + unsigned char pending_request[12]; + int pending_request_len; + int try_number; + struct timeval retry_time; +} natpmp_t; + +typedef struct { + uint16_t type; /* NATPMP_RESPTYPE_* */ + uint16_t resultcode; /* NAT-PMP response code */ + uint32_t epoch; /* Seconds since start of epoch */ + union { + struct { + //in_addr_t addr; + struct in_addr addr; + } publicaddress; + struct { + uint16_t privateport; + uint16_t mappedpublicport; + uint32_t lifetime; + } newportmapping; + } pnu; +} natpmpresp_t; + +/* possible values for type field of natpmpresp_t */ +#define NATPMP_RESPTYPE_PUBLICADDRESS (0) +#define NATPMP_RESPTYPE_UDPPORTMAPPING (1) +#define NATPMP_RESPTYPE_TCPPORTMAPPING (2) + +/* Values to pass to sendnewportmappingrequest() */ +#define NATPMP_PROTOCOL_UDP (1) +#define NATPMP_PROTOCOL_TCP (2) + +/* return values */ +/* NATPMP_ERR_INVALIDARGS : invalid arguments passed to the function */ +#define NATPMP_ERR_INVALIDARGS (-1) +/* NATPMP_ERR_SOCKETERROR : socket() failed. check errno for details */ +#define NATPMP_ERR_SOCKETERROR (-2) +/* NATPMP_ERR_CANNOTGETGATEWAY : can't get default gateway IP */ +#define NATPMP_ERR_CANNOTGETGATEWAY (-3) +/* NATPMP_ERR_CLOSEERR : close() failed. check errno for details */ +#define NATPMP_ERR_CLOSEERR (-4) +/* NATPMP_ERR_RECVFROM : recvfrom() failed. check errno for details */ +#define NATPMP_ERR_RECVFROM (-5) +/* NATPMP_ERR_NOPENDINGREQ : readnatpmpresponseorretry() called while + * no NAT-PMP request was pending */ +#define NATPMP_ERR_NOPENDINGREQ (-6) +/* NATPMP_ERR_NOGATEWAYSUPPORT : the gateway does not support NAT-PMP */ +#define NATPMP_ERR_NOGATEWAYSUPPORT (-7) +/* NATPMP_ERR_CONNECTERR : connect() failed. check errno for details */ +#define NATPMP_ERR_CONNECTERR (-8) +/* NATPMP_ERR_WRONGPACKETSOURCE : packet not received from the network gateway */ +#define NATPMP_ERR_WRONGPACKETSOURCE (-9) +/* NATPMP_ERR_SENDERR : send() failed. check errno for details */ +#define NATPMP_ERR_SENDERR (-10) +/* NATPMP_ERR_FCNTLERROR : fcntl() failed. check errno for details */ +#define NATPMP_ERR_FCNTLERROR (-11) +/* NATPMP_ERR_GETTIMEOFDAYERR : gettimeofday() failed. check errno for details */ +#define NATPMP_ERR_GETTIMEOFDAYERR (-12) + +/* */ +#define NATPMP_ERR_UNSUPPORTEDVERSION (-14) +#define NATPMP_ERR_UNSUPPORTEDOPCODE (-15) + +/* Errors from the server : */ +#define NATPMP_ERR_UNDEFINEDERROR (-49) +#define NATPMP_ERR_NOTAUTHORIZED (-51) +#define NATPMP_ERR_NETWORKFAILURE (-52) +#define NATPMP_ERR_OUTOFRESOURCES (-53) + +/* NATPMP_TRYAGAIN : no data available for the moment. try again later */ +#define NATPMP_TRYAGAIN (-100) + +#ifdef __cplusplus +extern "C" { +#endif + +/* initnatpmp() + * initialize a natpmp_t object + * With forcegw=1 the gateway is not detected automaticaly. + * Return values : + * 0 = OK + * NATPMP_ERR_INVALIDARGS + * NATPMP_ERR_SOCKETERROR + * NATPMP_ERR_FCNTLERROR + * NATPMP_ERR_CANNOTGETGATEWAY + * NATPMP_ERR_CONNECTERR */ +LIBSPEC int initnatpmp(natpmp_t * p, int forcegw, in_addr_t forcedgw); + +/* closenatpmp() + * close resources associated with a natpmp_t object + * Return values : + * 0 = OK + * NATPMP_ERR_INVALIDARGS + * NATPMP_ERR_CLOSEERR */ +LIBSPEC int closenatpmp(natpmp_t * p); + +/* sendpublicaddressrequest() + * send a public address NAT-PMP request to the network gateway + * Return values : + * 2 = OK (size of the request) + * NATPMP_ERR_INVALIDARGS + * NATPMP_ERR_SENDERR */ +LIBSPEC int sendpublicaddressrequest(natpmp_t * p); + +/* sendnewportmappingrequest() + * send a new port mapping NAT-PMP request to the network gateway + * Arguments : + * protocol is either NATPMP_PROTOCOL_TCP or NATPMP_PROTOCOL_UDP, + * lifetime is in seconds. + * To remove a port mapping, set lifetime to zero. + * To remove all port mappings to the host, set lifetime and both ports + * to zero. + * Return values : + * 12 = OK (size of the request) + * NATPMP_ERR_INVALIDARGS + * NATPMP_ERR_SENDERR */ +LIBSPEC int sendnewportmappingrequest(natpmp_t * p, int protocol, + uint16_t privateport, uint16_t publicport, + uint32_t lifetime); + +/* getnatpmprequesttimeout() + * fills the timeval structure with the timeout duration of the + * currently pending NAT-PMP request. + * Return values : + * 0 = OK + * NATPMP_ERR_INVALIDARGS + * NATPMP_ERR_GETTIMEOFDAYERR + * NATPMP_ERR_NOPENDINGREQ */ +LIBSPEC int getnatpmprequesttimeout(natpmp_t * p, struct timeval * timeout); + +/* readnatpmpresponseorretry() + * fills the natpmpresp_t structure if possible + * Return values : + * 0 = OK + * NATPMP_TRYAGAIN + * NATPMP_ERR_INVALIDARGS + * NATPMP_ERR_NOPENDINGREQ + * NATPMP_ERR_NOGATEWAYSUPPORT + * NATPMP_ERR_RECVFROM + * NATPMP_ERR_WRONGPACKETSOURCE + * NATPMP_ERR_UNSUPPORTEDVERSION + * NATPMP_ERR_UNSUPPORTEDOPCODE + * NATPMP_ERR_NOTAUTHORIZED + * NATPMP_ERR_NETWORKFAILURE + * NATPMP_ERR_OUTOFRESOURCES + * NATPMP_ERR_UNSUPPORTEDOPCODE + * NATPMP_ERR_UNDEFINEDERROR */ +LIBSPEC int readnatpmpresponseorretry(natpmp_t * p, natpmpresp_t * response); + +#ifdef ENABLE_STRNATPMPERR +LIBSPEC const char * strnatpmperr(int t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3rdParty/LibNATPMP/src/libnatpmp/natpmpc.c b/3rdParty/LibNATPMP/src/libnatpmp/natpmpc.c new file mode 100644 index 0000000..d869572 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/natpmpc.c @@ -0,0 +1,229 @@ +/* $Id: natpmpc.c,v 1.9 2011/04/18 18:25:21 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007-2011, Thomas BERNARD <miniupnp@free.fr> + * http://miniupnp.free.fr/libnatpmp.html + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <stdio.h> +#include <errno.h> +#include <string.h> +#if defined(_MSC_VER) +#if _MSC_VER >= 1400 +#define strcasecmp _stricmp +#else +#define strcasecmp stricmp +#endif +#else +#include <unistd.h> +#endif +#ifdef WIN32 +#include <winsock2.h> +#else +#include <netinet/in.h> +#include <arpa/inet.h> +#endif +#include "natpmp.h" + +void usage(FILE * out, const char * argv0) +{ + fprintf(out, "Usage :\n"); + fprintf(out, " %s [options]\n", argv0); + fprintf(out, "\tdisplay the public IP address.\n"); + fprintf(out, " %s -h\n", argv0); + fprintf(out, "\tdisplay this help screen.\n"); + fprintf(out, " %s [options] -a <public port> <private port> <protocol> [lifetime]\n", argv0); + fprintf(out, "\tadd a port mapping.\n"); + fprintf(out, "\nOption available :\n"); + fprintf(out, " -g ipv4address\n"); + fprintf(out, "\tforce the gateway to be used as destination for NAT-PMP commands.\n"); + fprintf(out, "\n In order to remove a mapping, set it with a lifetime of 0 seconds.\n"); + fprintf(out, " To remove all mappings for your machine, use 0 as private port and lifetime.\n"); +} + +/* sample code for using libnatpmp */ +int main(int argc, char * * argv) +{ + natpmp_t natpmp; + natpmpresp_t response; + int r; + int sav_errno; + struct timeval timeout; + fd_set fds; + int i; + int protocol = 0; + uint16_t privateport = 0; + uint16_t publicport = 0; + uint32_t lifetime = 3600; + int command = 0; + int forcegw = 0; + in_addr_t gateway = 0; + +#ifdef WIN32 + WSADATA wsaData; + int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if(nResult != NO_ERROR) + { + fprintf(stderr, "WSAStartup() failed.\n"); + return -1; + } +#endif + + /* argument parsing */ + for(i=1; i<argc; i++) { + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case 'h': + usage(stdout, argv[0]); + return 0; + case 'g': + forcegw = 1; + if(argc < i + 1) { + fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]); + return 1; + } + gateway = inet_addr(argv[++i]); + break; + case 'a': + command = 'a'; + if(argc < i + 3) { + fprintf(stderr, "Not enough arguments for option -%c\n", argv[i][1]); + return 1; + } + i++; + if(1 != sscanf(argv[i], "%hu", &publicport)) { + fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]); + return 1; + } + i++; + if(1 != sscanf(argv[i], "%hu", &privateport)) { + fprintf(stderr, "%s is not a correct 16bits unsigned integer\n", argv[i]); + return 1; + } + i++; + if(0 == strcasecmp(argv[i], "tcp")) + protocol = NATPMP_PROTOCOL_TCP; + else if(0 == strcasecmp(argv[i], "udp")) + protocol = NATPMP_PROTOCOL_UDP; + else { + fprintf(stderr, "%s is not a valid protocol\n", argv[i]); + return 1; + } + if(argc >= i) { + i++; + if(1 != sscanf(argv[i], "%u", &lifetime)) { + fprintf(stderr, "%s is not a correct 32bits unsigned integer\n", argv[i]); + } + } + break; + default: + fprintf(stderr, "Unknown option %s\n", argv[i]); + usage(stderr, argv[0]); + return 1; + } + } else { + fprintf(stderr, "Unknown option %s\n", argv[i]); + usage(stderr, argv[0]); + return 1; + } + } + + /* initnatpmp() */ + r = initnatpmp(&natpmp, forcegw, gateway); + printf("initnatpmp() returned %d (%s)\n", r, r?"FAILED":"SUCCESS"); + if(r<0) + return 1; + + printf("using gateway : %s\n", inet_ntoa(*((struct in_addr *)&natpmp.gateway))); + + /* sendpublicaddressrequest() */ + r = sendpublicaddressrequest(&natpmp); + printf("sendpublicaddressrequest returned %d (%s)\n", + r, r==2?"SUCCESS":"FAILED"); + if(r<0) + return 1; + + do { + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + r = select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + if(r<0) { + fprintf(stderr, "select()"); + return 1; + } + r = readnatpmpresponseorretry(&natpmp, &response); + sav_errno = errno; + printf("readnatpmpresponseorretry returned %d (%s)\n", + r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); + if(r<0 && r!=NATPMP_TRYAGAIN) { +#ifdef ENABLE_STRNATPMPERR + fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", + strnatpmperr(r)); +#endif + fprintf(stderr, " errno=%d '%s'\n", + sav_errno, strerror(sav_errno)); + } + } while(r==NATPMP_TRYAGAIN); + if(r<0) + return 1; + + /* TODO : check that response.type == 0 */ + printf("Public IP address : %s\n", inet_ntoa(response.pnu.publicaddress.addr)); + printf("epoch = %u\n", response.epoch); + + if(command == 'a') { + /* sendnewportmappingrequest() */ + r = sendnewportmappingrequest(&natpmp, protocol, + privateport, publicport, + lifetime); + printf("sendnewportmappingrequest returned %d (%s)\n", + r, r==12?"SUCCESS":"FAILED"); + if(r < 0) + return 1; + + do { + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + printf("readnatpmpresponseorretry returned %d (%s)\n", + r, r==0?"OK":(r==NATPMP_TRYAGAIN?"TRY AGAIN":"FAILED")); + } while(r==NATPMP_TRYAGAIN); + if(r<0) { +#ifdef ENABLE_STRNATPMPERR + fprintf(stderr, "readnatpmpresponseorretry() failed : %s\n", + strnatpmperr(r)); +#endif + return 1; + } + + printf("Mapped public port %hu protocol %s to local port %hu " + "liftime %u\n", + response.pnu.newportmapping.mappedpublicport, + response.type == NATPMP_RESPTYPE_UDPPORTMAPPING ? "UDP" : + (response.type == NATPMP_RESPTYPE_TCPPORTMAPPING ? "TCP" : + "UNKNOWN"), + response.pnu.newportmapping.privateport, + response.pnu.newportmapping.lifetime); + printf("epoch = %u\n", response.epoch); + } + + r = closenatpmp(&natpmp); + printf("closenatpmp() returned %d (%s)\n", r, r==0?"SUCCESS":"FAILED"); + if(r<0) + return 1; + + return 0; +} + diff --git a/3rdParty/LibNATPMP/src/libnatpmp/wingettimeofday.c b/3rdParty/LibNATPMP/src/libnatpmp/wingettimeofday.c new file mode 100644 index 0000000..5b1b8a6 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/wingettimeofday.c @@ -0,0 +1,50 @@ +/* $Id: wingettimeofday.c,v 1.3 2009/12/19 12:00:00 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007-2008, Thomas BERNARD <miniupnp@free.fr> + * http://miniupnp.free.fr/libnatpmp.html + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef WIN32 +#if defined(_MSC_VER) +struct timeval { + long tv_sec; + long tv_usec; +}; +#else +#include <sys/time.h> +#endif + +typedef struct _FILETIME { + unsigned long dwLowDateTime; + unsigned long dwHighDateTime; +} FILETIME; + +void __stdcall GetSystemTimeAsFileTime(FILETIME*); + +//int gettimeofday(struct timeval* p, void* tz /* IGNORED */); + +int gettimeofday(struct timeval* p, void* tz /* IGNORED */) { + union { + long long ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } _now; + + if(!p) + return -1; + GetSystemTimeAsFileTime( &(_now.ft) ); + p->tv_usec =(long)((_now.ns100 / 10LL) % 1000000LL ); + p->tv_sec = (long)((_now.ns100-(116444736000000000LL))/10000000LL); + return 0; +} +#endif + diff --git a/3rdParty/LibNATPMP/src/libnatpmp/wingettimeofday.h b/3rdParty/LibNATPMP/src/libnatpmp/wingettimeofday.h new file mode 100644 index 0000000..ed6c599 --- /dev/null +++ b/3rdParty/LibNATPMP/src/libnatpmp/wingettimeofday.h @@ -0,0 +1,27 @@ +/* $Id: wingettimeofday.h,v 1.1 2009/12/19 12:02:42 nanard Exp $ */ +/* libnatpmp + * Copyright (c) 2007-2008, Thomas BERNARD <miniupnp@free.fr> + * http://miniupnp.free.fr/libnatpmp.html + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef __WINGETTIMEOFDAY_H__ +#define __WINGETTIMEOFDAY_H__ +#ifdef WIN32 +#if defined(_MSC_VER) +#include <time.h> +#else +#include <sys/time.h> +#endif +int gettimeofday(struct timeval* p, void* tz /* IGNORED */); +#endif +#endif diff --git a/3rdParty/Lua/SConscript b/3rdParty/Lua/SConscript index 3baa2d8..68f4e36 100644 --- a/3rdParty/Lua/SConscript +++ b/3rdParty/Lua/SConscript @@ -30,6 +30,10 @@ if env.get("LUA_BUNDLED", False) : if env["SCONS_STAGE"] == "build" : myenv = env.Clone() + if env["PLATFORM"] == "win32" : + myenv.Append(CFLAGS = ["/TP"]) + else : + myenv.Append(CFLAGS = ["-x", "c++"]) # Remove warn flags myenv.Replace(CCFLAGS = [flag for flag in env["CCFLAGS"] if flag not in ["-W", "-Wall"]]) diff --git a/3rdParty/Lua/src/lua.c b/3rdParty/Lua/src/lua.c index 3a46609..2b10827 100644 --- a/3rdParty/Lua/src/lua.c +++ b/3rdParty/Lua/src/lua.c @@ -12,10 +12,10 @@ #define lua_c -#include "lua.h" +#include <lua.h> -#include "lauxlib.h" -#include "lualib.h" +#include <lauxlib.h> +#include <lualib.h> diff --git a/3rdParty/OpenSSL/.gitignore b/3rdParty/OpenSSL/.gitignore new file mode 100644 index 0000000..fa963ae --- /dev/null +++ b/3rdParty/OpenSSL/.gitignore @@ -0,0 +1 @@ +openssl diff --git a/3rdParty/OpenSSL/SConscript b/3rdParty/OpenSSL/SConscript index c19632c..dfe78b7 100644 --- a/3rdParty/OpenSSL/SConscript +++ b/3rdParty/OpenSSL/SConscript @@ -1,6 +1,6 @@ Import("env") -openssl_bundle_dir = "#/../openssl" +openssl_bundle_dir = "openssl" if env.get("OPENSSL_BUNDLED", False) : if env["SCONS_STAGE"] == "flags" : diff --git a/BuildTools/CLang/.gitignore b/BuildTools/CLang/.gitignore new file mode 100644 index 0000000..df682c0 --- /dev/null +++ b/BuildTools/CLang/.gitignore @@ -0,0 +1,4 @@ +CLangDiagnosticsFlags +CLangDiagnosticsFlagsTool.sh +CLangDiagnosticsFlagsTool +clang-diagnostics-overview.* diff --git a/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp b/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp new file mode 100644 index 0000000..ccd5925 --- /dev/null +++ b/BuildTools/CLang/CLangDiagnosticsFlagsTool.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <iostream> +#include <set> +#include <vector> +#include <cassert> +#include <boost/algorithm/string/predicate.hpp> +#include <boost/graph/graph_traits.hpp> +#include <boost/graph/adjacency_list.hpp> +#include <boost/graph/topological_sort.hpp> +#include <boost/graph/topological_sort.hpp> +#include <boost/graph/graphviz.hpp> + +// ----------------------------------------------------------------------------- +// Include diagnostics data from CLang +// ----------------------------------------------------------------------------- + +#define DIAG(name, a, b, c, d, e, f, g) name, + +namespace diag { + enum LexKinds { +#include <clang/Basic/DiagnosticLexKinds.inc> +#include <clang/Basic/DiagnosticParseKinds.inc> +#include <clang/Basic/DiagnosticCommonKinds.inc> +#include <clang/Basic/DiagnosticDriverKinds.inc> +#include <clang/Basic/DiagnosticFrontendKinds.inc> +#include <clang/Basic/DiagnosticSemaKinds.inc> + }; +} + +#define GET_DIAG_ARRAYS +#include <clang/Basic/DiagnosticGroups.inc> +#undef GET_DIAG_ARRAYS + +struct DiagTableEntry { + const char* name; + const short* array; + const short* group; +}; + +static const DiagTableEntry diagnostics[] = { +#define GET_DIAG_TABLE +#include <clang/Basic/DiagnosticGroups.inc> +#undef GET_DIAG_TABLE +}; +static const size_t diagnostics_count = sizeof(diagnostics) / sizeof(diagnostics[0]); + +// ----------------------------------------------------------------------------- + +using namespace boost; + +struct Properties { + Properties() : have(false), implicitHave(false), dontWant(false), implicitDontWant(false), ignored(false), available(false), missing(false), redundant(false), alreadyCovered(false) { + } + + std::string name; + bool have; + bool implicitHave; + bool dontWant; + bool implicitDontWant; + bool ignored; + bool available; + bool missing; + bool redundant; + bool alreadyCovered; +}; + +class GraphVizLabelWriter { + public: + GraphVizLabelWriter(const std::vector<Properties>& properties) : properties(properties) { + } + + template <class VertexOrEdge> + void operator()(std::ostream& out, const VertexOrEdge& v) const { + std::string color; + if (properties[v].missing) { + color = "orange"; + } + else if (properties[v].redundant) { + color = "lightblue"; + } + else if (properties[v].have) { + color = "darkgreen"; + } + else if (properties[v].implicitHave) { + color = "green"; + } + else if (properties[v].dontWant) { + color = "red"; + } + else if (properties[v].implicitDontWant) { + color = "pink"; + } + else if (properties[v].ignored) { + color = "white"; + } + else if (properties[v].available) { + color = "yellow"; + } + else { + assert(false); + } + out << "[label=" << escape_dot_string(properties[v].name) << " fillcolor=\"" << color << "\" style=filled]"; + } + + private: + const std::vector<Properties> properties; +}; + +int main(int argc, char* argv[]) { + // Parse command-line arguments + std::set<std::string> have; + std::set<std::string> dontWant; + std::string outputDir; + for (int i = 1; i < argc; ++i) { + std::string arg(argv[i]); + if (starts_with(arg, "-W")) { + have.insert(arg.substr(2, arg.npos)); + } + else if (starts_with(arg, "-w")) { + dontWant.insert(arg.substr(2, arg.npos)); + } + else if (starts_with(arg, "-O")) { + outputDir = arg.substr(2, arg.npos) + "/"; + } + } + + // Build the graph and initialize properties + typedef adjacency_list<vecS, vecS, bidirectionalS> Graph; + typedef graph_traits<Graph>::vertex_descriptor Vertex; + Graph g(diagnostics_count); + std::vector<Properties> properties(num_vertices(g)); + for (size_t i = 0; i < diagnostics_count; ++i) { + std::string name(diagnostics[i].name); + properties[i].name = name; + properties[i].implicitHave = properties[i].have = have.find(name) != have.end(); + properties[i].implicitDontWant = properties[i].dontWant = dontWant.find(name) != dontWant.end(); + properties[i].ignored = diagnostics[i].group == 0 && diagnostics[i].array == 0; + properties[i].alreadyCovered = false; + properties[i].available = true; + for (const short* j = diagnostics[i].group; j && *j != -1; ++j) { + add_edge(i, *j, g); + } + } + + // Sort the diagnostics + std::list<Vertex> sortedDiagnostics; + boost::topological_sort(g, std::front_inserter(sortedDiagnostics)); + + // Propagate dontWant and have properties down + for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) { + graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd; + for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) { + properties[*adjacentIt].implicitDontWant = properties[*i].implicitDontWant || properties[*adjacentIt].implicitDontWant; + properties[*adjacentIt].implicitHave = properties[*i].implicitHave || properties[*adjacentIt].implicitHave; + } + } + + // Propagate 'available' property upwards + for(std::list<Vertex>::const_reverse_iterator i = sortedDiagnostics.rbegin(); i != sortedDiagnostics.rend(); ++i) { + properties[*i].available = properties[*i].available && !properties[*i].implicitDontWant; + graph_traits<Graph>::in_edge_iterator edgesIt, edgesEnd; + graph_traits<Graph>::edge_descriptor edge; + for (tie(edgesIt, edgesEnd) = in_edges(*i, g); edgesIt != edgesEnd; ++edgesIt) { + properties[source(*edgesIt, g)].available = properties[source(*edgesIt, g)].available && properties[*i].available; + } + } + + // Collect missing & redundant flags + std::set<std::string> missing; + std::set<std::string> redundant; + for(std::list<Vertex>::const_iterator i = sortedDiagnostics.begin(); i != sortedDiagnostics.end(); ++i) { + bool markChildrenCovered = true; + if (properties[*i].alreadyCovered) { + if (properties[*i].have) { + properties[*i].redundant = true; + redundant.insert(properties[*i].name); + } + } + else { + if (properties[*i].available) { + if (!properties[*i].implicitHave && !properties[*i].ignored) { + properties[*i].missing = true; + missing.insert(properties[*i].name); + } + } + else { + markChildrenCovered = false; + } + } + if (markChildrenCovered) { + graph_traits<Graph>::adjacency_iterator adjacentIt, adjacentEnd; + for (tie(adjacentIt, adjacentEnd) = adjacent_vertices(*i, g); adjacentIt != adjacentEnd; ++adjacentIt) { + properties[*adjacentIt].alreadyCovered = true; + } + } + } + + // Write information + if (!missing.empty()) { + std::cout << "Missing diagnostic flags: "; + for(std::set<std::string>::const_iterator i = missing.begin(); i != missing.end(); ++i) { + std::cout << "-W" << *i << " "; + } + std::cout<< std::endl; + } + + if (!redundant.empty()) { + std::cout << "Redundant diagnostic flags: "; + for(std::set<std::string>::const_iterator i = redundant.begin(); i != redundant.end(); ++i) { + std::cout << "-W" << *i << " "; + } + std::cout<< std::endl; + } + + // Write graphviz file + if (!outputDir.empty()) { + std::ofstream f((outputDir + "clang-diagnostics-overview.dot").c_str()); + write_graphviz(f, g, GraphVizLabelWriter(properties)); + f.close(); + } + + return 0; +} diff --git a/BuildTools/CLang/SConscript b/BuildTools/CLang/SConscript new file mode 100644 index 0000000..850c35c --- /dev/null +++ b/BuildTools/CLang/SConscript @@ -0,0 +1,15 @@ +Import("env") + +#myenv = Environment() +#myenv.Append(CPPPATH = ["."]) +#myenv.Program("CLangDiagnosticsFlagsTool", ["CLangDiagnosticsFlagsTool.cpp"]) +# +#disabledDiagnostics = ["-wunreachable-code", "-wunused-macros", "-wmissing-noreturn", "-wlong-long", "-wcast-align", "-wglobal-constructors", "-wmissing-prototypes", "-wpadded", "-wshadow"] +#clangDiagnosticsFlagsToolCommand = "BuildTools/CLang/CLangDiagnosticsFlagsTool -O" + env.Dir(".").abspath + " " + " ".join(disabledDiagnostics) + " " +#clangDiagnosticsFlagsToolCommand += " ".join([flag for flag in env["CXXFLAGS"] if flag.startswith("-W")]) +#clangDiagnosticsFlagsToolCommand += "\n" +#clangDiagnosticsFlagsToolCommand += "dot -Tpng " + env.Dir(".").abspath + "/clang-diagnostics-overview.dot > " + env.Dir(".").abspath + "/clang-diagnostics-overview.png\n" +#v = env.WriteVal("#/BuildTools/CLang/CLangDiagnosticsFlagsTool.sh", env.Value(clangDiagnosticsFlagsToolCommand)) +#env.AddPostAction(v, Chmod(v[0], 0755)) +# +# diff --git a/BuildTools/CheckHeaders.py b/BuildTools/CheckHeaders.py new file mode 100755 index 0000000..73f49db --- /dev/null +++ b/BuildTools/CheckHeaders.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +import os, sys + +foundBadHeaders = False + +for (path, dirs, files) in os.walk(".") : + if "3rdParty" in path or ".sconf" in path or ".framework" in path : + continue + if not "Swiften" in path : + continue + + for filename in [os.path.join(path, file) for file in files if file.endswith(".h")] : + file = open(filename, "r") + for line in file.readlines() : + for include in ["iostream", "algorithm", "cassert", "boost/bind.hpp", "boost/filesystem.hpp", "Base/foreach.h", "Base/Log.h", "boost/date_time/date_time.hpp", "boost/filesystem/filesystem.hpp"] : + if "#include" in line and include in line and not "Base/Log" in filename : + print "Found " + include + " include in " + filename + foundBadHeaders = True + +sys.exit(foundBadHeaders) diff --git a/BuildTools/CheckTabs.py b/BuildTools/CheckTabs.py index 6074a66..c069140 100755 --- a/BuildTools/CheckTabs.py +++ b/BuildTools/CheckTabs.py @@ -5,7 +5,7 @@ import os, sys foundExpandedTabs = False for (path, dirs, files) in os.walk(".") : - if not "3rdParty" in path and not ".sconf" in path and not ".framework" in path : + if not "3rdParty" in path and not ".sconf" in path and not ".framework" in path and not path.startswith("build") : for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file] : file = open(filename, "r") contents = [] diff --git a/BuildTools/Copyrighter.py b/BuildTools/Copyrighter.py index a768f0d..b20a786 100755 --- a/BuildTools/Copyrighter.py +++ b/BuildTools/Copyrighter.py @@ -134,9 +134,9 @@ if sys.argv[1] == "check-copyright" : elif sys.argv[1] == "check-all-copyrights" : ok = True for (path, dirs, files) in os.walk(".") : - if "3rdParty" in path or ".sconf" in path or "Swift.app" in path : + if "3rdParty" in path or ".sconf" in path or "Swift.app" in path or path.startswith("build") : continue - for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file and not "Version.h" in file and not "swiften-config.h" in file] : + for filename in [os.path.join(path, file) for file in files if (file.endswith(".cpp") or file.endswith(".h")) and not "ui_" in file and not "moc_" in file and not "qrc_" in file and not "BuildVersion.h" in file and not "Swiften.h" in file and not "Version.h" in file and not "swiften-config.h" in file and not "linit.cpp" in file ] : ok &= check_copyright(filename) if not ok : sys.exit(-1) diff --git a/BuildTools/Cppcheck.sh b/BuildTools/Cppcheck.sh new file mode 100755 index 0000000..7b6a33b --- /dev/null +++ b/BuildTools/Cppcheck.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +cppcheck $@ \ + --enable=all \ + --inline-suppr \ + --suppress=postfixOperator:3rdParty/hippomocks.h \ + --suppress=stlSize:3rdParty/hippomocks.h \ + --suppress=noConstructor \ + --suppress=publicAllocationError:Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp \ + -i 3rdParty -i .git -i .sconf_temp \ + -i Swiftob/linit.cpp \ + -i Swift/QtUI/EventViewer/main.cpp \ + -i Swift/QtUI/ApplicationTest \ + -i Swift/QtUI/ChatView/main.cpp \ + -i Swift/QtUI/Roster/main.cpp \ + -i Swift/QtUI/NotifierTest/NotifierTest.cpp \ + \ + -I . \ + -I Swift/QtUI \ + . diff --git a/BuildTools/SCons/SConscript.boot b/BuildTools/SCons/SConscript.boot new file mode 100644 index 0000000..7148f6e --- /dev/null +++ b/BuildTools/SCons/SConscript.boot @@ -0,0 +1,299 @@ +import sys, os, re, platform, hashlib +sys.path.append(Dir("#/BuildTools/SCons").abspath) + +################################################################################ +# Build variables +################################################################################ + +vars = Variables(os.path.join(Dir("#").abspath, "config.py")) +vars.Add('cc', "C compiler") +vars.Add('cxx', "C++ compiler") +vars.Add('ccflags', "Extra C(++) compiler flags") +vars.Add('link', "Linker") +vars.Add('linkflags', "Extra linker flags") +vars.Add(BoolVariable("ccache", "Use CCache", "no")) +vars.Add(BoolVariable("distcc", "Use DistCC", "no")) +vars.Add('distcc_hosts', "DistCC hosts (overrides DISTCC_HOSTS)") +vars.Add(EnumVariable("test", "Compile and run tests", "none", ["none", "all", "unit", "system"])) +vars.Add(BoolVariable("optimize", "Compile with optimizations turned on", "no")) +vars.Add(BoolVariable("debug", "Compile with debug information", "yes")) +vars.Add(BoolVariable("allow_warnings", "Allow compilation warnings during compilation", "yes")) +vars.Add(BoolVariable("assertions", "Compile with assertions", "yes")) +vars.Add(BoolVariable("max_jobs", "Build with maximum number of parallel jobs", "no")) +vars.Add(EnumVariable("target", "Choose a target platform for compilation", "native", ["native", "iphone-simulator", "iphone-device", "xcode"])) +vars.Add(BoolVariable("swift_mobile", "Build mobile Swift", "no")) +if os.name != "nt" : + vars.Add(BoolVariable("coverage", "Compile with coverage information", "no")) +if os.name == "posix" : + vars.Add(BoolVariable("valgrind", "Run tests with valgrind", "no")) +if os.name == "mac" or (os.name == "posix" and os.uname()[0] == "Darwin"): + vars.Add(BoolVariable("universal", "Create universal binaries", "no")) + vars.Add(BoolVariable("mac105", "Link against the 10.5 frameworks", "no")) +if os.name == "nt" : + vars.Add(PathVariable("vcredist", "MSVC redistributable dir", "", PathVariable.PathAccept)) +if os.name == "nt" : + vars.Add(PackageVariable("bonjour", "Bonjour SDK location", "yes")) +vars.Add(PackageVariable("openssl", "OpenSSL location", "yes")) +vars.Add(PathVariable("boost_includedir", "Boost headers location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("boost_libdir", "Boost library location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("expat_includedir", "Expat headers location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("expat_libdir", "Expat library location", None, PathVariable.PathAccept)) +vars.Add("expat_libname", "Expat library name", "libexpat" if os.name == "nt" else "expat") +vars.Add(PathVariable("libidn_includedir", "LibIDN headers location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("libidn_libdir", "LibIDN library location", None, PathVariable.PathAccept)) +vars.Add("libidn_libname", "LibIDN library name", "libidn" if os.name == "nt" else "idn") +vars.Add(PathVariable("sqlite_includedir", "SQLite headers location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("sqlite_libdir", "SQLite library location", None, PathVariable.PathAccept)) +vars.Add("sqlite_libname", "SQLite library name", "libsqlite3" if os.name == "nt" else "sqlite3") +vars.Add(PathVariable("avahi_includedir", "Avahi headers location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("avahi_libdir", "Avahi library location", None, PathVariable.PathAccept)) +vars.Add(PathVariable("qt", "Qt location", "", PathVariable.PathAccept)) +vars.Add(PathVariable("docbook_xml", "DocBook XML", None, PathVariable.PathAccept)) +vars.Add(PathVariable("docbook_xsl", "DocBook XSL", None, PathVariable.PathAccept)) +vars.Add(BoolVariable("build_examples", "Build example programs", "yes")) +vars.Add(BoolVariable("enable_variants", "Build in a separate dir under build/, depending on compile flags", "no")) +vars.Add(BoolVariable("experimental", "Build experimental features", "no")) + +################################################################################ +# Set up default build & configure environment +################################################################################ + +env = Environment(CPPPATH = ["#"], ENV = { + 'PATH' : os.environ['PATH'], + 'LD_LIBRARY_PATH' : os.environ.get("LD_LIBRARY_PATH", ""), + }, variables = vars) + +Help(vars.GenerateHelpText(env)) + +# Default environment variables +env["PLATFORM_FLAGS"] = {} + +# Default custom tools +env.Tool("Test", toolpath = ["#/BuildTools/SCons/Tools"]) +env.Tool("WriteVal", toolpath = ["#/BuildTools/SCons/Tools"]) +env.Tool("BuildVersion", toolpath = ["#/BuildTools/SCons/Tools"]) +env.Tool("Flags", toolpath = ["#/BuildTools/SCons/Tools"]) +if env["PLATFORM"] == "darwin" : + env.Tool("Nib", toolpath = ["#/BuildTools/SCons/Tools"]) + env.Tool("AppBundle", toolpath = ["#/BuildTools/SCons/Tools"]) +if env["PLATFORM"] == "win32" : + env.Tool("WindowsBundle", toolpath = ["#/BuildTools/SCons/Tools"]) + #So we don't need to escalate with UAC + if "TMP" in os.environ.keys() : + env['ENV']['TMP'] = os.environ['TMP'] +env.Tool("SLOCCount", toolpath = ["#/BuildTools/SCons/Tools"]) + +# Max out the number of jobs +if env["max_jobs"] : + try : + import multiprocessing + SetOption("num_jobs", multiprocessing.cpu_count()) + except NotImplementedError : + pass + except ImportError : + pass + +# Default compiler flags +if env.get("distcc", False) : + env["ENV"]["HOME"] = os.environ["HOME"] + env["ENV"]["DISTCC_HOSTS"] = os.environ.get("DISTCC_HOSTS", "") + if "distcc_hosts" in env : + env["ENV"]["DISTCC_HOSTS"] = env["distcc_hosts"] + env["CC"] = "distcc gcc" + env["CXX"] = "distcc g++" +if "cc" in env : + env["CC"] = env["cc"] +if "cxx" in env : + env["CXX"] = env["cxx"] +ccflags = env.get("ccflags", []) +if isinstance(ccflags, str) : + # FIXME: Make the splitting more robust + env["CCFLAGS"] = ccflags.split(" ") +else : + env["CCFLAGS"] = ccflags +if "link" in env : + env["SHLINK"] = env["link"] + env["LINK"] = env["link"] +env["LINKFLAGS"] = env.get("linkflags", []) +# This isn't a real flag (yet) AFAIK. Be sure to append it to the CXXFLAGS +# where you need it +env["OBJCCFLAGS"] = [] +if env["optimize"] : + if env["PLATFORM"] == "win32" : + env.Append(CCFLAGS = ["/O2", "/GL"]) + env.Append(LINKFLAGS = ["/INCREMENTAL:NO", "/LTCG"]) + else : + env.Append(CCFLAGS = ["-O2"]) + +if env["target"] == "xcode" and os.environ["CONFIGURATION"] == "Release" : + env.Append(CCFLAGS = ["-Os"]) + +if env["debug"] : + if env["PLATFORM"] == "win32" : + env.Append(CCFLAGS = ["/Zi", "/MDd"]) + env.Append(LINKFLAGS = ["/DEBUG"]) + else : + env.Append(CCFLAGS = ["-g"]) +elif env["PLATFORM"] == "win32" : + env.Append(CCFLAGS = ["/MD"]) + +if env.get("universal", 0) : + assert(env["PLATFORM"] == "darwin") + env.Append(CCFLAGS = [ + "-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk", + "-arch", "i386", + "-arch", "ppc"]) + env.Append(LINKFLAGS = [ + "-mmacosx-version-min=10.4", + "-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk", + "-arch", "i386", + "-arch", "ppc"]) + +if env.get("mac105", 0) : + assert(env["PLATFORM"] == "darwin") + env.Append(CCFLAGS = [ + "-isysroot", "/Developer/SDKs/MacOSX10.5.sdk", + "-arch", "i386"]) + env.Append(LINKFLAGS = [ + "-mmacosx-version-min=10.5", + "-isysroot", "/Developer/SDKs/MacOSX10.5.sdk", + "-arch", "i386"]) + env.Append(FRAMEWORKS = ["Security"]) + +if not env["assertions"] : + env.Append(CPPDEFINES = ["NDEBUG"]) + +if env["experimental"] : + env.Append(CPPDEFINES = ["SWIFT_EXPERIMENTAL_FT"]) + +# If we build shared libs on AMD64, we need -fPIC. +# This should have no performance impact om AMD64 +if env["PLATFORM"] == "posix" and platform.machine() == "x86_64" : + env.Append(CCFLAGS = ["-fPIC"]) + +# Warnings +if env["PLATFORM"] == "win32" : + # TODO: Find the ideal set of warnings + #env.Append(CCFLAGS = ["/Wall"]) + pass +else : + env.Append(CXXFLAGS = ["-Wextra", "-Wall", "-Wnon-virtual-dtor", "-Wundef", "-Wold-style-cast", "-Wno-long-long", "-Woverloaded-virtual", "-Wfloat-equal", "-Wredundant-decls"]) + if not env.get("allow_warnings", False) : + env.Append(CXXFLAGS = ["-Werror"]) + gccVersion = env.get("CCVERSION", "0.0.0").split(".") + if gccVersion >= ["4", "5", "0"] : + env.Append(CXXFLAGS = ["-Wlogical-op"]) + if "clang" in env["CC"] : + env.Append(CXXFLAGS = ["-W#warnings", "-Wc++0x-compat", "-Waddress-of-temporary", "-Wambiguous-member-template", "-Warray-bounds", "-Watomic-properties", "-Wbind-to-temporary-copy", "-Wbuiltin-macro-redefined", "-Wc++-compat", "-Wc++0x-extensions", "-Wcomments", "-Wconditional-uninitialized", "-Wconstant-logical-operand", "-Wdeclaration-after-statement", "-Wdeprecated", "-Wdeprecated-implementations", "-Wdeprecated-writable-strings", "-Wduplicate-method-arg", "-Wempty-body", "-Wendif-labels", "-Wenum-compare", "-Wformat=2", "-Wfour-char-constants", "-Wgnu", "-Wincomplete-implementation", "-Winvalid-noreturn", "-Winvalid-offsetof", "-Winvalid-token-paste", "-Wlocal-type-template-args", "-Wmethod-signatures", "-Wmicrosoft", "-Wmissing-declarations", "-Wnon-pod-varargs", "-Wnonfragile-abi2", "-Wnull-dereference", "-Wout-of-line-declaration", "-Woverlength-strings", "-Wpacked", "-Wpointer-arith", "-Wpointer-sign", "-Wprotocol", "-Wreadonly-setter-attrs", "-Wselector", "-Wshift-overflow", "-Wshift-sign-overflow", "-Wstrict-selector-match", "-Wsuper-class-method-mismatch", "-Wtautological-compare", "-Wtypedef-redefinition", "-Wundeclared-selector", "-Wunknown-warning-option", "-Wunnamed-type-template-args", "-Wunused-exception-parameter", "-Wunused-member-function", "-Wused-but-marked-unused", "-Wvariadic-macros"]) +# To enable: +# "-Wheader-hygiene" +# "-Wnon-gcc", +# "-Wweak-vtables", +# "-Wlarge-by-value-copy", + +if env.get("coverage", 0) : + assert(env["PLATFORM"] != "win32") + env.Append(CCFLAGS = ["-fprofile-arcs", "-ftest-coverage"]) + env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"]) + +if env["PLATFORM"] == "win32" : + env.Append(LIBS = ["user32", "crypt32", "dnsapi", "iphlpapi", "ws2_32", "wsock32", "Advapi32"]) + env.Append(CCFLAGS = ["/EHsc", "/nologo"]) + # FIXME: We should find a decent solution for MSVS 10 + if int(env["MSVS_VERSION"].split(".")[0]) < 10 : + env["LINKCOM"] = [env["LINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1'] + env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2'] + +if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode"] : + env.Append(FRAMEWORKS = ["IOKit", "AppKit", "SystemConfiguration"]) + +# Testing +env["TEST_TYPE"] = env["test"] +if "check" in ARGUMENTS : + env["TEST_TYPE"] = "unit" +env["checker_report"] = ARGUMENTS.get("checker_report", False) +env["TEST"] = (env["TEST_TYPE"] != "none") or env.GetOption("clean") +if env.get("valgrind", 0) : + env["TEST_RUNNER"] = "valgrind --suppressions=QA/valgrind.supp -q --leak-check=full --track-origins=yes " +env["TEST_IGNORE_RESULT"] = "ignore_test_result" in ARGUMENTS +env["TEST_CREATE_LIBRARIES"] = "create_test_libraries" in ARGUMENTS + +# Packaging +env["DIST"] = "dist" in ARGUMENTS or env.GetOption("clean") +for path in ["SWIFT_INSTALLDIR", "SWIFTEN_INSTALLDIR"] : + if ARGUMENTS.get(path, "") : + if os.path.isabs(ARGUMENTS[path]) : + env[path] = Dir(ARGUMENTS[path]).abspath + else : + env[path] = Dir("#/" + ARGUMENTS[path]).abspath + +################################################################################ +# XCode / iPhone / ... +################################################################################ + +target = env["target"] +if target in ["iphone-device", "iphone-simulator", "xcode"] : + # Extract/initialize all the information we need + if target == "xcode" : + # Get the information from the XCode environment + env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = os.environ["PLATFORM_DEVELOPER_BIN_DIR"] + env["XCODE_SDKROOT"] = os.environ["SDKROOT"] + env["XCODE_ARCH_FLAGS"] = sum([["-arch", arch] for arch in os.environ["ARCHS"].split(" ")], []) + # Usae absolute path sources so Xcode can highlight compilation errors in swiften + env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM ${SOURCES.abspath}' + else : + # Hard code values + env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin" + if target == "iphone-device": + env["XCODE_ARCH_FLAGS"] = ["-arch", "armv6", "-arch", "armv7"] + sdkPart = "iPhoneOS" + else : + env["XCODE_ARCH_FLAGS"] = ["-arch", "i386"] + sdkPart = "iPhoneSimulator" + sdkVer = "4.3" + env["XCODE_SDKROOT"] = "/Developer/Platforms/" + sdkPart + ".platform/Developer/SDKs/" + sdkPart + sdkVer + ".sdk" + + # Set the build flags + env["CC"] = "$XCODE_PLATFORM_DEVELOPER_BIN_DIR/gcc" + env["CXX"] = "$XCODE_PLATFORM_DEVELOPER_BIN_DIR/g++" + env["OBJCCFLAGS"] = ["-fobjc-abi-version=2", "-fobjc-legacy-dispatch"] + env["LD"] = env["CC"] + env.Append(CCFLAGS = env["XCODE_ARCH_FLAGS"] + ["-fvisibility=hidden"]) + env.Append(LINKFLAGS = env["XCODE_ARCH_FLAGS"]) + env.Append(CPPFLAGS = ["-isysroot", "$XCODE_SDKROOT"]) + env.Append(FRAMEWORKS = ["CoreFoundation", "Foundation", "UIKit", "CoreGraphics"]) + env.Append(LINKFLAGS = env["XCODE_ARCH_FLAGS"] + ["-isysroot", "$XCODE_SDKROOT", "-L\"$XCODE_SDKROOT/usr/lib\"", "-F\"$XCODE_SDKROOT/System/Library/Frameworks\"", "-F\"$XCODE_SDKROOT/System/Library/PrivateFrameworks\""]) + # Bit of a hack, because BOOST doesn't know the endianness for ARM + env.Append(CPPDEFINES = ["_LITTLE_ENDIAN"]) + +# CCache +if env.get("ccache", False) : + env["ENV"]["HOME"] = os.environ["HOME"] + for var in os.environ : + if var.startswith("CCACHE_") : + env["ENV"][var] = os.environ[var] + if env.get("CC", "") != "" : + env["CC"] = "ccache " + env["CC"] + else : + env["CC"] = "ccache gcc" + if env.get("CXX", "") != "" : + env["CXX"] = "ccache " + env["CXX"] + else : + env["CC"] = "ccache g++" + +conf_env = env.Clone() + +Export("env") +Export("conf_env") + +variant = "" +if env["enable_variants"] : + fingerprint = ",".join([flag for flag in env["CXXFLAGS"] + env["CCFLAGS"] if not flag.startswith("-W") and not flag.startswith("-fvisibility")]) + variant = "build/" + fingerprint + if not os.path.exists(Dir("#/build").abspath) : + os.mkdir(Dir("#/build").abspath) + if os.path.exists(Dir("#/build/current").abspath) : + os.unlink(Dir("#/build/current").abspath) + os.symlink(os.path.basename(variant), Dir("#/build/current").abspath) + +Return("variant") diff --git a/BuildTools/SCons/SConstruct b/BuildTools/SCons/SConstruct index 7c172f4..448bdbd 100644 --- a/BuildTools/SCons/SConstruct +++ b/BuildTools/SCons/SConstruct @@ -1,263 +1,17 @@ import sys, os, re, platform -sys.path.append(Dir("BuildTools/SCons").abspath) import SCons.SConf -################################################################################ -# Build variables -################################################################################ - -vars = Variables(os.path.join(Dir("#").abspath, "config.py")) -vars.Add('cc', "C compiler") -vars.Add('cxx', "C++ compiler") -vars.Add('ccflags', "Extra C(++) compiler flags") -vars.Add('link', "Linker") -vars.Add('linkflags', "Extra linker flags") -vars.Add(BoolVariable("ccache", "Use CCache", "no")) -vars.Add(BoolVariable("distcc", "Use DistCC", "no")) -vars.Add('distcc_hosts', "DistCC hosts (overrides DISTCC_HOSTS)") -vars.Add(EnumVariable("test", "Compile and run tests", "none", ["none", "all", "unit", "system"])) -vars.Add(BoolVariable("optimize", "Compile with optimizations turned on", "no")) -vars.Add(BoolVariable("debug", "Compile with debug information", "yes")) -vars.Add(BoolVariable("allow_warnings", "Allow compilation warnings during compilation", "yes")) -vars.Add(BoolVariable("max_jobs", "Build with maximum number of parallel jobs", "no")) -vars.Add(EnumVariable("target", "Choose a target platform for compilation", "native", ["native", "iphone-simulator", "iphone-device", "xcode"])) -vars.Add(BoolVariable("swift_mobile", "Build mobile Swift", "no")) -if os.name != "nt" : - vars.Add(BoolVariable("coverage", "Compile with coverage information", "no")) -if os.name == "posix" : - vars.Add(BoolVariable("valgrind", "Run tests with valgrind", "no")) -if os.name == "mac" or (os.name == "posix" and os.uname()[0] == "Darwin"): - vars.Add(BoolVariable("universal", "Create universal binaries", "no")) - vars.Add(BoolVariable("mac105", "Link against the 10.5 frameworks", "no")) -if os.name == "nt" : - vars.Add(PathVariable("vcredist", "MSVC redistributable dir", "", PathVariable.PathAccept)) -if os.name == "nt" : - vars.Add(PackageVariable("bonjour", "Bonjour SDK location", "yes")) -vars.Add(PackageVariable("openssl", "OpenSSL location", "yes")) -vars.Add(PathVariable("boost_includedir", "Boost headers location", None, PathVariable.PathAccept)) -vars.Add(PathVariable("boost_libdir", "Boost library location", None, PathVariable.PathAccept)) -vars.Add(PathVariable("expat_includedir", "Expat headers location", None, PathVariable.PathAccept)) -vars.Add(PathVariable("expat_libdir", "Expat library location", None, PathVariable.PathAccept)) -vars.Add("expat_libname", "Expat library name", "libexpat" if os.name == "nt" else "expat") -vars.Add(PathVariable("libidn_includedir", "LibIDN headers location", None, PathVariable.PathAccept)) -vars.Add(PathVariable("libidn_libdir", "LibIDN library location", None, PathVariable.PathAccept)) -vars.Add("libidn_libname", "LibIDN library name", "libidn" if os.name == "nt" else "idn") -vars.Add(PathVariable("avahi_includedir", "Avahi headers location", None, PathVariable.PathAccept)) -vars.Add(PathVariable("avahi_libdir", "Avahi library location", None, PathVariable.PathAccept)) -vars.Add(PathVariable("qt", "Qt location", "", PathVariable.PathAccept)) -vars.Add(PathVariable("docbook_xml", "DocBook XML", None, PathVariable.PathAccept)) -vars.Add(PathVariable("docbook_xsl", "DocBook XSL", None, PathVariable.PathAccept)) - -################################################################################ -# Set up default build & configure environment -################################################################################ +Import("env", "conf_env") -env = Environment(CPPPATH = ["#"], ENV = { - 'PATH' : os.environ['PATH'], - 'LD_LIBRARY_PATH' : os.environ.get("LD_LIBRARY_PATH", ""), - }, variables = vars) - -Help(vars.GenerateHelpText(env)) - -# Default environment variables -env["PLATFORM_FLAGS"] = {} - -# Default custom tools -env.Tool("Test", toolpath = ["#/BuildTools/SCons/Tools"]) -env.Tool("WriteVal", toolpath = ["#/BuildTools/SCons/Tools"]) -env.Tool("BuildVersion", toolpath = ["#/BuildTools/SCons/Tools"]) -env.Tool("Flags", toolpath = ["#/BuildTools/SCons/Tools"]) -if env["PLATFORM"] == "darwin" : - env.Tool("Nib", toolpath = ["#/BuildTools/SCons/Tools"]) - env.Tool("AppBundle", toolpath = ["#/BuildTools/SCons/Tools"]) -if env["PLATFORM"] == "win32" : - env.Tool("WindowsBundle", toolpath = ["#/BuildTools/SCons/Tools"]) - #So we don't need to escalate with UAC - if "TMP" in os.environ.keys() : - env['ENV']['TMP'] = os.environ['TMP'] -env.Tool("SLOCCount", toolpath = ["#/BuildTools/SCons/Tools"]) +root = Dir("../..").abspath # Override SConscript to handle tests oldSConscript = SConscript def SConscript(*arguments, **keywords) : - if not keywords.get("test_only", False) or env["TEST"] : - return apply(oldSConscript, arguments, keywords) + if not keywords.get("test_only", False) or env["TEST"] : + return apply(oldSConscript, arguments, keywords) +env.SConscript = SConscript -# Max out the number of jobs -if env["max_jobs"] : - try : - import multiprocessing - SetOption("num_jobs", multiprocessing.cpu_count()) - except NotImplementedError : - pass - -# Default compiler flags -if env.get("distcc", False) : - env["ENV"]["HOME"] = os.environ["HOME"] - env["ENV"]["DISTCC_HOSTS"] = os.environ.get("DISTCC_HOSTS", "") - if "distcc_hosts" in env : - env["ENV"]["DISTCC_HOSTS"] = env["distcc_hosts"] - env["CC"] = "distcc gcc" - env["CXX"] = "distcc g++" -if env.get("ccache", False) : - env["ENV"]["HOME"] = os.environ["HOME"] - for var in os.environ : - if var.startswith("CCACHE_") : - env["ENV"][var] = os.environ[var] - env["CC"] = "ccache gcc" - env["CXX"] = "ccache g++" -if "cc" in env : - env["CC"] = env["cc"] -if "cxx" in env : - env["CXX"] = env["cxx"] -ccflags = env.get("ccflags", []) -if isinstance(ccflags, str) : - # FIXME: Make the splitting more robust - env["CCFLAGS"] = ccflags.split(" ") -else : - env["CCFLAGS"] = ccflags -if "link" in env : - env["SHLINK"] = env["link"] - env["LINK"] = env["link"] -env["LINKFLAGS"] = env.get("linkflags", []) -# This isn't a real flag (yet) AFAIK. Be sure to append it to the CXXFLAGS -# where you need it -env["OBJCCFLAGS"] = [] -if env["optimize"] : - if env["PLATFORM"] == "win32" : - env.Append(CCFLAGS = ["/O2", "/GL"]) - env.Append(LINKFLAGS = ["/INCREMENTAL:NO", "/LTCG"]) - else : - env.Append(CCFLAGS = ["-O2"]) - -if env["debug"] : - if env["PLATFORM"] == "win32" : - env.Append(CCFLAGS = ["/Zi", "/MDd"]) - env.Append(LINKFLAGS = ["/DEBUG"]) - else : - env.Append(CCFLAGS = ["-g"]) -elif env["PLATFORM"] == "win32" : - env.Append(CCFLAGS = ["/MD"]) - -if env.get("universal", 0) : - assert(env["PLATFORM"] == "darwin") - env.Append(CCFLAGS = [ - "-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk", - "-arch", "i386", - "-arch", "ppc"]) - env.Append(LINKFLAGS = [ - "-mmacosx-version-min=10.4", - "-isysroot", "/Developer/SDKs/MacOSX10.4u.sdk", - "-arch", "i386", - "-arch", "ppc"]) - -if env.get("mac105", 0) : - assert(env["PLATFORM"] == "darwin") - env.Append(CCFLAGS = [ - "-isysroot", "/Developer/SDKs/MacOSX10.5.sdk", - "-arch", "i386"]) - env.Append(LINKFLAGS = [ - "-mmacosx-version-min=10.5", - "-isysroot", "/Developer/SDKs/MacOSX10.5.sdk", - "-arch", "i386"]) - env.Append(FRAMEWORKS = ["Security"]) - -# If we build shared libs on AMD64, we need -fPIC. -# This should have no performance impact om AMD64 -if env["PLATFORM"] == "posix" and platform.machine() == "x86_64" : - env.Append(CCFLAGS = ["-fPIC"]) - -# Warnings -if env["PLATFORM"] == "win32" : - # TODO: Find the ideal set of warnings - #env.Append(CCFLAGS = ["/Wall"]) - pass -else : - env.Append(CXXFLAGS = ["-Wextra", "-Wall", "-Wnon-virtual-dtor", "-Wundef", "-Wold-style-cast", "-Wno-long-long", "-Woverloaded-virtual", "-Wfloat-equal", "-Wredundant-decls"]) - if not env.get("allow_warnings", False) : - env.Append(CXXFLAGS = ["-Werror"]) - gccVersion = env.get("CCVERSION", "0.0.0").split(".") - if gccVersion >= ["4", "5", "0"] : - env.Append(CCFLAGS = ["-Wlogical-op"]) - -if env.get("coverage", 0) : - assert(env["PLATFORM"] != "win32") - env.Append(CCFLAGS = ["-fprofile-arcs", "-ftest-coverage"]) - env.Append(LINKFLAGS = ["-fprofile-arcs", "-ftest-coverage"]) - -if env["PLATFORM"] == "win32" : - env.Append(LIBS = ["user32", "crypt32", "dnsapi", "ws2_32", "wsock32"]) - env.Append(CCFLAGS = ["/EHsc", "/nologo"]) - # FIXME: We should find a decent solution for MSVS 10 - if int(env["MSVS_VERSION"].split(".")[0]) < 10 : - env["LINKCOM"] = [env["LINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;1'] - env["SHLINKCOM"] = [env["SHLINKCOM"], 'mt.exe -nologo -manifest ${TARGET}.manifest -outputresource:$TARGET;2'] - -if env["PLATFORM"] == "darwin" and not env["target"] in ["iphone-device", "iphone-simulator", "xcode"] : - env.Append(FRAMEWORKS = ["IOKit", "AppKit"]) - -# Testing -env["TEST_TYPE"] = env["test"] -if "check" in ARGUMENTS : - env["TEST_TYPE"] = "unit" -env["checker_report"] = ARGUMENTS.get("checker_report", False) -env["TEST"] = (env["TEST_TYPE"] != "none") or env.GetOption("clean") -if env.get("valgrind", 0) : - env["TEST_RUNNER"] = "valgrind --suppressions=QA/valgrind.supp -q --leak-check=full --track-origins=yes " -env["TEST_IGNORE_RESULT"] = "ignore_test_result" in ARGUMENTS - -# Packaging -env["DIST"] = "dist" in ARGUMENTS or env.GetOption("clean") -for path in ["SWIFT_INSTALLDIR", "SWIFTEN_INSTALLDIR"] : - if ARGUMENTS.get(path, "") : - if os.path.isabs(ARGUMENTS[path]) : - env[path] = Dir(ARGUMENTS[path]).abspath - else : - env[path] = Dir("#/" + ARGUMENTS[path]).abspath - -################################################################################ -# XCode / iPhone / ... -################################################################################ - -target = env["target"] -if target in ["iphone-device", "iphone-simulator", "xcode"] : - # Extract/initialize all the information we need - if target == "xcode" : - # Get the information from the XCode environment - env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = os.environ["PLATFORM_DEVELOPER_BIN_DIR"] - env["XCODE_SDKROOT"] = os.environ["SDKROOT"] - env["XCODE_ARCH_FLAGS"] = sum([["-arch", arch] for arch in os.environ["ARCHS"].split(" ")], []) - else : - # Hard code values - env["XCODE_PLATFORM_DEVELOPER_BIN_DIR"] = "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin" - if target == "iphone-device": - env["XCODE_ARCH_FLAGS"] = ["-arch", "armv6"] - sdkPart = "iPhoneOS" - else : - env["XCODE_ARCH_FLAGS"] = ["-arch", "i386"] - sdkPart = "iPhoneSimulator" - sdkVer = "4.0" - env["XCODE_SDKROOT"] = "/Developer/Platforms/" + sdkPart + ".platform/Developer/SDKs/" + sdkPart + sdkVer + ".sdk" - - # Set the build flags - env["CC"] = "$XCODE_PLATFORM_DEVELOPER_BIN_DIR/gcc" - env["CXX"] = "$XCODE_PLATFORM_DEVELOPER_BIN_DIR/g++" - env["OBJCCFLAGS"] = ["-fobjc-abi-version=2", "-fobjc-legacy-dispatch"] - env["LD"] = env["CC"] - env.Append(CCFLAGS = env["XCODE_ARCH_FLAGS"]) - env.Append(LINKFLAGS = env["XCODE_ARCH_FLAGS"]) - env.Append(CPPFLAGS = ["-isysroot", "$XCODE_SDKROOT"]) - env.Append(FRAMEWORKS = ["CoreFoundation", "Foundation", "UIKit", "CoreGraphics"]) - env.Append(LINKFLAGS = env["XCODE_ARCH_FLAGS"] + ["-isysroot", "$XCODE_SDKROOT", "-L\"$XCODE_SDKROOT/usr/lib\"", "-F\"$XCODE_SDKROOT/System/Library/Frameworks\"", "-F\"$XCODE_SDKROOT/System/Library/PrivateFrameworks\""]) - # Bit of a hack, because BOOST doesn't know the endianness for ARM - env.Append(CPPDEFINES = ["_LITTLE_ENDIAN"]) - -conf_env = env.Clone() - -Export("env") -Export("conf_env") - - ################################################################################ # Extend the default build environment (not affecting the configure env) # @@ -317,9 +71,32 @@ def checkObjCHeader(context, header) : # Platform configuration ################################################################################ +env.Append(CPPPATH = [root]) + if ARGUMENTS.get("force-configure", 0) : SCons.SConf.SetCacheMode("force") +def CheckPKG(context, name): + context.Message( 'Checking for package %s... ' % name ) + ret = context.TryAction('pkg-config --exists \'%s\'' % name)[0] + context.Result( ret ) + return ret + +def CheckVersion(context, library, version, define, header, value) : + context.Message("Checking " + library + " version (>= " + version + ") ...") + ret = context.TryRun(""" +#include <%(header)s> +#include <stdio.h> + +int main(int argc, char* argv[]) { + printf("%%d\\n", %(define)s); + return 0; +} +""" % { "header" : header, "define": define }, ".c") + ok = ret[0] and int(ret[1]) >= value + context.Result(ok) + return ok + conf = Configure(conf_env) if not conf.CheckCXX() or not conf.CheckCC() : @@ -404,7 +181,7 @@ env["HAVE_XSS"] = 0 if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" : xss_flags = { "LIBPATH": ["/usr/X11R6/lib"], - "LIBS": ["X11", "Xss"] + "LIBS": ["Xss"] } xss_env = conf_env.Clone() xss_env.MergeFlags(xss_flags) @@ -414,6 +191,31 @@ if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" : env["XSS_FLAGS"] = xss_flags conf.Finish() +# GConf +env["HAVE_GCONF"] = 0 +if env["PLATFORM"] != "win32" and env["PLATFORM"] != "darwin" : + gconf_env = conf_env.Clone() + conf = Configure(gconf_env, custom_tests = {"CheckPKG": CheckPKG}) + if conf.CheckPKG("gconf-2.0") : + gconf_bare_env = Environment() + gconf_bare_env.ParseConfig('pkg-config --cflags gconf-2.0 gobject-2.0 --libs gconf-2.0 gobject-2.0') + gconf_flags = { + "LIBS": gconf_bare_env["LIBS"], + "CCFLAGS": gconf_bare_env["CCFLAGS"], + "CPPPATH": gconf_bare_env["CPPPATH"], + "CPPDEFINES": gconf_bare_env.get("CPPDEFINES", []), + } + gconf_env.MergeFlags(gconf_flags) + if conf.CheckCHeader("gconf/gconf-client.h") and conf.CheckLib("gconf-2") : + env["HAVE_GCONF"] = 1 + env["GCONF_FLAGS"] = { + "LIBS": gconf_env["LIBS"], + "CCFLAGS": gconf_env["CCFLAGS"], + "CPPPATH": gconf_env["CPPPATH"], + "CPPDEFINES": gconf_env.get("CPPDEFINES", []), + } + conf.Finish() + # Sparkle env["HAVE_SPARKLE"] = 0 if env["PLATFORM"] == "darwin" : @@ -451,8 +253,9 @@ if env["PLATFORM"] == "win32" : env["HAVE_SNARL"] = True # LibXML -conf = Configure(conf_env) +conf = Configure(conf_env, custom_tests = {"CheckVersion": CheckVersion}) if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") : +#and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623) : env["HAVE_LIBXML"] = 1 env["LIBXML_FLAGS"] = { "LIBS": ["xml2"] } conf.Finish() @@ -460,8 +263,9 @@ conf.Finish() if not env.get("HAVE_LIBXML", 0) : libxml_env = conf_env.Clone() libxml_env.Append(CPPPATH = ["/usr/include/libxml2"]) - conf = Configure(libxml_env) + conf = Configure(libxml_env, custom_tests = {"CheckVersion": CheckVersion}) if conf.CheckCHeader("libxml/parser.h") and conf.CheckLib("xml2") : +# and conf.CheckVersion("LibXML", "2.6.23", "LIBXML_VERSION", "libxml/xmlversion.h", 20623): env["HAVE_LIBXML"] = 1 env["LIBXML_FLAGS"] = { "CPPPATH": ["/usr/include/libxml2"], "LIBS": ["xml2"] } conf.Finish() @@ -507,6 +311,47 @@ else : env["LIBIDN_BUNDLED"] = 1 conf.Finish() +# LibMiniUPnPc +if env["experimental"] : + libminiupnpc_conf_env = conf_env.Clone() + conf = Configure(libminiupnpc_conf_env) + if conf.CheckCHeader("miniupnpc.h") and conf.CheckLib(env["libminiupnpc_libname"]) : + print "NOT IMPLEMENTED YET" + else : + env["LIBMINIUPNPC_BUNDLED"] = 1 + conf.Finish() +else : + env["LIBMINIUPNPC_FLAGS"] = {} + +# LibNATPMP +if env["experimental"] : + libnatpmp_conf_env = conf_env.Clone() + conf = Configure(libnatpmp_conf_env) + if conf.CheckCHeader("natpmp.h") and conf.CheckLib(env["libnatpmp_libname"]) : + print "NOT IMPLEMENTED YET" + else : + env["LIBNATPMP_BUNDLED"] = 1 + conf.Finish() +else : + env["LIBNATPMP_FLAGS"] = {} + +# SQLite +#sqlite_conf_env = conf_env.Clone() +#sqlite_flags = {} +#if env.get("sqlite_libdir", None) : +# sqlite_flags["LIBPATH"] = [env["sqlite_libdir"]] +#if env.get("sqlite_includedir", None) : +# sqlite_flags["CPPPATH"] = [env["sqlite_includedir"]] +#sqlite_conf_env.MergeFlags(sqlite_flags) +#conf = Configure(sqlite_conf_env) +#if conf.CheckCHeader("sqlite3.h") and conf.CheckLib(env["sqlite_libname"]) : +# env["HAVE_SQLITE"] = 1 +# env["SQLITE_FLAGS"] = { "LIBS": [env["sqlite_libname"]] } +# env["SQLITE_FLAGS"].update(sqlite_flags) +#else : +# env["SQLITE_BUNDLED"] = 1 +#conf.Finish() + # Lua env["LUA_BUNDLED"] = 1 @@ -558,7 +403,10 @@ if use_openssl and openssl_conf.CheckCHeader("openssl/ssl.h") : env["OPENSSL_FLAGS"]["LIBS"] = ["libeay32MD", "ssleay32MD"] else: env["OPENSSL_FLAGS"]["LIBS"] = ["ssl", "crypto"] -elif target in ("iphone-device", "iphone-simulator", "xcode") : + if env["PLATFORM"] == "darwin" : + if platform.mac_ver()[0].startswith("10.5") : + env["OPENSSL_FLAGS"]["FRAMEWORKS"] = ["Security"] +elif env["target"] in ("iphone-device", "iphone-simulator", "xcode") : env["OPENSSL_BUNDLED"] = True env["HAVE_OPENSSL"] = True else : @@ -621,6 +469,9 @@ if env.Dir("#/.git").exists() : # Project files ################################################################################ +# Build tools +env.SConscript(dirs = ["#/BuildTools/CLang"]) + # Modules modules = [] for dir in os.listdir(Dir("#/3rdParty").abspath) : @@ -642,7 +493,7 @@ for dir in os.listdir(Dir("#").abspath) : env["PROJECTS"] = [m for m in modules if m not in ["Documentation", "QA", "SwifTools"] and not m.startswith("3rdParty")] for stage in ["flags", "build", "test"] : env["SCONS_STAGE"] = stage - SConscript(dirs = map(lambda x : "#/" + x, modules)) + SConscript(dirs = map(lambda x : root + "/" + x, modules)) # SLOCCount if ARGUMENTS.get("sloccount", False) : diff --git a/BuildTools/SCons/Tools/AppBundle.py b/BuildTools/SCons/Tools/AppBundle.py index c271575..6a343f6 100644 --- a/BuildTools/SCons/Tools/AppBundle.py +++ b/BuildTools/SCons/Tools/AppBundle.py @@ -1,7 +1,7 @@ import SCons.Util, os.path def generate(env) : - def createAppBundle(env, bundle, version = "1.0", resources = [], frameworks = [], info = {}) : + def createAppBundle(env, bundle, version = "1.0", resources = [], frameworks = [], info = {}, handlesXMPPURIs = False) : bundleDir = bundle + ".app" bundleContentsDir = bundleDir + "/Contents" resourcesDir = bundleContentsDir + "/Resources" @@ -32,6 +32,18 @@ def generate(env) : for key, value in infoDict.items() : plist += "<key>" + key + "</key>\n" plist += "<string>" + value.encode("utf-8") + "</string>\n" + if handlesXMPPURIs : + plist += """<key>CFBundleURLTypes</key> +<array> + <dict> + <key>CFBundleURLName</key> + <string>XMPP URL</string> + <key>CFBundleURLSchemes</key> + <array> + <string>xmpp</string> + </array> + </dict> +</array>\n""" plist += """</dict> </plist> """ @@ -825,7 +825,11 @@ Swift contains some code contributed under the BSD License, under the following --- START OF BSD LICENSE Copyright (c) 2011, Arnt Gulbrandsen Copyright (c) 2011, Thilo Cestonaro +<<<<<<< HEAD +Copyright (c) 2011, Vlad Voicu +======= Copyright (c) 2011, Jan Kaluza +>>>>>>> swift-1.x All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: diff --git a/Documentation/BuildingOnUnix.txt b/Documentation/BuildingOnUnix.txt index 8de73c8..fa5759e 100644 --- a/Documentation/BuildingOnUnix.txt +++ b/Documentation/BuildingOnUnix.txt @@ -20,6 +20,9 @@ Running tests ------------- - Run ./scons test=unit - for running the unit tests, or - ./scons test=all - for running all tests. + for running the unit tests. + +Installing +---------- +- To install swift in /usr/local, run + ./scons SWIFT_INSTALLDIR=/usr/local /usr/local diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot0x.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot0x.cpp index b4ccc21..11773ae 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot0x.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot0x.cpp @@ -13,25 +13,19 @@ int main(int, char**) { SimpleEventLoop eventLoop; BoostNetworkFactories networkFactories(&eventLoop); - // Initialize the client with the JID and password Client client("echobot@wonderland.lit", "mypass", &networkFactories); - - // When the client is convnected, send out initial presence + client.setAlwaysTrustCertificates(); client.onConnected.connect([&] { - client.sendPresence(Presence::create("Send me a message")); + std::cout << "Connected" << std::endl; }); - - // When the client receives an incoming message, echo it back client.onMessageReceived.connect([&] (Message::ref message) { message->setTo(message->getFrom()); message->setFrom(JID()); client.sendMessage(message); }); - - // Start the client client.connect(); - // Run the event loop to start processing incoming network events eventLoop.run(); + return 0; } diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp index 4736494..8a64b56 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot1.cpp @@ -13,6 +13,7 @@ int main(int, char**) { BoostNetworkFactories networkFactories(&eventLoop); Client client("echobot@wonderland.lit", "mypass", &networkFactories); + client.setAlwaysTrustCertificates(); client.connect(); eventLoop.run(); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp index f431245..deeb852 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot2.cpp @@ -22,6 +22,7 @@ int main(int, char**) { BoostNetworkFactories networkFactories(&eventLoop); client = new Client("echobot@wonderland.lit", "mypass", &networkFactories); + client->setAlwaysTrustCertificates(); client->onConnected.connect(&handleConnected); client->onMessageReceived.connect(bind(&handleMessageReceived, _1)); client->connect(); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp index cd95b91..e3e3560 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot3.cpp @@ -16,6 +16,7 @@ class EchoBot { public: EchoBot(NetworkFactories* networkFactories) { client = new Client("echobot@wonderland.lit", "mypass", networkFactories); + client->setAlwaysTrustCertificates(); client->onConnected.connect(bind(&EchoBot::handleConnected, this)); client->onMessageReceived.connect( bind(&EchoBot::handleMessageReceived, this, _1)); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp index c2f555c..c8d8c84 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot4.cpp @@ -18,6 +18,7 @@ class EchoBot { EchoBot(NetworkFactories* networkFactories) { //... client = new Client("echobot@wonderland.lit", "mypass", networkFactories); + client->setAlwaysTrustCertificates(); client->onConnected.connect(bind(&EchoBot::handleConnected, this)); client->onMessageReceived.connect( bind(&EchoBot::handleMessageReceived, this, _1)); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp index 0b00330..810424c 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot5.cpp @@ -18,6 +18,7 @@ class EchoBot { EchoBot(NetworkFactories* networkFactories) { //... client = new Client("echobot@wonderland.lit", "mypass", networkFactories); + client->setAlwaysTrustCertificates(); client->onConnected.connect(bind(&EchoBot::handleConnected, this)); client->onMessageReceived.connect( bind(&EchoBot::handleMessageReceived, this, _1)); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp index d3587e9..92a2ab6 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoBot6.cpp @@ -23,6 +23,7 @@ class EchoBot { EchoBot(NetworkFactories* networkFactories) { //... client = new Client("echobot@wonderland.lit", "mypass", networkFactories); + client->setAlwaysTrustCertificates(); client->onConnected.connect(bind(&EchoBot::handleConnected, this)); client->onMessageReceived.connect( bind(&EchoBot::handleMessageReceived, this, _1)); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h index 7533a1e..62ea495 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayload.h @@ -8,9 +8,8 @@ #include <Swiften/Swiften.h> -using namespace Swift; //... -class EchoPayload : public Payload { +class EchoPayload : public Swift::Payload { public: EchoPayload() {} diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h index 9cbb795..33a8c41 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadParserFactory.h @@ -9,9 +9,7 @@ #include <Swiften/Swiften.h> #include "EchoPayload.h" -using namespace Swift; - -class EchoPayloadParser : public GenericPayloadParser<EchoPayload> { +class EchoPayloadParser : public Swift::GenericPayloadParser<EchoPayload> { public: EchoPayloadParser() : currentDepth(0) {} @@ -36,7 +34,7 @@ class EchoPayloadParser : public GenericPayloadParser<EchoPayload> { std::string currentText; }; -class EchoPayloadParserFactory : public GenericPayloadParserFactory<EchoPayloadParser> { +class EchoPayloadParserFactory : public Swift::GenericPayloadParserFactory<EchoPayloadParser> { public: EchoPayloadParserFactory() : GenericPayloadParserFactory<EchoPayloadParser>("echo", "http://swift.im/echo") {} diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h index 85e8e67..068113c 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/EchoPayloadSerializer.h @@ -9,9 +9,7 @@ #include <Swiften/Swiften.h> #include "EchoPayload.h" -using namespace Swift; - -class EchoPayloadSerializer : public GenericPayloadSerializer<EchoPayload> { +class EchoPayloadSerializer : public Swift::GenericPayloadSerializer<EchoPayload> { public: std::string serializePayload(boost::shared_ptr<EchoPayload> payload) const { XMLElement element("echo", "http://swift.im/protocol/echo"); diff --git a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript index 1960609..c6349bd 100644 --- a/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript +++ b/Documentation/SwiftenDevelopersGuide/Examples/EchoBot/SConscript @@ -15,11 +15,11 @@ if env["PLATFORM"] == "win32" : if int(env["MSVS_VERSION"].split(".")[0]) >= 10 : cpp0x = True else : - pass -# Disabling C++0x compilation, because older boosts are not compliant yet -# if env["CCVERSION"].split(".") >= ["4", "5", "0"] : -# cpp0x = True -# cpp0x_env.Replace(CXXFLAGS = [flag for flag in env["CXXFLAGS"] if flag != "-Werror"]) -# cpp0x_env.Append(CXXFLAGS = ["-std=c++0x"]) + if env["CCVERSION"].split(".") >= ["4", "5", "0"] : + # Temporarily disabling c++0x mode because of problems with boost::thread + # on some platforms + #cpp0x = True + cpp0x_env.Replace(CXXFLAGS = [flag for flag in env["CXXFLAGS"] if flag != "-Werror"]) + cpp0x_env.Append(CXXFLAGS = ["-std=c++0x"]) if cpp0x : cpp0x_env.Program("EchoBot0x", "EchoBot0x.cpp") diff --git a/Documentation/SwiftenDevelopersGuide/SConscript b/Documentation/SwiftenDevelopersGuide/SConscript index e000ac2..c50641f 100644 --- a/Documentation/SwiftenDevelopersGuide/SConscript +++ b/Documentation/SwiftenDevelopersGuide/SConscript @@ -87,6 +87,7 @@ if "doc" in ARGUMENTS : sources = [] for i in range(1, 7) : sources.append("Examples/EchoBot/EchoBot" + str(i) + ".cpp") +sources.append("Examples/EchoBot/EchoBot0x.cpp") sources += ["Examples/EchoBot/" + i for i in ["EchoPayloadParserFactory.h", "EchoPayloadSerializer.h", "EchoPayload.h", "EchoComponent.cpp"]] for source in sources : env.Command(source + ".xml", source, Action(generateDocBookCode, cmdstr = "$GENCOMSTR")) diff --git a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml index e0daff3..fae79e4 100644 --- a/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml +++ b/Documentation/SwiftenDevelopersGuide/Swiften Developers Guide.xml @@ -94,7 +94,12 @@ <literal>connect()</literal> to instruct the client to connect to the XMPP server with the given credentials. Note that this call returns immediately; it is only when starting the event loop that network - the actual connection process will start. + the actual connection process will start. The call to + <literal>setAlwaysTrustCertificates()</literal> before connecting + avoids checks for certificate validity; this is convenient for + the examples in this guide (because not all servers have trusted + certificates), but for production software, you should + not call this. </para> </sect1> @@ -177,8 +182,20 @@ </para> <para> + If you use a C++ compiler that supports C++0x lambda expressions (such as + GCC 4.5 or Microsoft Visual Studio 2010), you can write this example in a more + concise way, as illustrated in <xref linkend="Example-EchoBot0x"/>. However, + for the remainder of this guide, we will not use this functionality. + </para> + <example id="Example-EchoBot0x"> + <title>EchoBot using C++0x lambda expressions. This is currently only possible with a limited set of C++compilers.</title> + <include xmlns="http://www.w3.org/2001/XInclude" href="Examples/EchoBot/EchoBot0x.cpp.xml" xpointer="xpointer(//programlisting|//calloutlist)"/> + </example> + + <para> Before moving on to the next step, we are going to rearrange our - code a bit, to make it a bit cleaner. Instead of using global + code from <xref linkend="Example-EchoBot2"/> a bit, to make it a bit cleaner. + Instead of using global variables, we are going to create an <literal>EchoBot</literal> class with the current code in it. The resulting code can be found in <xref linkend="Example-EchoBot3"/>. diff --git a/Limber/Server/ServerFromClientSession.cpp b/Limber/Server/ServerFromClientSession.cpp index b51a53f..3a37c65 100644 --- a/Limber/Server/ServerFromClientSession.cpp +++ b/Limber/Server/ServerFromClientSession.cpp @@ -51,7 +51,7 @@ void ServerFromClientSession::handleElement(boost::shared_ptr<Element> element) getXMPPLayer()->resetParser(); } else { - PLAINMessage plainMessage(authRequest->getMessage() ? *authRequest->getMessage() : ""); + PLAINMessage plainMessage(authRequest->getMessage() ? *authRequest->getMessage() : createSafeByteArray("")); if (userRegistry_->isValidUserPassword(JID(plainMessage.getAuthenticationID(), getLocalJID().getDomain()), plainMessage.getPassword())) { getXMPPLayer()->writeElement(boost::shared_ptr<AuthSuccess>(new AuthSuccess())); user_ = plainMessage.getAuthenticationID(); diff --git a/Limber/Server/ServerFromClientSession.h b/Limber/Server/ServerFromClientSession.h index 80ef063..1a0e109 100644 --- a/Limber/Server/ServerFromClientSession.h +++ b/Limber/Server/ServerFromClientSession.h @@ -7,13 +7,14 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/enable_shared_from_this.hpp> #include <string> -#include "Swiften/Session/Session.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Network/Connection.h" +#include <Swiften/Session/Session.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class ProtocolHeader; @@ -26,7 +27,6 @@ namespace Swift { class XMPPLayer; class ConnectionLayer; class Connection; - class ByteArray; class ServerFromClientSession : public Session { public: diff --git a/Limber/Server/ServerSession.h b/Limber/Server/ServerSession.h index bd4ab6d..486ebaa 100644 --- a/Limber/Server/ServerSession.h +++ b/Limber/Server/ServerSession.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Stanza.h" +#include <Swiften/Elements/Stanza.h> namespace Swift { class ServerSession { diff --git a/Limber/Server/ServerStanzaRouter.cpp b/Limber/Server/ServerStanzaRouter.cpp index fec529f..ea695e3 100644 --- a/Limber/Server/ServerStanzaRouter.cpp +++ b/Limber/Server/ServerStanzaRouter.cpp @@ -9,6 +9,7 @@ #include <cassert> #include <algorithm> +#include <Swiften/Base/Algorithm.h> namespace Swift { @@ -67,7 +68,7 @@ void ServerStanzaRouter::addClientSession(ServerSession* clientSession) { } void ServerStanzaRouter::removeClientSession(ServerSession* clientSession) { - clientSessions_.erase(std::remove(clientSessions_.begin(), clientSessions_.end(), clientSession), clientSessions_.end()); + erase(clientSessions_, clientSession); } } diff --git a/Limber/Server/ServerStanzaRouter.h b/Limber/Server/ServerStanzaRouter.h index 2a1960c..4a9493b 100644 --- a/Limber/Server/ServerStanzaRouter.h +++ b/Limber/Server/ServerStanzaRouter.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <map> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/Stanza.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Stanza.h> namespace Swift { class ServerSession; diff --git a/Limber/Server/SimpleUserRegistry.cpp b/Limber/Server/SimpleUserRegistry.cpp index 5b7329a..9ae6fd5 100644 --- a/Limber/Server/SimpleUserRegistry.cpp +++ b/Limber/Server/SimpleUserRegistry.cpp @@ -11,13 +11,13 @@ namespace Swift { SimpleUserRegistry::SimpleUserRegistry() { } -bool SimpleUserRegistry::isValidUserPassword(const JID& user, const std::string& password) const { - std::map<JID,std::string>::const_iterator i = users.find(user); +bool SimpleUserRegistry::isValidUserPassword(const JID& user, const SafeByteArray& password) const { + std::map<JID,SafeByteArray>::const_iterator i = users.find(user); return i != users.end() ? i->second == password : false; } void SimpleUserRegistry::addUser(const JID& user, const std::string& password) { - users.insert(std::make_pair(user, password)); + users.insert(std::make_pair(user, createSafeByteArray(password))); } } diff --git a/Limber/Server/SimpleUserRegistry.h b/Limber/Server/SimpleUserRegistry.h index 677d006..280bfce 100644 --- a/Limber/Server/SimpleUserRegistry.h +++ b/Limber/Server/SimpleUserRegistry.h @@ -8,7 +8,7 @@ #include <map> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> #include <string> #include "Limber/Server/UserRegistry.h" @@ -19,10 +19,10 @@ namespace Swift { public: SimpleUserRegistry(); - virtual bool isValidUserPassword(const JID& user, const std::string& password) const; + virtual bool isValidUserPassword(const JID& user, const SafeByteArray& password) const; void addUser(const JID& user, const std::string& password); private: - std::map<JID, std::string> users; + std::map<JID, SafeByteArray> users; }; } diff --git a/Limber/Server/UserRegistry.h b/Limber/Server/UserRegistry.h index c021fc4..9584a7e 100644 --- a/Limber/Server/UserRegistry.h +++ b/Limber/Server/UserRegistry.h @@ -7,15 +7,15 @@ #pragma once #include <string> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { - class JID; class UserRegistry { public: virtual ~UserRegistry(); - virtual bool isValidUserPassword(const JID& user, const std::string& password) const = 0; + virtual bool isValidUserPassword(const JID& user, const SafeByteArray& password) const = 0; }; } diff --git a/QA/Checker/IO.cpp b/QA/Checker/IO.cpp new file mode 100644 index 0000000..41fe5d3 --- /dev/null +++ b/QA/Checker/IO.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <QA/Checker/IO.h> + +#include <algorithm> +#include <iostream> + +std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s) { + std::ios::fmtflags oldFlags = os.flags(); + os << std::hex; + for (Swift::ByteArray::const_iterator i = s.begin(); i != s.end(); ++i) { + if (*i >= 32 && *i < 127) { + os << *i; + } + else { + os << "\\x" << static_cast<unsigned int>(static_cast<unsigned char>(*i)); + } + } + os << std::endl; + os.flags(oldFlags); + return os; +} + +std::ostream& operator<<(std::ostream& os, const Swift::SafeByteArray& s) { + std::ios::fmtflags oldFlags = os.flags(); + os << std::hex; + for (Swift::SafeByteArray::const_iterator i = s.begin(); i != s.end(); ++i) { + if (*i >= 32 && *i < 127) { + os << *i; + } + else { + os << "\\x" << static_cast<unsigned int>(static_cast<unsigned char>(*i)); + } + } + os << std::endl; + os.flags(oldFlags); + return os; +} + +std::ostream& operator<<(std::ostream& os, const std::vector<int>& s) { + for (std::vector<int>::const_iterator i = s.begin(); i != s.end(); ++i) { + os << *i << " "; + } + os << std::endl; + return os; +} + +std::ostream& operator<<(std::ostream& os, const std::vector<size_t>& s) { + for (std::vector<size_t>::const_iterator i = s.begin(); i != s.end(); ++i) { + os << *i << " "; + } + os << std::endl; + return os; +} + +bool operator==(const Swift::ByteArray& a, const Swift::ByteArray& b) { + if (a.size() != b.size()) { + return false; + } + return std::equal(a.begin(), a.end(), b.begin()); +} diff --git a/QA/Checker/IO.h b/QA/Checker/IO.h new file mode 100644 index 0000000..3e40f7e --- /dev/null +++ b/QA/Checker/IO.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> + +std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s); +bool operator==(const Swift::ByteArray& a, const Swift::ByteArray& b); +std::ostream& operator<<(std::ostream& os, const Swift::SafeByteArray& s); +std::ostream& operator<<(std::ostream& os, const std::vector<int>& s); +std::ostream& operator<<(std::ostream& os, const std::vector<size_t>& s); diff --git a/QA/Checker/SConscript b/QA/Checker/SConscript index 0456b93..ed17be5 100644 --- a/QA/Checker/SConscript +++ b/QA/Checker/SConscript @@ -10,5 +10,6 @@ if env["TEST"] : if env["SCONS_STAGE"] == "build" : checker_env = env.Clone() + checker_env.MergeFlags(env["BOOST_FLAGS"]) checker_env.MergeFlags(env["CPPUNIT_FLAGS"]) - checker_env.Library("Checker", "checker.cpp") + checker_env.Library("Checker", ["checker.cpp", "IO.cpp"]) diff --git a/QA/Checker/checker.cpp b/QA/Checker/checker.cpp index 1870b5d..12237dc 100644 --- a/QA/Checker/checker.cpp +++ b/QA/Checker/checker.cpp @@ -13,6 +13,8 @@ #include <cppunit/TextTestProgressListener.h> #include <cppunit/TextOutputter.h> +#include <Swiften/Base/Log.h> + int main(int argc, char* argv[]) { bool verbose = false; bool outputXML = false; @@ -27,6 +29,9 @@ int main(int argc, char* argv[]) { else if (param == "--xml") { outputXML = true; } + else if (param == "--debug") { + Swift::logging = true; + } else { testsToRun.push_back(param); } diff --git a/QA/UnitTest/SConscript b/QA/UnitTest/SConscript index 8cc43b9..3a19ea5 100644 --- a/QA/UnitTest/SConscript +++ b/QA/UnitTest/SConscript @@ -27,8 +27,12 @@ if env["TEST"] : myenv.Append(CPPDEFINES = ["HAVE_LIBXML"]) if env.get("HAVE_EXPAT") : myenv.Append(CPPDEFINES = ["HAVE_EXPAT"]) - checker = myenv.Program("checker", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"]) - for i in ["HOME", "USERPROFILE", "APPDATA"]: - if os.environ.get(i, "") : - myenv["ENV"][i] = os.environ[i] - myenv.Test(checker, is_checker = True) + if env["TEST_CREATE_LIBRARIES"] : + lib = myenv.StaticLibrary("Swift_UnitTests", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"]) + myenv.Program("checker", lib) + else : + checker = myenv.Program("checker", env["UNITTEST_SOURCES"] + env["UNITTEST_OBJECTS"]) + for i in ["HOME", "USERPROFILE", "APPDATA"]: + if os.environ.get(i, "") : + myenv["ENV"][i] = os.environ[i] + myenv.Test(checker, is_checker = True) @@ -1 +1,5 @@ -SConscript("BuildTools/SCons/SConstruct") +variant_dir = SConscript("BuildTools/SCons/SConscript.boot") +if variant_dir : + SConscript("BuildTools/SCons/SConstruct", variant_dir = variant_dir, src_dir = ".") +else : + SConscript("BuildTools/SCons/SConstruct") diff --git a/Slimber/CLI/main.cpp b/Slimber/CLI/main.cpp index 5252373..3dd59a6 100644 --- a/Slimber/CLI/main.cpp +++ b/Slimber/CLI/main.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/EventLoop/SimpleEventLoop.h" +#include <Swiften/EventLoop/SimpleEventLoop.h> #include "Slimber/CLI/DummyMenulet.h" #include "Slimber/MainController.h" diff --git a/Slimber/Cocoa/CocoaMenulet.h b/Slimber/Cocoa/CocoaMenulet.h index 7f2758b..5c7c33e 100644 --- a/Slimber/Cocoa/CocoaMenulet.h +++ b/Slimber/Cocoa/CocoaMenulet.h @@ -9,7 +9,7 @@ #include <Cocoa/Cocoa.h> #include "Slimber/Menulet.h" -#include "Slimber/Cocoa/CocoaAction.h" +#include <SwifTools/Cocoa/CocoaAction.h> class CocoaMenulet : public Menulet { public: diff --git a/Slimber/Cocoa/SConscript b/Slimber/Cocoa/SConscript index e122d87..1283dc7 100644 --- a/Slimber/Cocoa/SConscript +++ b/Slimber/Cocoa/SConscript @@ -17,7 +17,6 @@ myenv.Program("Slimber", [ "main.mm", "CocoaController.mm", "CocoaMenulet.mm", - "CocoaAction.mm" ]) myenv.Nib("MainMenu") diff --git a/Slimber/Cocoa/main.h b/Slimber/Cocoa/main.h index 681139d..0f686ad 100644 --- a/Slimber/Cocoa/main.h +++ b/Slimber/Cocoa/main.h @@ -6,6 +6,6 @@ #pragma once -#include "Swiften/EventLoop/Cocoa/CocoaEventLoop.h" +#include <Swiften/EventLoop/Cocoa/CocoaEventLoop.h> extern Swift::CocoaEventLoop* eventLoop; diff --git a/Slimber/Cocoa/main.mm b/Slimber/Cocoa/main.mm index fc051e0..167c1ab 100644 --- a/Slimber/Cocoa/main.mm +++ b/Slimber/Cocoa/main.mm @@ -1,7 +1,7 @@ #include <Cocoa/Cocoa.h> #include "Slimber/Cocoa/main.h" -#include "Swiften/EventLoop/Cocoa/CocoaEventLoop.h" +#include <Swiften/EventLoop/Cocoa/CocoaEventLoop.h> Swift::CocoaEventLoop* eventLoop; diff --git a/Slimber/FileVCardCollection.cpp b/Slimber/FileVCardCollection.cpp index 960cd84..97ade08 100644 --- a/Slimber/FileVCardCollection.cpp +++ b/Slimber/FileVCardCollection.cpp @@ -8,11 +8,11 @@ #include <boost/filesystem/fstream.hpp> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/VCard.h" -#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" -#include "Swiften/Parser/PayloadParsers/VCardParser.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Elements/VCard.h> +#include <Swiften/Serializer/PayloadSerializers/VCardSerializer.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> +#include <Swiften/Parser/PayloadParsers/VCardParser.h> namespace Swift { @@ -22,11 +22,11 @@ FileVCardCollection::FileVCardCollection(boost::filesystem::path dir) : vcardsPa boost::shared_ptr<VCard> FileVCardCollection::getOwnVCard() const { if (boost::filesystem::exists(vcardsPath / std::string("vcard.xml"))) { ByteArray data; - data.readFromFile(boost::filesystem::path(vcardsPath / std::string("vcard.xml")).string()); + readByteArrayFromFile(data, boost::filesystem::path(vcardsPath / std::string("vcard.xml")).string()); VCardParser parser; PayloadParserTester tester(&parser); - tester.parse(data.toString()); + tester.parse(byteArrayToString(data)); return boost::dynamic_pointer_cast<VCard>(parser.getPayload()); } else { diff --git a/Slimber/LinkLocalPresenceManager.cpp b/Slimber/LinkLocalPresenceManager.cpp index edb7e91..708327e 100644 --- a/Slimber/LinkLocalPresenceManager.cpp +++ b/Slimber/LinkLocalPresenceManager.cpp @@ -8,10 +8,10 @@ #include <boost/bind.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/LinkLocal/LinkLocalServiceBrowser.h> +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Elements/Presence.h> namespace Swift { diff --git a/Slimber/LinkLocalPresenceManager.h b/Slimber/LinkLocalPresenceManager.h index 26bb7ce..5613448 100644 --- a/Slimber/LinkLocalPresenceManager.h +++ b/Slimber/LinkLocalPresenceManager.h @@ -7,11 +7,11 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Elements/RosterItemPayload.h" +#include <Swiften/Elements/RosterItemPayload.h> #include <string> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> namespace Swift { class LinkLocalService; diff --git a/Slimber/MainController.cpp b/Slimber/MainController.cpp index e39a660..c2bbb40 100644 --- a/Slimber/MainController.cpp +++ b/Slimber/MainController.cpp @@ -10,11 +10,11 @@ #include <boost/lexical_cast.hpp> #include <iostream> -#include "Swiften/Base/foreach.h" -#include "SwifTools/Application/PlatformApplicationPathProvider.h" -#include "Swiften/LinkLocal/LinkLocalService.h" -#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" -#include "Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h" +#include <Swiften/Base/foreach.h> +#include <SwifTools/Application/PlatformApplicationPathProvider.h> +#include <Swiften/LinkLocal/LinkLocalService.h> +#include <Swiften/LinkLocal/LinkLocalServiceBrowser.h> +#include <Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h> #include "Slimber/Server.h" #include "Slimber/FileVCardCollection.h" #include "Slimber/MenuletController.h" diff --git a/Slimber/Menulet.h b/Slimber/Menulet.h index df3c32c..f734b18 100644 --- a/Slimber/Menulet.h +++ b/Slimber/Menulet.h @@ -7,7 +7,7 @@ #pragma once #include <string> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> class Menulet { public: diff --git a/Slimber/MenuletController.cpp b/Slimber/MenuletController.cpp index 351db21..03b9187 100644 --- a/Slimber/MenuletController.cpp +++ b/Slimber/MenuletController.cpp @@ -6,7 +6,7 @@ #include "Slimber/MenuletController.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/foreach.h> #include <string> #include "Slimber/Menulet.h" diff --git a/Slimber/Qt/main.cpp b/Slimber/Qt/main.cpp index 0971eca..517a253 100644 --- a/Slimber/Qt/main.cpp +++ b/Slimber/Qt/main.cpp @@ -11,8 +11,8 @@ #include "QtMenulet.h" #include "Slimber/MainController.h" -#include "Swiften/EventLoop/Qt/QtEventLoop.h" -#include "Slimber/Qt/BuildVersion.h" +#include <Swiften/EventLoop/Qt/QtEventLoop.h> +#include <Slimber/Qt/BuildVersion.h> int main(int argc, char* argv[]) { QApplication app(argc, argv); diff --git a/Slimber/SConscript b/Slimber/SConscript index 11beee6..2298b0a 100644 --- a/Slimber/SConscript +++ b/Slimber/SConscript @@ -34,6 +34,7 @@ if "Slimber" in env["PROJECTS"] : myenv.UseFlags(env["LIMBER_FLAGS"]) myenv.MergeFlags(env["BOOST_FLAGS"]) myenv.MergeFlags(env["SWIFTEN_FLAGS"]) + myenv.MergeFlags(env["SWIFTEN_DEP_FLAGS"]) myenv.StaticLibrary("Slimber", [ "LinkLocalPresenceManager.cpp", "FileVCardCollection.cpp", diff --git a/Slimber/Server.cpp b/Slimber/Server.cpp index d1d0e24..84b33fa 100644 --- a/Slimber/Server.cpp +++ b/Slimber/Server.cpp @@ -8,6 +8,7 @@ #include <string> #include <boost/bind.hpp> +#include <iostream> #include "Swiften/Base/String.h" #include "Swiften/LinkLocal/LinkLocalConnector.h" @@ -22,12 +23,14 @@ #include "Swiften/Elements/IQ.h" #include "Swiften/Elements/VCard.h" #include "Limber/Server/UserRegistry.h" +#include "Swiften/Session/Session.h" +#include <Swiften/Base/foreach.h> #include <string> -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" -#include "Swiften/LinkLocal/OutgoingLinkLocalSession.h" -#include "Swiften/LinkLocal/IncomingLinkLocalSession.h" -#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" -#include "Swiften/Network/ConnectionServer.h" +#include <Swiften/LinkLocal/LinkLocalServiceInfo.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 "Limber/Server/ServerFromClientSession.h" diff --git a/Slimber/Server.h b/Slimber/Server.h index d1a2332..58b1e7c 100644 --- a/Slimber/Server.h +++ b/Slimber/Server.h @@ -87,7 +87,7 @@ namespace Swift { public: DummyUserRegistry() {} - virtual bool isValidUserPassword(const JID&, const std::string&) const { + virtual bool isValidUserPassword(const JID&, const SafeByteArray&) const { return true; } }; diff --git a/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp b/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp index 47eb05c..e45861b 100644 --- a/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp +++ b/Slimber/UnitTest/LinkLocalPresenceManagerTest.cpp @@ -9,16 +9,16 @@ #include <boost/bind.hpp> #include <map> -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Elements/RosterItemPayload.h" +#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" +#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; @@ -56,14 +56,14 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { void testConstructor() { addService("alice@wonderland"); addService("rabbit@teaparty"); - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_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()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland", "Alice"); @@ -79,7 +79,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testServiceRemoved() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland"); removeService("alice@wonderland"); @@ -92,7 +92,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testServiceChanged() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland"); updateServicePresence("alice@wonderland", LinkLocalServiceInfo::Away, "I'm Away"); @@ -105,7 +105,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetAllPresence() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland"); addService("rabbit@teaparty"); @@ -121,7 +121,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetRoster() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland", "Alice"); addService("rabbit@teaparty", "Rabbit"); @@ -140,7 +140,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetRoster_InfoWithNick() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland", "Alice", "Alice In", "Wonderland"); @@ -149,7 +149,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetRoster_InfoWithFirstName() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland", "", "Alice In", ""); @@ -158,7 +158,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetRoster_InfoWithLastName() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland", "", "", "Wonderland"); @@ -167,7 +167,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetRoster_InfoWithFirstAndLastName() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland", "", "Alice In", "Wonderland"); @@ -176,7 +176,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetRoster_NoInfo() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland"); @@ -185,7 +185,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetServiceForJID() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland"); addService("rabbit@teaparty"); @@ -197,7 +197,7 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } void testGetServiceForJID_NoMatch() { - std::auto_ptr<LinkLocalPresenceManager> testling(createTestling()); + boost::shared_ptr<LinkLocalPresenceManager> testling(createTestling()); addService("alice@wonderland"); addService("queen@garden"); @@ -206,8 +206,8 @@ class LinkLocalPresenceManagerTest : public CppUnit::TestFixture { } private: - std::auto_ptr<LinkLocalPresenceManager> createTestling() { - std::auto_ptr<LinkLocalPresenceManager> testling( + boost::shared_ptr<LinkLocalPresenceManager> createTestling() { + boost::shared_ptr<LinkLocalPresenceManager> testling( new LinkLocalPresenceManager(browser)); testling->onRosterChanged.connect(boost::bind( &LinkLocalPresenceManagerTest::handleRosterChanged, this, _1)); diff --git a/Slimber/VCardCollection.h b/Slimber/VCardCollection.h index 2203444..4e50848 100644 --- a/Slimber/VCardCollection.h +++ b/Slimber/VCardCollection.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/VCard.h" +#include <Swiften/Elements/VCard.h> namespace Swift { class VCardCollection { diff --git a/Sluift/Lua/Value.cpp b/Sluift/Lua/Value.cpp index c03e633..3164ec6 100644 --- a/Sluift/Lua/Value.cpp +++ b/Sluift/Lua/Value.cpp @@ -6,9 +6,7 @@ #include "Value.h" -extern "C" { - #include <lualib.h> -} +#include <lualib.h> #include <boost/variant/apply_visitor.hpp> #include <Swiften/Base/foreach.h> diff --git a/Sluift/SConscript b/Sluift/SConscript index 576eae5..f6388a0 100644 --- a/Sluift/SConscript +++ b/Sluift/SConscript @@ -22,6 +22,10 @@ if env["SCONS_STAGE"] == "build" : myenv.Append(CPPDEFINES = ["SLUIFT_BUILD_DLL"]) elif myenv["PLATFORM"] == "darwin" : myenv["SHLIBSUFFIX"] = ".so" + if env["PLATFORM"] == "win32" : + myenv.Append(CFLAGS = ["/TP"]) + else : + myenv.Append(CFLAGS = ["-x", "c++"]) myenv["SLUIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "sluift") def patchLua(env, target, source) : @@ -51,8 +55,10 @@ if env["SCONS_STAGE"] == "build" : myenv.SharedLibrary("sluift", ["dll.c"]) if env["PLATFORM"] == "win32" : - myenv.WindowsBundle("Sluift", - resources = {"": [ - os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"), - os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll") - ]}) + ssl_libs = [] + if myenv.get("OPENSSL_DIR", False) : + ssl_libs = [ + os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"), + os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll") + ] + myenv.WindowsBundle("Sluift", resources = {"": ssl_libs}) diff --git a/Sluift/linit.c b/Sluift/linit.c index bb5d985..73f0522 100644 --- a/Sluift/linit.c +++ b/Sluift/linit.c @@ -1,6 +1,6 @@ -#include "lua.h" -#include "lualib.h" -#include "lauxlib.h" +#include <lua.h> +#include <lualib.h> +#include <lauxlib.h> #include "sluift.h" // A built-in table print function diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp index 49cfec4..4f762fa 100644 --- a/Sluift/sluift.cpp +++ b/Sluift/sluift.cpp @@ -4,16 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -extern "C" { - #include "sluift.h" - #include <lauxlib.h> -} +#include "sluift.h" +#include <lauxlib.h> #include <iostream> #include <string> #include <deque> #include <boost/assign/list_of.hpp> +#include <Swiften/Base/foreach.h> #include <Swiften/Swiften.h> #include "Watchdog.h" @@ -63,11 +62,20 @@ class SluiftClient { return client; } + ClientOptions& getOptions() { + return options; + } + void connect() { rosterReceived = false; client->connect(); } + void connect(const std::string& host) { + rosterReceived = false; + client->connect(host); + } + void waitConnected() { Watchdog watchdog(globalTimeout, networkFactories.getTimerFactory()); while (!watchdog.getTimedOut() && client->isActive() && !client->isAvailable()) { @@ -179,6 +187,7 @@ class SluiftClient { private: Client* client; + ClientOptions options; ClientXMLTracer* tracer; bool rosterReceived; std::deque<Stanza::ref> pendingEvents; @@ -196,7 +205,13 @@ static inline SluiftClient* getClient(lua_State* L) { static int sluift_client_connect(lua_State *L) { try { SluiftClient* client = getClient(L); - client->connect(); + std::string host(luaL_checkstring(L, 2)); + if (host.empty()) { + client->connect(); + } + else { + client->connect(host); + } client->waitConnected(); return 1; } @@ -453,12 +468,12 @@ static int sluift_client_set_options(lua_State* L) { luaL_checktype(L, 2, LUA_TTABLE); lua_getfield(L, 2, "compress"); if (!lua_isnil(L, -1)) { - client->getClient()->setUseStreamCompression(lua_toboolean(L, -1)); + client->getOptions().useStreamCompression = lua_toboolean(L, -1); } lua_getfield(L, 2, "tls"); if (!lua_isnil(L, -1)) { bool useTLS = lua_toboolean(L, -1); - client->getClient()->setUseTLS(useTLS ? Client::UseTLSWhenAvailable : Client::NeverUseTLS); + client->getOptions().useTLS = (useTLS ? ClientOptions::UseTLSWhenAvailable : ClientOptions::NeverUseTLS); } lua_pushvalue(L, 1); return 0; diff --git a/Sluift/sluift.h b/Sluift/sluift.h index f28862e..27b4eab 100644 --- a/Sluift/sluift.h +++ b/Sluift/sluift.h @@ -12,6 +12,6 @@ #define SLUIFT_API extern #endif -#include "lua.h" +#include <lua.h> SLUIFT_API int (luaopen_sluift)(lua_State *L); diff --git a/SwifTools/Application/ApplicationPathProvider.cpp b/SwifTools/Application/ApplicationPathProvider.cpp index e683563..aa7e609 100644 --- a/SwifTools/Application/ApplicationPathProvider.cpp +++ b/SwifTools/Application/ApplicationPathProvider.cpp @@ -7,9 +7,9 @@ #include <boost/filesystem.hpp> #include <iostream> -#include "SwifTools/Application/ApplicationPathProvider.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Base/Paths.h" +#include <SwifTools/Application/ApplicationPathProvider.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Paths.h> namespace Swift { diff --git a/SwifTools/Application/CocoaApplication.mm b/SwifTools/Application/CocoaApplication.mm index edfdc25..cbb5f2e 100644 --- a/SwifTools/Application/CocoaApplication.mm +++ b/SwifTools/Application/CocoaApplication.mm @@ -1,4 +1,4 @@ -#include "SwifTools/Application/CocoaApplication.h" +#include <SwifTools/Application/CocoaApplication.h> #include <AppKit/AppKit.h> #include <Cocoa/Cocoa.h> diff --git a/SwifTools/Application/MacOSXApplicationPathProvider.cpp b/SwifTools/Application/MacOSXApplicationPathProvider.cpp index 085eb33..41b0e4c 100644 --- a/SwifTools/Application/MacOSXApplicationPathProvider.cpp +++ b/SwifTools/Application/MacOSXApplicationPathProvider.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Application/MacOSXApplicationPathProvider.h" +#include <SwifTools/Application/MacOSXApplicationPathProvider.h> #include <iostream> #include <mach-o/dyld.h> diff --git a/SwifTools/Application/MacOSXApplicationPathProvider.h b/SwifTools/Application/MacOSXApplicationPathProvider.h index fec1944..760ea9b 100644 --- a/SwifTools/Application/MacOSXApplicationPathProvider.h +++ b/SwifTools/Application/MacOSXApplicationPathProvider.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Application/ApplicationPathProvider.h" +#include <SwifTools/Application/ApplicationPathProvider.h> namespace Swift { class MacOSXApplicationPathProvider : public ApplicationPathProvider { diff --git a/SwifTools/Application/PlatformApplicationPathProvider.h b/SwifTools/Application/PlatformApplicationPathProvider.h index bb9bfa9..7ea4b35 100644 --- a/SwifTools/Application/PlatformApplicationPathProvider.h +++ b/SwifTools/Application/PlatformApplicationPathProvider.h @@ -6,20 +6,20 @@ #pragma once -#include "Swiften/Base/Platform.h" +#include <Swiften/Base/Platform.h> #if defined(SWIFTEN_PLATFORM_MACOSX) -#include "SwifTools/Application/MacOSXApplicationPathProvider.h" +#include <SwifTools/Application/MacOSXApplicationPathProvider.h> namespace Swift { typedef MacOSXApplicationPathProvider PlatformApplicationPathProvider; } #elif defined(SWIFTEN_PLATFORM_WIN32) -#include "SwifTools/Application/WindowsApplicationPathProvider.h" +#include <SwifTools/Application/WindowsApplicationPathProvider.h> namespace Swift { typedef WindowsApplicationPathProvider PlatformApplicationPathProvider; } #else -#include "SwifTools/Application/UnixApplicationPathProvider.h" +#include <SwifTools/Application/UnixApplicationPathProvider.h> namespace Swift { typedef UnixApplicationPathProvider PlatformApplicationPathProvider; } diff --git a/SwifTools/Application/SConscript b/SwifTools/Application/SConscript index 0097bca..32924fc 100644 --- a/SwifTools/Application/SConscript +++ b/SwifTools/Application/SConscript @@ -21,6 +21,7 @@ else : objects = swiftools_env.StaticObject(sources) swiftools_env.Append(SWIFTOOLS_OBJECTS = [objects]) -env.Append(UNITTEST_SOURCES = [ - File("UnitTest/ApplicationPathProviderTest.cpp") - ]) +if swiftools_env["PLATFORM"] != "darwin" or swiftools_env["target"] == "native" : + env.Append(UNITTEST_SOURCES = [ + File("UnitTest/ApplicationPathProviderTest.cpp") + ]) diff --git a/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp b/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp index a418bc2..5eb0e16 100644 --- a/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp +++ b/SwifTools/Application/UnitTest/ApplicationPathProviderTest.cpp @@ -9,7 +9,7 @@ #include <string> #include <boost/algorithm/string.hpp> -#include "SwifTools/Application/PlatformApplicationPathProvider.h" +#include <SwifTools/Application/PlatformApplicationPathProvider.h> using namespace Swift; diff --git a/SwifTools/Application/UnixApplicationPathProvider.cpp b/SwifTools/Application/UnixApplicationPathProvider.cpp index d5a2f58..784256f 100644 --- a/SwifTools/Application/UnixApplicationPathProvider.cpp +++ b/SwifTools/Application/UnixApplicationPathProvider.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Application/UnixApplicationPathProvider.h" +#include <SwifTools/Application/UnixApplicationPathProvider.h> #include <unistd.h> #include <boost/algorithm/string.hpp> diff --git a/SwifTools/Application/UnixApplicationPathProvider.h b/SwifTools/Application/UnixApplicationPathProvider.h index 7ca64c3..198e4ee 100644 --- a/SwifTools/Application/UnixApplicationPathProvider.h +++ b/SwifTools/Application/UnixApplicationPathProvider.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Application/ApplicationPathProvider.h" +#include <SwifTools/Application/ApplicationPathProvider.h> namespace Swift { class UnixApplicationPathProvider : public ApplicationPathProvider { diff --git a/SwifTools/Application/WindowsApplicationPathProvider.cpp b/SwifTools/Application/WindowsApplicationPathProvider.cpp index afcdea2..8514fa7 100644 --- a/SwifTools/Application/WindowsApplicationPathProvider.cpp +++ b/SwifTools/Application/WindowsApplicationPathProvider.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Application/WindowsApplicationPathProvider.h" +#include <SwifTools/Application/WindowsApplicationPathProvider.h> #include <windows.h> diff --git a/SwifTools/Application/WindowsApplicationPathProvider.h b/SwifTools/Application/WindowsApplicationPathProvider.h index 9428908..f288326 100644 --- a/SwifTools/Application/WindowsApplicationPathProvider.h +++ b/SwifTools/Application/WindowsApplicationPathProvider.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Application/ApplicationPathProvider.h" +#include <SwifTools/Application/ApplicationPathProvider.h> namespace Swift { class WindowsApplicationPathProvider : public ApplicationPathProvider { diff --git a/SwifTools/AutoUpdater/AutoUpdater.cpp b/SwifTools/AutoUpdater/AutoUpdater.cpp index f4e462b..e424f3b 100644 --- a/SwifTools/AutoUpdater/AutoUpdater.cpp +++ b/SwifTools/AutoUpdater/AutoUpdater.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/AutoUpdater/AutoUpdater.h" +#include <SwifTools/AutoUpdater/AutoUpdater.h> namespace Swift { diff --git a/SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.cpp b/SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.cpp index 4dd06c7..d2e89ac 100644 --- a/SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.cpp +++ b/SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h" +#include <SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h> #include <cassert> #ifdef HAVE_SPARKLE -#include "SwifTools/AutoUpdater/SparkleAutoUpdater.h" +#include <SwifTools/AutoUpdater/SparkleAutoUpdater.h> #endif namespace Swift { diff --git a/SwifTools/AutoUpdater/SparkleAutoUpdater.h b/SwifTools/AutoUpdater/SparkleAutoUpdater.h index fc08975..f367945 100644 --- a/SwifTools/AutoUpdater/SparkleAutoUpdater.h +++ b/SwifTools/AutoUpdater/SparkleAutoUpdater.h @@ -7,7 +7,7 @@ #pragma once #include <string> -#include "SwifTools/AutoUpdater/AutoUpdater.h" +#include <SwifTools/AutoUpdater/AutoUpdater.h> namespace Swift { class SparkleAutoUpdater : public AutoUpdater { diff --git a/SwifTools/AutoUpdater/SparkleAutoUpdater.mm b/SwifTools/AutoUpdater/SparkleAutoUpdater.mm index 440e178..c35abc8 100644 --- a/SwifTools/AutoUpdater/SparkleAutoUpdater.mm +++ b/SwifTools/AutoUpdater/SparkleAutoUpdater.mm @@ -1,4 +1,4 @@ -#include "SwifTools/AutoUpdater/SparkleAutoUpdater.h" +#include <SwifTools/AutoUpdater/SparkleAutoUpdater.h> #include <Cocoa/Cocoa.h> #include <Sparkle/Sparkle.h> diff --git a/Slimber/Cocoa/CocoaAction.h b/SwifTools/Cocoa/CocoaAction.h index a46ef7c..a46ef7c 100644 --- a/Slimber/Cocoa/CocoaAction.h +++ b/SwifTools/Cocoa/CocoaAction.h diff --git a/Slimber/Cocoa/CocoaAction.mm b/SwifTools/Cocoa/CocoaAction.mm index 15498a1..d560787 100644 --- a/Slimber/Cocoa/CocoaAction.mm +++ b/SwifTools/Cocoa/CocoaAction.mm @@ -1,4 +1,10 @@ -#include "Slimber/Cocoa/CocoaAction.h" +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <SwifTools/Cocoa/CocoaAction.h> @implementation CocoaAction diff --git a/SwifTools/Cocoa/SConscript b/SwifTools/Cocoa/SConscript new file mode 100644 index 0000000..4ae4a07 --- /dev/null +++ b/SwifTools/Cocoa/SConscript @@ -0,0 +1,8 @@ +Import("swiftools_env", "env") + +sources = [] +if swiftools_env["PLATFORM"] == "darwin" and swiftools_env["target"] == "native" : + sources += ["CocoaAction.mm"] + +objects = swiftools_env.StaticObject(sources) +swiftools_env.Append(SWIFTOOLS_OBJECTS = [objects]) diff --git a/SwifTools/Dock/Dock.cpp b/SwifTools/Dock/Dock.cpp index 77bcd84..e159b8d 100644 --- a/SwifTools/Dock/Dock.cpp +++ b/SwifTools/Dock/Dock.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Dock/Dock.h" +#include <SwifTools/Dock/Dock.h> namespace Swift { diff --git a/SwifTools/Dock/MacOSXDock.h b/SwifTools/Dock/MacOSXDock.h index 64cc737..df2686f 100644 --- a/SwifTools/Dock/MacOSXDock.h +++ b/SwifTools/Dock/MacOSXDock.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Dock/Dock.h" +#include <SwifTools/Dock/Dock.h> namespace Swift { diff --git a/SwifTools/Dock/MacOSXDock.mm b/SwifTools/Dock/MacOSXDock.mm index a7a3d55..b8374fa 100644 --- a/SwifTools/Dock/MacOSXDock.mm +++ b/SwifTools/Dock/MacOSXDock.mm @@ -1,10 +1,10 @@ -#include "SwifTools/Dock/MacOSXDock.h" +#include <SwifTools/Dock/MacOSXDock.h> #include <AppKit/AppKit.h> #include <Cocoa/Cocoa.h> #include <boost/lexical_cast.hpp> -#include "Swiften/Base/String.h" +#include <Swiften/Base/String.h> namespace Swift { diff --git a/SwifTools/Dock/NullDock.h b/SwifTools/Dock/NullDock.h index a1655a4..b015770 100644 --- a/SwifTools/Dock/NullDock.h +++ b/SwifTools/Dock/NullDock.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Dock/Dock.h" +#include <SwifTools/Dock/Dock.h> namespace Swift { class NullDock : public Dock { diff --git a/SwifTools/Dock/WindowsDock.h b/SwifTools/Dock/WindowsDock.h index dc298da..0254617 100644 --- a/SwifTools/Dock/WindowsDock.h +++ b/SwifTools/Dock/WindowsDock.h @@ -9,8 +9,8 @@ #include <QSystemTrayIcon> #include <boost/lexical_cast.hpp> -#include "SwifTools/Dock/Dock.h" -#include "SwifTools/Notifier/Notifier.h" +#include <SwifTools/Dock/Dock.h> +#include <SwifTools/Notifier/Notifier.h> namespace Swift { class WindowsDock : public Dock { diff --git a/SwifTools/Idle/ActualIdleDetector.cpp b/SwifTools/Idle/ActualIdleDetector.cpp index 59df632..2a99e1a 100644 --- a/SwifTools/Idle/ActualIdleDetector.cpp +++ b/SwifTools/Idle/ActualIdleDetector.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/ActualIdleDetector.h" +#include <SwifTools/Idle/ActualIdleDetector.h> #include <boost/bind.hpp> #include <iostream> -#include "SwifTools/Idle/IdleQuerier.h" -#include "Swiften/Network/Timer.h" -#include "Swiften/Network/TimerFactory.h" +#include <SwifTools/Idle/IdleQuerier.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/Network/TimerFactory.h> namespace Swift { diff --git a/SwifTools/Idle/ActualIdleDetector.h b/SwifTools/Idle/ActualIdleDetector.h index 3a355cc..7845398 100644 --- a/SwifTools/Idle/ActualIdleDetector.h +++ b/SwifTools/Idle/ActualIdleDetector.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "SwifTools/Idle/IdleDetector.h" +#include <SwifTools/Idle/IdleDetector.h> namespace Swift { class IdleQuerier; diff --git a/SwifTools/Idle/DummyIdleQuerier.h b/SwifTools/Idle/DummyIdleQuerier.h index 0c40643..162d8f6 100644 --- a/SwifTools/Idle/DummyIdleQuerier.h +++ b/SwifTools/Idle/DummyIdleQuerier.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Idle/IdleQuerier.h" +#include <SwifTools/Idle/IdleQuerier.h> namespace Swift { class DummyIdleQuerier : public IdleQuerier { diff --git a/SwifTools/Idle/IdleDetector.cpp b/SwifTools/Idle/IdleDetector.cpp index f29be01..66ec4a5 100644 --- a/SwifTools/Idle/IdleDetector.cpp +++ b/SwifTools/Idle/IdleDetector.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/IdleDetector.h" +#include <SwifTools/Idle/IdleDetector.h> namespace Swift { diff --git a/SwifTools/Idle/IdleDetector.h b/SwifTools/Idle/IdleDetector.h index 746e281..9e379f7 100644 --- a/SwifTools/Idle/IdleDetector.h +++ b/SwifTools/Idle/IdleDetector.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> namespace Swift { @@ -29,7 +29,6 @@ namespace Swift { boost::signal<void (bool /* isIdle */)> onIdleChanged; - protected: void setIdle(bool b) { if (b != idle) { idle = b; diff --git a/SwifTools/Idle/IdleQuerier.cpp b/SwifTools/Idle/IdleQuerier.cpp index d8c01ca..f553252 100644 --- a/SwifTools/Idle/IdleQuerier.cpp +++ b/SwifTools/Idle/IdleQuerier.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/IdleQuerier.h" +#include <SwifTools/Idle/IdleQuerier.h> namespace Swift { diff --git a/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp b/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp index 5ae4a4d..df233a2 100644 --- a/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp +++ b/SwifTools/Idle/IdleQuerierTest/IdleQuerierTest.cpp @@ -6,8 +6,8 @@ #include <iostream> -#include "SwifTools/Idle/PlatformIdleQuerier.h" -#include "Swiften/Base/sleep.h" +#include <SwifTools/Idle/PlatformIdleQuerier.h> +#include <Swiften/Base/sleep.h> using namespace Swift; diff --git a/SwifTools/Idle/IdleQuerierTest/SConscript b/SwifTools/Idle/IdleQuerierTest/SConscript index 65f94ba..5878a46 100644 --- a/SwifTools/Idle/IdleQuerierTest/SConscript +++ b/SwifTools/Idle/IdleQuerierTest/SConscript @@ -7,5 +7,6 @@ if env["TEST"] : myenv.MergeFlags(myenv["BOOST_FLAGS"]) if myenv["HAVE_XSS"] : myenv.MergeFlags(myenv.get("XSS_FLAGS", {})) + myenv.Append(LIBS = ["X11"]) myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) tester = myenv.Program("IdleQuerierTest", ["IdleQuerierTest.cpp"]) diff --git a/SwifTools/Idle/MacOSXIdleQuerier.cpp b/SwifTools/Idle/MacOSXIdleQuerier.cpp index 4760285..b634fcb 100644 --- a/SwifTools/Idle/MacOSXIdleQuerier.cpp +++ b/SwifTools/Idle/MacOSXIdleQuerier.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/MacOSXIdleQuerier.h" +#include <SwifTools/Idle/MacOSXIdleQuerier.h> #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -26,6 +26,7 @@ int MacOSXIdleQuerier::getIdleTimeSeconds() { uint64_t idle = 0; bool result = CFNumberGetValue((CFNumberRef)property, kCFNumberSInt64Type, &idle); assert(result); + (void) result; CFRelease(property); return idle / 1000000000; } diff --git a/SwifTools/Idle/MacOSXIdleQuerier.h b/SwifTools/Idle/MacOSXIdleQuerier.h index ebd4656..fbbd448 100644 --- a/SwifTools/Idle/MacOSXIdleQuerier.h +++ b/SwifTools/Idle/MacOSXIdleQuerier.h @@ -8,7 +8,7 @@ #include <IOKit/IOKitLib.h> -#include "SwifTools/Idle/IdleQuerier.h" +#include <SwifTools/Idle/IdleQuerier.h> namespace Swift { class MacOSXIdleQuerier : public IdleQuerier { diff --git a/SwifTools/Idle/PlatformIdleQuerier.cpp b/SwifTools/Idle/PlatformIdleQuerier.cpp index a28e701..34bcedd 100644 --- a/SwifTools/Idle/PlatformIdleQuerier.cpp +++ b/SwifTools/Idle/PlatformIdleQuerier.cpp @@ -4,17 +4,17 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/PlatformIdleQuerier.h" -#include "Swiften/Base/Platform.h" +#include <SwifTools/Idle/PlatformIdleQuerier.h> +#include <Swiften/Base/Platform.h> -#if defined(SWIFTEN_PLATFORM_MACOSX) && defined(HAVE_IOKIT) -#include "SwifTools/Idle/MacOSXIdleQuerier.h" +#if defined(SWIFTEN_PLATFORM_MACOSX) && defined(HAVE_IOKIT) && !defined(SWIFTEN_PLATFORM_IPHONE) +#include <SwifTools/Idle/MacOSXIdleQuerier.h> #elif defined(SWIFTEN_PLATFORM_WINDOWS) -#include "SwifTools/Idle/WindowsIdleQuerier.h" +#include <SwifTools/Idle/WindowsIdleQuerier.h> #elif defined(HAVE_XSS) -#include "SwifTools/Idle/XSSIdleQuerier.h" +#include <SwifTools/Idle/XSSIdleQuerier.h> #endif -#include "SwifTools/Idle/DummyIdleQuerier.h" +#include <SwifTools/Idle/DummyIdleQuerier.h> #include <cassert> #include <iostream> @@ -23,7 +23,7 @@ namespace Swift { PlatformIdleQuerier::PlatformIdleQuerier() : querier(NULL) { #if defined(SWIFTEN_PLATFORM_MACOSX) -#if defined(HAVE_IOKIT) +#if defined(HAVE_IOKIT) && !defined(SWIFTEN_PLATFORM_IPHONE) querier = new MacOSXIdleQuerier(); #else querier = new DummyIdleQuerier(); diff --git a/SwifTools/Idle/PlatformIdleQuerier.h b/SwifTools/Idle/PlatformIdleQuerier.h index 30c4bb7..2679e39 100644 --- a/SwifTools/Idle/PlatformIdleQuerier.h +++ b/SwifTools/Idle/PlatformIdleQuerier.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Idle/IdleQuerier.h" +#include <SwifTools/Idle/IdleQuerier.h> namespace Swift { class PlatformIdleQuerier : public IdleQuerier { diff --git a/SwifTools/Idle/UnitTest/ActualIdleDetectorTest.cpp b/SwifTools/Idle/UnitTest/ActualIdleDetectorTest.cpp index 3fa7136..686b7a0 100644 --- a/SwifTools/Idle/UnitTest/ActualIdleDetectorTest.cpp +++ b/SwifTools/Idle/UnitTest/ActualIdleDetectorTest.cpp @@ -8,11 +8,11 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "SwifTools/Idle/ActualIdleDetector.h" -#include "SwifTools/Idle/IdleQuerier.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/Timer.h" +#include <SwifTools/Idle/ActualIdleDetector.h> +#include <SwifTools/Idle/IdleQuerier.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/Timer.h> using namespace Swift; diff --git a/SwifTools/Idle/WindowsIdleQuerier.cpp b/SwifTools/Idle/WindowsIdleQuerier.cpp index 904fd6d..4b9a5a1 100644 --- a/SwifTools/Idle/WindowsIdleQuerier.cpp +++ b/SwifTools/Idle/WindowsIdleQuerier.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/WindowsIdleQuerier.h" +#include <SwifTools/Idle/WindowsIdleQuerier.h> #include <windows.h> diff --git a/SwifTools/Idle/WindowsIdleQuerier.h b/SwifTools/Idle/WindowsIdleQuerier.h index 8297c77..4a219e5 100644 --- a/SwifTools/Idle/WindowsIdleQuerier.h +++ b/SwifTools/Idle/WindowsIdleQuerier.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Idle/IdleQuerier.h" +#include <SwifTools/Idle/IdleQuerier.h> namespace Swift { class WindowsIdleQuerier : public IdleQuerier { diff --git a/SwifTools/Idle/XSSIdleQuerier.cpp b/SwifTools/Idle/XSSIdleQuerier.cpp index 39a3cef..74e1eda 100644 --- a/SwifTools/Idle/XSSIdleQuerier.cpp +++ b/SwifTools/Idle/XSSIdleQuerier.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Idle/XSSIdleQuerier.h" +#include <SwifTools/Idle/XSSIdleQuerier.h> #include <cassert> #include <iostream> diff --git a/SwifTools/Idle/XSSIdleQuerier.h b/SwifTools/Idle/XSSIdleQuerier.h index b00c702..29569a3 100644 --- a/SwifTools/Idle/XSSIdleQuerier.h +++ b/SwifTools/Idle/XSSIdleQuerier.h @@ -9,7 +9,7 @@ #include <X11/Xlib.h> #include <X11/extensions/scrnsaver.h> -#include "SwifTools/Idle/IdleQuerier.h" +#include <SwifTools/Idle/IdleQuerier.h> namespace Swift { class XSSIdleQuerier : public IdleQuerier { diff --git a/SwifTools/LastLineTracker.cpp b/SwifTools/LastLineTracker.cpp new file mode 100644 index 0000000..a7360a8 --- /dev/null +++ b/SwifTools/LastLineTracker.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "LastLineTracker.h" + +using namespace Swift; + +LastLineTracker::LastLineTracker() { + lastFocus = true; + shouldMove = false; +} + +void LastLineTracker::setHasFocus(bool focus) { + if (!focus && lastFocus) { + shouldMove = true; + lastFocus = focus; + return; + } + shouldMove = false; + lastFocus = focus; +} + +bool LastLineTracker::getShouldMoveLastLine() { + bool ret = shouldMove; + shouldMove = false; + return ret; +} diff --git a/SwifTools/LastLineTracker.h b/SwifTools/LastLineTracker.h new file mode 100644 index 0000000..b7c9a3b --- /dev/null +++ b/SwifTools/LastLineTracker.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +namespace Swift { + class LastLineTracker { + public: + LastLineTracker(); + void setHasFocus(bool focus); + bool getShouldMoveLastLine(); + private: + bool lastFocus; + bool shouldMove; + }; +} diff --git a/SwifTools/Linkify.cpp b/SwifTools/Linkify.cpp index 91c713f..2ca284d 100644 --- a/SwifTools/Linkify.cpp +++ b/SwifTools/Linkify.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Linkify.h" +#include <SwifTools/Linkify.h> #include <boost/regex.hpp> #include <sstream> @@ -12,7 +12,7 @@ namespace Swift { -static boost::regex linkifyRegexp("^https?://.*"); +static boost::regex linkifyRegexp("^(https?://|xmpp:).*"); std::string Linkify::linkify(const std::string& input) { std::ostringstream result; @@ -42,7 +42,7 @@ std::string Linkify::linkify(const std::string& input) { } } } - if (currentURL.size() > 0) { + if (!currentURL.empty()) { std::string url(¤tURL[0], currentURL.size()); result << "<a href=\"" << url << "\">" << url << "</a>"; } diff --git a/SwifTools/Notifier/GNTPNotifier.cpp b/SwifTools/Notifier/GNTPNotifier.cpp index 9a20c33..9bc05bd 100644 --- a/SwifTools/Notifier/GNTPNotifier.cpp +++ b/SwifTools/Notifier/GNTPNotifier.cpp @@ -6,15 +6,15 @@ // FIXME: This notifier needs finishing (handling callbacks etc.) -#include "SwifTools/Notifier/GNTPNotifier.h" +#include <SwifTools/Notifier/GNTPNotifier.h> #include <cassert> #include <iostream> #include <boost/bind.hpp> #include <sstream> -#include "Swiften/Base/foreach.h" -#include "Swiften/Network/ConnectionFactory.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/ConnectionFactory.h> namespace Swift { diff --git a/SwifTools/Notifier/GNTPNotifier.h b/SwifTools/Notifier/GNTPNotifier.h index a740c27..2cba044 100644 --- a/SwifTools/Notifier/GNTPNotifier.h +++ b/SwifTools/Notifier/GNTPNotifier.h @@ -8,8 +8,8 @@ #include <boost/filesystem.hpp> -#include "SwifTools/Notifier/Notifier.h" -#include "Swiften/Network/Connection.h" +#include <SwifTools/Notifier/Notifier.h> +#include <Swiften/Network/Connection.h> namespace Swift { class ConnectionFactory; diff --git a/SwifTools/Notifier/GrowlNotifier.cpp b/SwifTools/Notifier/GrowlNotifier.cpp index e289313..d83634d 100644 --- a/SwifTools/Notifier/GrowlNotifier.cpp +++ b/SwifTools/Notifier/GrowlNotifier.cpp @@ -8,17 +8,17 @@ #include <cassert> -#include "Swiften/Base/String.h" -#include "Swiften/Base/ByteArray.h" -#include "SwifTools/Notifier/GrowlNotifier.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/String.h> +#include <Swiften/Base/ByteArray.h> +#include <SwifTools/Notifier/GrowlNotifier.h> +#include <Swiften/Base/foreach.h> #pragma GCC diagnostic ignored "-Wold-style-cast" #pragma GCC diagnostic ignored "-Wdeprecated-declarations" namespace { struct Context { - Context() {} + Context() : callback(0) {} Context(const boost::function<void()>& callback) : callback(new boost::function<void()>(callback)) {} boost::function<void()>* callback; @@ -74,12 +74,12 @@ GrowlNotifier::GrowlNotifier(const std::string& name) { void GrowlNotifier::showMessage(Type type, const std::string& subject, const std::string& description, const boost::filesystem::path& picturePath, boost::function<void()> callback) { ByteArray picture; - picture.readFromFile(picturePath.string()); + readByteArrayFromFile(picture, picturePath.string()); CFStringRef cfSubject = SWIFTEN_STRING_TO_CFSTRING(subject); CFStringRef cfDescription = SWIFTEN_STRING_TO_CFSTRING(description); CFStringRef cfName = SWIFTEN_STRING_TO_CFSTRING(typeToString(type)); - CFDataRef cfIcon = CFDataCreate( NULL, (UInt8*) picture.getData(), picture.getSize()); + CFDataRef cfIcon = CFDataCreate( NULL, (UInt8*) vecptr(picture), picture.size()); Context context(callback); CFDataRef cfContextData[1]; diff --git a/SwifTools/Notifier/GrowlNotifier.h b/SwifTools/Notifier/GrowlNotifier.h index d4a6178..e2686e8 100644 --- a/SwifTools/Notifier/GrowlNotifier.h +++ b/SwifTools/Notifier/GrowlNotifier.h @@ -10,7 +10,7 @@ #include <Growl/Growl.h> #include <boost/filesystem/fstream.hpp> -#include "SwifTools/Notifier/Notifier.h" +#include <SwifTools/Notifier/Notifier.h> namespace Swift { /** diff --git a/SwifTools/Notifier/LoggingNotifier.h b/SwifTools/Notifier/LoggingNotifier.h index 18ae0e2..32e0610 100644 --- a/SwifTools/Notifier/LoggingNotifier.h +++ b/SwifTools/Notifier/LoggingNotifier.h @@ -6,8 +6,8 @@ #pragma once -#include "SwifTools/Notifier/Notifier.h" -#include "Swiften/Base/ByteArray.h" +#include <SwifTools/Notifier/Notifier.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class LoggingNotifier : public Notifier { diff --git a/SwifTools/Notifier/Notifier.cpp b/SwifTools/Notifier/Notifier.cpp index 1673400..5cd9c50 100644 --- a/SwifTools/Notifier/Notifier.cpp +++ b/SwifTools/Notifier/Notifier.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Notifier/Notifier.h" +#include <SwifTools/Notifier/Notifier.h> namespace Swift { diff --git a/SwifTools/Notifier/NullNotifier.h b/SwifTools/Notifier/NullNotifier.h index 24b4476..2fa9c11 100644 --- a/SwifTools/Notifier/NullNotifier.h +++ b/SwifTools/Notifier/NullNotifier.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Notifier/Notifier.h" +#include <SwifTools/Notifier/Notifier.h> namespace Swift { class NullNotifier : public Notifier { diff --git a/SwifTools/Notifier/SnarlNotifier.cpp b/SwifTools/Notifier/SnarlNotifier.cpp index d891e7d..19d3622 100644 --- a/SwifTools/Notifier/SnarlNotifier.cpp +++ b/SwifTools/Notifier/SnarlNotifier.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/Notifier/SnarlNotifier.h" +#include <SwifTools/Notifier/SnarlNotifier.h> #include <cassert> #include <iostream> #include <boost/bind.hpp> -#include "Swiften/Base/foreach.h" -#include "SwifTools/Notifier/Win32NotifierWindow.h" +#include <Swiften/Base/foreach.h> +#include <SwifTools/Notifier/Win32NotifierWindow.h> #define SWIFT_SNARLNOTIFIER_MESSAGE_ID 0x4567 // Sounds sick to pick a number, but this is windows diff --git a/SwifTools/Notifier/SnarlNotifier.h b/SwifTools/Notifier/SnarlNotifier.h index 9e2cddf..c96dfa6 100644 --- a/SwifTools/Notifier/SnarlNotifier.h +++ b/SwifTools/Notifier/SnarlNotifier.h @@ -8,8 +8,8 @@ #include <map> -#include "SwifTools/Notifier/Notifier.h" -#include "SnarlInterface.h" +#include <SwifTools/Notifier/Notifier.h> +#include <SnarlInterface.h> namespace Swift { class Win32NotifierWindow; diff --git a/SwifTools/Notifier/TogglableNotifier.h b/SwifTools/Notifier/TogglableNotifier.h index 415caf6..e8de5de 100644 --- a/SwifTools/Notifier/TogglableNotifier.h +++ b/SwifTools/Notifier/TogglableNotifier.h @@ -6,7 +6,7 @@ #pragma once -#include "SwifTools/Notifier/Notifier.h" +#include <SwifTools/Notifier/Notifier.h> namespace Swift { class TogglableNotifier : public Notifier { diff --git a/SwifTools/Notifier/Win32NotifierWindow.h b/SwifTools/Notifier/Win32NotifierWindow.h index 7ac149b..2279b0b 100644 --- a/SwifTools/Notifier/Win32NotifierWindow.h +++ b/SwifTools/Notifier/Win32NotifierWindow.h @@ -8,7 +8,7 @@ //#include <windows.h> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class Win32NotifierWindow { diff --git a/SwifTools/SConscript b/SwifTools/SConscript index d4747db..e5085cc 100644 --- a/SwifTools/SConscript +++ b/SwifTools/SConscript @@ -27,6 +27,7 @@ if env["SCONS_STAGE"] == "build" : "AutoUpdater/PlatformAutoUpdaterFactory.cpp", "Linkify.cpp", "TabComplete.cpp", + "LastLineTracker.cpp", ] if swiftools_env.get("HAVE_SPARKLE", 0) : @@ -50,8 +51,10 @@ if env["SCONS_STAGE"] == "build" : "Application", "Dock", "Notifier", + "URIHandler", "Idle/IdleQuerierTest", "Idle/UnitTest", + "Cocoa", "UnitTest" ]) diff --git a/SwifTools/TabComplete.cpp b/SwifTools/TabComplete.cpp index b123360..f4ef837 100644 --- a/SwifTools/TabComplete.cpp +++ b/SwifTools/TabComplete.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "SwifTools/TabComplete.h" +#include <SwifTools/TabComplete.h> #include <algorithm> #include <boost/algorithm/string.hpp> -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/foreach.h> namespace Swift { @@ -28,7 +28,7 @@ void TabComplete::removeWord(const std::string& word) { std::string TabComplete::completeWord(const std::string& word) { if (word == lastCompletion_) { - if (lastCompletionCandidates_.size() != 0) { + if (!lastCompletionCandidates_.empty()) { size_t match = 0; for (match = 0; match < lastCompletionCandidates_.size(); match++) { if (lastCompletionCandidates_[match] == lastCompletion_) { @@ -47,7 +47,7 @@ std::string TabComplete::completeWord(const std::string& word) { lastCompletionCandidates_.push_back(candidate); } } - lastCompletion_ = lastCompletionCandidates_.size() > 0 ? lastCompletionCandidates_[0] : word; + lastCompletion_ = !lastCompletionCandidates_.empty() ? lastCompletionCandidates_[0] : word; } return lastCompletion_; } diff --git a/SwifTools/URIHandler/MacOSXURIHandler.h b/SwifTools/URIHandler/MacOSXURIHandler.h new file mode 100644 index 0000000..f803420 --- /dev/null +++ b/SwifTools/URIHandler/MacOSXURIHandler.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <SwifTools/URIHandler/URIHandler.h> + +namespace Swift { + class MacOSXURIHandler : public URIHandler { + public: + MacOSXURIHandler(); + virtual ~MacOSXURIHandler(); + + virtual void start(); + virtual void stop(); + + private: + class Private; + Private* p; + }; +} diff --git a/SwifTools/URIHandler/MacOSXURIHandler.mm b/SwifTools/URIHandler/MacOSXURIHandler.mm new file mode 100644 index 0000000..3542e2f --- /dev/null +++ b/SwifTools/URIHandler/MacOSXURIHandler.mm @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <SwifTools/URIHandler/MacOSXURIHandler.h> + +#include <Cocoa/Cocoa.h> +#include <iostream> + +using namespace Swift; + +@interface MacOSXURIEventHandler : NSObject { + URIHandler* handler; +} +- (id) initWithHandler: (URIHandler*) handler; +- (void) getUrl: (NSAppleEventDescriptor*) event withReplyEvent: (NSAppleEventDescriptor*) replyEvent; + +@end +@implementation MacOSXURIEventHandler + - (id) initWithHandler: (URIHandler*) h { + if ([super init]) { + handler = h; + } + return self; + } + + - (void) getUrl: (NSAppleEventDescriptor*) event withReplyEvent: (NSAppleEventDescriptor*) replyEvent { + (void) replyEvent; + NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + handler->onURI(std::string([url UTF8String])); + } +@end + +class MacOSXURIHandler::Private { + public: + MacOSXURIEventHandler* eventHandler; +}; + +MacOSXURIHandler::MacOSXURIHandler() { + p = new Private(); + p->eventHandler = [[MacOSXURIEventHandler alloc] initWithHandler: this]; +} + +MacOSXURIHandler::~MacOSXURIHandler() { + [p->eventHandler release]; + delete p; +} + +void MacOSXURIHandler::start() { + [[NSAppleEventManager sharedAppleEventManager] setEventHandler:p->eventHandler andSelector:@selector(getUrl:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier]; + LSSetDefaultHandlerForURLScheme((CFStringRef)@"xmpp", (CFStringRef)bundleID); +} + +void MacOSXURIHandler::stop() { + [[NSAppleEventManager sharedAppleEventManager] removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL]; +} diff --git a/Swiften/Elements/JingleTransport.h b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.h index ecd2a34..5a2db7a 100644 --- a/Swiften/Elements/JingleTransport.h +++ b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.h @@ -6,9 +6,6 @@ #pragma once -#include <Swiften/Elements/Payload.h> - namespace Swift { - class JingleTransport : public Payload { - }; + void registerAppAsDefaultXMPPURIHandler(); } diff --git a/SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm new file mode 100644 index 0000000..dca91b8 --- /dev/null +++ b/SwifTools/URIHandler/MacOSXURIHandlerHelpers.mm @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <SwifTools/URIHandler/MacOSXURIHandlerHelpers.h> + +#include <Cocoa/Cocoa.h> + +namespace Swift { + void registerAppAsDefaultXMPPURIHandler() { + NSString* bundleID = [[NSBundle mainBundle] bundleIdentifier]; + LSSetDefaultHandlerForURLScheme((CFStringRef)@"xmpp", (CFStringRef)bundleID); + } +} diff --git a/SwifTools/URIHandler/NullURIHandler.h b/SwifTools/URIHandler/NullURIHandler.h new file mode 100644 index 0000000..28c35bb --- /dev/null +++ b/SwifTools/URIHandler/NullURIHandler.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <SwifTools/URIHandler/URIHandler.h> + +namespace Swift { + class NullURIHandler : public URIHandler { + public: + virtual void start() { + } + + virtual void stop() { + } + }; +} diff --git a/SwifTools/URIHandler/SConscript b/SwifTools/URIHandler/SConscript new file mode 100644 index 0000000..42c6ca8 --- /dev/null +++ b/SwifTools/URIHandler/SConscript @@ -0,0 +1,23 @@ +Import("swiftools_env", "env") + +sources = [ + "XMPPURI.cpp", + "URIHandler.cpp", + ] + +if swiftools_env["PLATFORM"] == "darwin" and swiftools_env["target"] == "native" : + sources += [ + "MacOSXURIHandler.mm", + "MacOSXURIHandlerHelpers.mm", + ] +elif swiftools_env["PLATFORM"] == "win32" : + sources += [] +else : + sources += [] + +objects = swiftools_env.StaticObject(sources) +swiftools_env.Append(SWIFTOOLS_OBJECTS = [objects]) + +env.Append(UNITTEST_SOURCES = [ + File("UnitTest/XMPPURITest.cpp"), + ]) diff --git a/SwifTools/URIHandler/URIHandler.cpp b/SwifTools/URIHandler/URIHandler.cpp new file mode 100644 index 0000000..91e54e5 --- /dev/null +++ b/SwifTools/URIHandler/URIHandler.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <SwifTools/URIHandler/URIHandler.h> + +using namespace Swift; + +URIHandler::URIHandler() { +} + +URIHandler::~URIHandler() { +} diff --git a/SwifTools/URIHandler/URIHandler.h b/SwifTools/URIHandler/URIHandler.h new file mode 100644 index 0000000..9dd13a8 --- /dev/null +++ b/SwifTools/URIHandler/URIHandler.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class URIHandler { + public: + URIHandler(); + virtual ~URIHandler(); + + boost::signal<void (const std::string&)> onURI; + }; +} diff --git a/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp b/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp new file mode 100644 index 0000000..8d03b60 --- /dev/null +++ b/SwifTools/URIHandler/UnitTest/XMPPURITest.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <SwifTools/URIHandler/XMPPURI.h> + +using namespace Swift; + +class XMPPURITest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(XMPPURITest); + CPPUNIT_TEST(testFromString_Authority); + CPPUNIT_TEST(testFromString_AuthorityWithPath); + CPPUNIT_TEST(testFromString_AuthorityWithFragment); + CPPUNIT_TEST(testFromString_AuthorityWithPathAndFragment); + CPPUNIT_TEST(testFromString_AuthorityWithIntlChars); + CPPUNIT_TEST(testFromString_AuthorityWithQueryWithoutParameters); + CPPUNIT_TEST(testFromString_AuthorityWithQueryWithParameters); + CPPUNIT_TEST(testFromString_AuthorityWithQueryWithoutParametersWithFragment); + CPPUNIT_TEST(testFromString_AuthorityWithQueryWithParametersWithFragment); + CPPUNIT_TEST(testFromString_Path); + CPPUNIT_TEST(testFromString_PathWithFragment); + CPPUNIT_TEST(testFromString_PathWithIntlChars); + CPPUNIT_TEST(testFromString_PathWithInvalidEscapedChar); + CPPUNIT_TEST(testFromString_PathWithIncompleteEscapedChar); + CPPUNIT_TEST(testFromString_PathWithIncompleteEscapedChar2); + CPPUNIT_TEST(testFromString_PathWithQueryWithoutParameters); + CPPUNIT_TEST(testFromString_PathWithQueryWithParameters); + CPPUNIT_TEST(testFromString_PathWithQueryWithoutParametersWithFragment); + CPPUNIT_TEST(testFromString_PathWithQueryWithParametersWithFragment); + CPPUNIT_TEST(testFromString_NoPrefix); + CPPUNIT_TEST_SUITE_END(); + + public: + void testFromString_Authority() { + XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com"); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority()); + } + + void testFromString_AuthorityWithPath() { + XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com/baz@example.com"); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath()); + } + + void testFromString_AuthorityWithFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_AuthorityWithPathAndFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp://foo@bar.com/baz@example.com#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_AuthorityWithIntlChars() { + XMPPURI testling = XMPPURI::fromString("xmpp://nasty!%23$%25()*+,-.;=\%3F\%5B\%5C\%5D\%5E_\%60\%7B\%7C\%7D~node@example.com"); + + CPPUNIT_ASSERT_EQUAL(JID("nasty!#$\%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getAuthority()); + } + + void testFromString_AuthorityWithQueryWithoutParameters() { + XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + } + + void testFromString_AuthorityWithQueryWithParameters() { + XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject")); + CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body")); + } + + void testFromString_AuthorityWithQueryWithoutParametersWithFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_AuthorityWithQueryWithParametersWithFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp://test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getAuthority()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject")); + CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body")); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_Path() { + XMPPURI testling = XMPPURI::fromString("xmpp:baz@example.com"); + + CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath()); + } + + void testFromString_PathWithFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp:baz@example.com#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("baz@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_PathWithIntlChars() { + XMPPURI testling = XMPPURI::fromString("xmpp:nasty!%23$%25()*+,-.;=\%3F\%5B\%5C\%5D\%5E_\%60\%7B\%7C\%7D~node@example.com"); + + CPPUNIT_ASSERT_EQUAL(JID("nasty!#$\%()*+,-.;=?[\\]^_`{|}~node@example.com"), testling.getPath()); + } + + void testFromString_PathWithInvalidEscapedChar() { + XMPPURI testling = XMPPURI::fromString("xmpp:test%%@example.com"); + + CPPUNIT_ASSERT_EQUAL(JID(), testling.getPath()); + } + + void testFromString_PathWithIncompleteEscapedChar() { + XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com%"); + + CPPUNIT_ASSERT_EQUAL(JID(), testling.getPath()); + } + + void testFromString_PathWithIncompleteEscapedChar2() { + XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com%1"); + + CPPUNIT_ASSERT_EQUAL(JID(), testling.getPath()); + } + + void testFromString_PathWithQueryWithoutParameters() { + XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + } + + void testFromString_PathWithQueryWithParameters() { + XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject")); + CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body")); + } + + void testFromString_PathWithQueryWithoutParametersWithFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_PathWithQueryWithParametersWithFragment() { + XMPPURI testling = XMPPURI::fromString("xmpp:test@example.com?message;subject=Test%20Message;body=Here%27s%20a%20test%20message#myfragment"); + + CPPUNIT_ASSERT_EQUAL(JID("test@example.com"), testling.getPath()); + CPPUNIT_ASSERT_EQUAL(std::string("message"), testling.getQueryType()); + CPPUNIT_ASSERT_EQUAL(std::string("Test Message"), get(testling.getQueryParameters(), "subject")); + CPPUNIT_ASSERT_EQUAL(std::string("Here's a test message"), get(testling.getQueryParameters(), "body")); + CPPUNIT_ASSERT_EQUAL(std::string("myfragment"), testling.getFragment()); + } + + void testFromString_NoPrefix() { + XMPPURI testling = XMPPURI::fromString("baz@example.com"); + + CPPUNIT_ASSERT(testling.isNull()); + } + + private: + std::string get(const std::map<std::string, std::string>& m, const std::string& k) { + std::map<std::string, std::string>::const_iterator i = m.find(k); + return i == m.end() ? "" : i->second; + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(XMPPURITest); diff --git a/SwifTools/URIHandler/XMPPURI.cpp b/SwifTools/URIHandler/XMPPURI.cpp new file mode 100644 index 0000000..cb81391 --- /dev/null +++ b/SwifTools/URIHandler/XMPPURI.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <SwifTools/URIHandler/XMPPURI.h> + +#include <boost/algorithm/string/predicate.hpp> +#include <boost/algorithm/string/find_format.hpp> +#include <boost/algorithm/string/formatter.hpp> +#include <boost/algorithm/string/find_iterator.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/classification.hpp> +#include <sstream> +#include <stdexcept> +#include <vector> + +using namespace Swift; + +// Disabling this code for now, since GCC4.5+boost1.42 (on ubuntu) seems to +// result in a bug. Replacing it with naive code. +#if 0 +// Should be in anonymous namespace, but older GCCs complain if we do that +struct PercentEncodedCharacterFinder { + template<typename Iterator> + boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { + boost::iterator_range<Iterator> r = boost::first_finder("%")(begin, end); + if (r.end() == end) { + return r; + } + else { + if (r.end() + 1 == end || r.end() + 2 == end) { + throw std::runtime_error("Incomplete escape character"); + } + else { + r.advance_end(2); + return r; + } + } + } +}; + +struct PercentUnencodeFormatter { + template<typename FindResult> + std::string operator()(const FindResult& match) const { + std::stringstream s; + s << std::hex << std::string(match.begin() + 1, match.end()); + unsigned int value; + s >> value; + if (s.fail() || s.bad()) { + throw std::runtime_error("Invalid escape character"); + } + unsigned char charValue = static_cast<unsigned char>(value); + return std::string(reinterpret_cast<const char*>(&charValue), 1); + } +}; + +namespace { + std::string unescape(const std::string& s) { + try { + return boost::find_format_all_copy(s, PercentEncodedCharacterFinder(), PercentUnencodeFormatter()); + } + catch (const std::exception&) { + return ""; + } + } +} +#endif +namespace { + std::string unescape(const std::string& str) { + std::string result; + for (size_t i = 0; i < str.size(); ++i) { + if (str[i] == '%') { + if (i + 3 < str.size()) { + std::stringstream s; + s << std::hex << str.substr(i+1, 2); + unsigned int value; + s >> value; + if (s.fail() || s.bad()) { + return ""; + } + unsigned char charValue = static_cast<unsigned char>(value); + result += std::string(reinterpret_cast<const char*>(&charValue), 1); + i += 2; + } + else { + return ""; + } + } + else { + result += str[i]; + } + } + return result; + } +} + +XMPPURI::XMPPURI() { +} + +XMPPURI XMPPURI::fromString(const std::string& s) { + XMPPURI result; + if (boost::starts_with(s, "xmpp:")) { + std::string uri = s.substr(5, s.npos); + bool parsePath = true; + bool parseQuery = true; + bool parseFragment = true; + + // Parse authority + if (boost::starts_with(uri, "//")) { + size_t i = uri.find_first_of("/#?", 2); + result.setAuthority(JID(unescape(uri.substr(2, i - 2)))); + if (i == uri.npos) { + uri = ""; + parsePath = parseQuery = parseFragment = false; + } + else { + if (uri[i] == '?') { + parsePath = false; + } + else if (uri[i] == '#') { + parseQuery = parsePath = false; + } + uri = uri.substr(i + 1, uri.npos); + } + } + + // Parse path + if (parsePath) { + size_t i = uri.find_first_of("#?"); + result.setPath(JID(unescape(uri.substr(0, i)))); + if (i == uri.npos) { + uri = ""; + parseQuery = parseFragment = false; + } + else { + if (uri[i] == '#') { + parseQuery = false; + } + uri = uri.substr(i + 1, uri.npos); + } + } + + // Parse query + if (parseQuery) { + size_t end = uri.find_first_of("#"); + std::string query = uri.substr(0, end); + bool haveType = false; + typedef boost::split_iterator<std::string::iterator> split_iterator; + for (split_iterator it = boost::make_split_iterator(query, boost::first_finder(";")); it != split_iterator(); ++it) { + if (haveType) { + std::vector<std::string> keyValue; + boost::split(keyValue, *it, boost::is_any_of("=")); + if (keyValue.size() == 1) { + result.addQueryParameter(unescape(keyValue[0]), ""); + } + else if (keyValue.size() >= 2) { + result.addQueryParameter(unescape(keyValue[0]), unescape(keyValue[1])); + } + } + else { + result.setQueryType(unescape(boost::copy_range<std::string>(*it))); + haveType = true; + } + } + uri = (end == uri.npos ? "" : uri.substr(end + 1, uri.npos)); + } + + // Parse fragment + if (parseFragment) { + result.setFragment(unescape(uri)); + } + } + return result; +} diff --git a/SwifTools/URIHandler/XMPPURI.h b/SwifTools/URIHandler/XMPPURI.h new file mode 100644 index 0000000..266b79b --- /dev/null +++ b/SwifTools/URIHandler/XMPPURI.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <map> + +#include <Swiften/JID/JID.h> + +namespace Swift { + class XMPPURI { + public: + XMPPURI(); + + const JID& getAuthority() const { + return authority; + } + + void setAuthority(const JID& j) { + authority = j; + } + + const JID& getPath() const { + return path; + } + + void setPath(const JID& j) { + path = j; + } + + const std::string& getQueryType() const { + return queryType; + } + + void setQueryType(const std::string& q) { + queryType = q; + } + + const std::map<std::string, std::string>& getQueryParameters() const { + return queryParameters; + } + + void addQueryParameter(const std::string& key, const std::string& path) { + queryParameters[key] = path; + } + + const std::string& getFragment() const { + return fragment; + } + + void setFragment(const std::string& f) { + fragment = f; + } + + bool isNull() const { + return !authority.isValid() && !path.isValid(); + } + + static XMPPURI fromString(const std::string&); + + private: + JID authority; + JID path; + std::string fragment; + std::string queryType; + std::map<std::string, std::string> queryParameters; + }; +} diff --git a/SwifTools/UnitTest/LastLineTrackerTest.cpp b/SwifTools/UnitTest/LastLineTrackerTest.cpp new file mode 100644 index 0000000..a7046ed --- /dev/null +++ b/SwifTools/UnitTest/LastLineTrackerTest.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <SwifTools/LastLineTracker.h> + +using namespace Swift; + +class LastLineTrackerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LastLineTrackerTest); + CPPUNIT_TEST(testFocusNormal); + CPPUNIT_TEST(testFocusOut); + CPPUNIT_TEST(testFocusOtherTab); + CPPUNIT_TEST(testRepeatedFocusOut); + CPPUNIT_TEST(testRepeatedFocusIn); + CPPUNIT_TEST_SUITE_END(); + public: + LastLineTrackerTest () { + }; + void testFocusNormal() { + LastLineTracker testling; + testling.setHasFocus(true); + CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine()); + } + void testFocusOut() { + LastLineTracker testling; + testling.setHasFocus(false); + CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine()); + CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine()); + CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine()); + } + void testFocusOtherTab() { + LastLineTracker testling; + testling.setHasFocus(true); + testling.setHasFocus(false); + CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine()); + CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine()); + } + + void testRepeatedFocusOut() { + LastLineTracker testling; + testling.setHasFocus(true); + CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine()); + testling.setHasFocus(false); + CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine()); + testling.setHasFocus(false); + CPPUNIT_ASSERT_EQUAL(false, testling.getShouldMoveLastLine()); + } + void testRepeatedFocusIn() { + LastLineTracker testling; + testling.setHasFocus(false); + CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine()); + testling.setHasFocus(true); + testling.setHasFocus(false); + CPPUNIT_ASSERT_EQUAL(true, testling.getShouldMoveLastLine()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LastLineTrackerTest); diff --git a/SwifTools/UnitTest/LinkifyTest.cpp b/SwifTools/UnitTest/LinkifyTest.cpp index f7e2a37..3d0ce00 100644 --- a/SwifTools/UnitTest/LinkifyTest.cpp +++ b/SwifTools/UnitTest/LinkifyTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "SwifTools/Linkify.h" +#include <SwifTools/Linkify.h> using namespace Swift; diff --git a/SwifTools/UnitTest/SConscript b/SwifTools/UnitTest/SConscript index 8034905..e469deb 100644 --- a/SwifTools/UnitTest/SConscript +++ b/SwifTools/UnitTest/SConscript @@ -2,5 +2,6 @@ Import("env") env.Append(UNITTEST_SOURCES = [ File("LinkifyTest.cpp"), - File("TabCompleteTest.cpp") + File("TabCompleteTest.cpp"), + File("LastLineTrackerTest.cpp"), ]) diff --git a/SwifTools/UnitTest/TabCompleteTest.cpp b/SwifTools/UnitTest/TabCompleteTest.cpp index 2224839..0466484 100644 --- a/SwifTools/UnitTest/TabCompleteTest.cpp +++ b/SwifTools/UnitTest/TabCompleteTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "SwifTools/TabComplete.h" +#include <SwifTools/TabComplete.h> using namespace Swift; diff --git a/Swift/Controllers/AdHocManager.cpp b/Swift/Controllers/AdHocManager.cpp new file mode 100644 index 0000000..e926138 --- /dev/null +++ b/Swift/Controllers/AdHocManager.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/AdHocManager.h> + +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h> +#include <Swift/Controllers/UIInterfaces/MainWindow.h> +#include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h> + +namespace Swift { + +AdHocManager::AdHocManager(const JID& jid, AdHocCommandWindowFactory* factory, IQRouter* iqRouter, UIEventStream* uiEventStream, MainWindow* mainWindow) : jid_(jid) { + iqRouter_ = iqRouter; + uiEventStream_ = uiEventStream; + mainWindow_ = mainWindow; + factory_ = factory; + + uiEventStream_->onUIEvent.connect(boost::bind(&AdHocManager::handleUIEvent, this, _1)); +} + +AdHocManager::~AdHocManager() { + uiEventStream_->onUIEvent.disconnect(boost::bind(&AdHocManager::handleUIEvent, this, _1)); +} + +void AdHocManager::setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info) { + if (iqRouter_->isAvailable() && info->hasFeature(DiscoInfo::CommandsFeature)) { + if (discoItemsRequest_) { + discoItemsRequest_->onResponse.disconnect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2)); + discoItemsRequest_.reset(); + } + discoItemsRequest_ = GetDiscoItemsRequest::create(JID(jid_.getDomain()), DiscoInfo::CommandsFeature, iqRouter_); + discoItemsRequest_->onResponse.connect(boost::bind(&AdHocManager::handleServerDiscoItemsResponse, this, _1, _2)); + discoItemsRequest_->send(); + } else { + mainWindow_->setAvailableAdHocCommands(std::vector<DiscoItems::Item>()); + } + +} + +void AdHocManager::handleServerDiscoItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error) { + std::vector<DiscoItems::Item> commands; + if (!error) { + foreach (DiscoItems::Item item, items->getItems()) { + if (item.getNode() != "http://isode.com/xmpp/commands#test") { + commands.push_back(item); + } + } + } + mainWindow_->setAvailableAdHocCommands(commands); +} + +void AdHocManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { + boost::shared_ptr<RequestAdHocUIEvent> adHocEvent = boost::dynamic_pointer_cast<RequestAdHocUIEvent>(event); + if (adHocEvent) { + factory_->createAdHocCommandWindow(boost::make_shared<OutgoingAdHocCommandSession>(adHocEvent->getCommand().getJID(), adHocEvent->getCommand().getNode(), iqRouter_)); + } +} + +} diff --git a/Swift/Controllers/AdHocManager.h b/Swift/Controllers/AdHocManager.h new file mode 100644 index 0000000..47b03cd --- /dev/null +++ b/Swift/Controllers/AdHocManager.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <vector> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Elements/DiscoItems.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Disco/GetDiscoItemsRequest.h> +#include <Swift/Controllers/UIEvents/UIEvent.h> + +namespace Swift { + class IQRouter; + class MainWindow; + class UIEventStream; + class AdHocCommandWindowFactory; + class AdHocManager { + public: + AdHocManager(const JID& jid, AdHocCommandWindowFactory* factory, IQRouter* iqRouter, UIEventStream* uiEventStream, MainWindow* mainWindow); + ~AdHocManager(); + void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info); + private: + void handleUIEvent(boost::shared_ptr<UIEvent> event); + void handleServerDiscoItemsResponse(boost::shared_ptr<DiscoItems>, ErrorPayload::ref error); + JID jid_; + IQRouter* iqRouter_; + UIEventStream* uiEventStream_; + MainWindow* mainWindow_; + AdHocCommandWindowFactory* factory_; + GetDiscoItemsRequest::ref discoItemsRequest_; + }; +} diff --git a/Swift/Controllers/CertificateMemoryStorageFactory.h b/Swift/Controllers/CertificateMemoryStorageFactory.h new file mode 100644 index 0000000..adbce80 --- /dev/null +++ b/Swift/Controllers/CertificateMemoryStorageFactory.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/Storages/CertificateStorageFactory.h> +#include <Swift/Controllers/Storages/CertificateMemoryStorage.h> + +namespace Swift { + class CertificateFactory; + + class CertificateMemoryStorageFactory : public CertificateStorageFactory { + public: + CertificateMemoryStorageFactory() { + } + + virtual CertificateStorage* createCertificateStorage(const JID&) const { + return new CertificateMemoryStorage(); + } + + private: + boost::filesystem::path basePath; + CertificateFactory* certificateFactory; + }; +} diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 22ef68d..a3d9fb5 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -11,16 +11,22 @@ #include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> -#include "Swiften/Avatars/AvatarManager.h" -#include "Swiften/Chat/ChatStateNotifier.h" -#include "Swiften/Chat/ChatStateTracker.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Disco/EntityCapsProvider.h" -#include "Swift/Controllers/UIInterfaces/ChatWindow.h" -#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" -#include "Swiften/Client/NickResolver.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Avatars/AvatarManager.h> +#include <Swiften/Chat/ChatStateNotifier.h> +#include <Swiften/Chat/ChatStateTracker.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> +#include <Swiften/Client/NickResolver.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> +#include <Swift/Controllers/FileTransfer/FileTransferController.h> #include <Swift/Controllers/StatusUtil.h> +#include <Swiften/Disco/EntityCapsProvider.h> +#include <Swiften/Base/foreach.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIEvents/SendFileUIEvent.h> + namespace Swift { @@ -28,7 +34,7 @@ namespace Swift { * The controller does not gain ownership of the stanzaChannel, nor the factory. */ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider) - : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory) { + : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider), eventStream_(eventStream) { isInMUC_ = isInMUC; lastWasPresence_ = false; chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider); @@ -59,6 +65,11 @@ ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQ chatWindow_->addSystemMessage(startMessage); chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_)); chatWindow_->onUserCancelsTyping.connect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_)); + chatWindow_->onFileTransferStart.connect(boost::bind(&ChatController::handleFileTransferStart, this, _1, _2)); + chatWindow_->onFileTransferAccept.connect(boost::bind(&ChatController::handleFileTransferAccept, this, _1, _2)); + chatWindow_->onFileTransferCancel.connect(boost::bind(&ChatController::handleFileTransferCancel, this, _1)); + chatWindow_->onSendFileRequest.connect(boost::bind(&ChatController::handleSendFileRequest, this, _1)); + handleBareJIDCapsChanged(toJID_); } @@ -74,6 +85,19 @@ ChatController::~ChatController() { delete chatStateTracker_; } +void ChatController::handleBareJIDCapsChanged(const JID& /*jid*/) { + DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_); + if (disco) { + if (disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) { + chatWindow_->setCorrectionEnabled(ChatWindow::Yes); + } else { + chatWindow_->setCorrectionEnabled(ChatWindow::No); + } + } else { + chatWindow_->setCorrectionEnabled(ChatWindow::Maybe); + } +} + void ChatController::setToJID(const JID& jid) { chatStateNotifier_->setContact(jid); ChatControllerBase::setToJID(jid); @@ -84,6 +108,7 @@ void ChatController::setToJID(const JID& jid) { presence = jid.isBare() ? presenceOracle_->getHighestPriorityPresence(jid.toBare()) : presenceOracle_->getLastPresence(jid); } chatStateNotifier_->setContactIsOnline(presence && presence->getType() == Presence::Available); + handleBareJIDCapsChanged(toJID_); } bool ChatController::isIncomingMessageFromMe(boost::shared_ptr<Message>) { @@ -102,8 +127,8 @@ void ChatController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> me setToJID(from); } } - chatStateNotifier_->receivedMessageFromContact(message->getPayload<ChatState>()); chatStateTracker_->handleMessageReceived(message); + chatStateNotifier_->receivedMessageFromContact(message->getPayload<ChatState>()); } void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) { @@ -116,27 +141,33 @@ void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) { } void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) { - std::string id = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); - if (stanzaChannel_->getStreamManagementEnabled()) { - chatWindow_->setAckState(id, ChatWindow::Pending); - unackedStanzas_[sentStanza] = id; + boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>(); + if (replace) { + eraseIf(unackedStanzas_, PairSecondEquals<boost::shared_ptr<Stanza>, std::string>(myLastMessageUIID_)); + chatWindow_->replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time()); + } else { + myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); + } + if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty() ) { + chatWindow_->setAckState(myLastMessageUIID_, ChatWindow::Pending); + unackedStanzas_[sentStanza] = myLastMessageUIID_; } lastWasPresence_ = false; chatStateNotifier_->userSentMessage(); } void ChatController::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) { - std::string id = unackedStanzas_[stanza]; - if (id != "") { - chatWindow_->setAckState(id, ChatWindow::Received); + std::map<boost::shared_ptr<Stanza>, std::string>::iterator unackedStanza = unackedStanzas_.find(stanza); + if (unackedStanza != unackedStanzas_.end()) { + chatWindow_->setAckState(unackedStanza->second, ChatWindow::Received); + unackedStanzas_.erase(unackedStanza); } - unackedStanzas_.erase(unackedStanzas_.find(stanza)); } void ChatController::setOnline(bool online) { if (!online) { std::map<boost::shared_ptr<Stanza>, std::string>::iterator it = unackedStanzas_.begin(); - for ( ; it != unackedStanzas_.end(); it++) { + for ( ; it != unackedStanzas_.end(); ++it) { chatWindow_->setAckState(it->second, ChatWindow::Failed); } unackedStanzas_.clear(); @@ -149,6 +180,45 @@ void ChatController::setOnline(bool online) { ChatControllerBase::setOnline(online); } +void ChatController::handleNewFileTransferController(FileTransferController* ftc) { + std::string nick = senderDisplayNameFromMessage(ftc->getOtherParty()); + std::string ftID = ftc->setChatWindow(chatWindow_, nick); + + ftControllers[ftID] = ftc; +} + +void ChatController::handleFileTransferCancel(std::string id) { + std::cout << "handleFileTransferCancel(" << id << ")" << std::endl; + if (ftControllers.find(id) != ftControllers.end()) { + ftControllers[id]->cancel(); + } else { + std::cerr << "unknown file transfer UI id" << std::endl; + } +} + +void ChatController::handleFileTransferStart(std::string id, std::string description) { + std::cout << "handleFileTransferStart(" << id << ", " << description << ")" << std::endl; + if (ftControllers.find(id) != ftControllers.end()) { + ftControllers[id]->start(description); + } else { + std::cerr << "unknown file transfer UI id" << std::endl; + } +} + +void ChatController::handleFileTransferAccept(std::string id, std::string filename) { + std::cout << "handleFileTransferAccept(" << id << ", " << filename << ")" << std::endl; + if (ftControllers.find(id) != ftControllers.end()) { + ftControllers[id]->accept(filename); + } else { + std::cerr << "unknown file transfer UI id" << std::endl; + } +} + +void ChatController::handleSendFileRequest(std::string filename) { + std::cout << "ChatController::handleSendFileRequest(" << filename << ")" << std::endl; + eventStream_->send(boost::make_shared<SendFileUIEvent>(getToJID(), filename)); +} + std::string ChatController::senderDisplayNameFromMessage(const JID& from) { return nickResolver_->jidToNick(from); } diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index dd4bf90..2531adb 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -8,12 +8,16 @@ #include "Swift/Controllers/Chat/ChatControllerBase.h" +#include <map> +#include <string> + namespace Swift { class AvatarManager; class ChatStateNotifier; class ChatStateTracker; class NickResolver; class EntityCapsProvider; + class FileTransferController; class ChatController : public ChatControllerBase { public: @@ -21,6 +25,7 @@ namespace Swift { virtual ~ChatController(); virtual void setToJID(const JID& jid); virtual void setOnline(bool online); + virtual void handleNewFileTransferController(FileTransferController* ftc); private: void handlePresenceChange(boost::shared_ptr<Presence> newPresence); @@ -35,16 +40,26 @@ namespace Swift { void handleStanzaAcked(boost::shared_ptr<Stanza> stanza); void dayTicked() {lastWasPresence_ = false;} void handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/); + void handleBareJIDCapsChanged(const JID& jid); + + void handleFileTransferCancel(std::string /* id */); + void handleFileTransferStart(std::string /* id */, std::string /* description */); + void handleFileTransferAccept(std::string /* id */, std::string /* filename */); + void handleSendFileRequest(std::string filename); private: NickResolver* nickResolver_; ChatStateNotifier* chatStateNotifier_; ChatStateTracker* chatStateTracker_; + std::string myLastMessageUIID_; bool isInMUC_; bool lastWasPresence_; std::string lastStatusChangeString_; std::map<boost::shared_ptr<Stanza>, std::string> unackedStanzas_; StatusShow::Type lastShownStatus_; + UIEventStream* eventStream_; + + std::map<std::string, FileTransferController*> ftControllers; }; } diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index 281d968..df59c2f 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include "Swift/Controllers/Chat/ChatControllerBase.h" #include <sstream> +#include <map> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> @@ -20,6 +21,7 @@ #include "Swiften/Elements/Delay.h" #include "Swiften/Base/foreach.h" #include "Swift/Controllers/XMPPEvents/EventController.h" +#include "Swiften/Disco/EntityCapsProvider.h" #include "Swift/Controllers/UIInterfaces/ChatWindow.h" #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h" @@ -27,10 +29,11 @@ namespace Swift { -ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory) { +ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency), eventController_(eventController), timerFactory_(timerFactory), entityCapsProvider_(entityCapsProvider) { chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); - chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1)); + chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1, _2)); + entityCapsProvider_->onCapsChanged.connect(boost::bind(&ChatControllerBase::handleCapsChanged, this, _1)); setOnline(stanzaChannel->isAvailable() && iqRouter->isAvailable()); createDayChangeTimer(); } @@ -39,6 +42,12 @@ ChatControllerBase::~ChatControllerBase() { delete chatWindow_; } +void ChatControllerBase::handleCapsChanged(const JID& jid) { + if (jid.compare(toJID_, JID::WithoutResource) == 0) { + handleBareJIDCapsChanged(jid); + } +} + void ChatControllerBase::createDayChangeTimer() { if (timerFactory_) { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); @@ -81,14 +90,21 @@ void ChatControllerBase::setAvailableServerFeatures(boost::shared_ptr<DiscoInfo> } void ChatControllerBase::handleAllMessagesRead() { - foreach (boost::shared_ptr<MessageEvent> messageEvent, unreadMessages_) { - messageEvent->read(); + if (!unreadMessages_.empty()) { + foreach (boost::shared_ptr<MessageEvent> messageEvent, unreadMessages_) { + messageEvent->read(); + } + unreadMessages_.clear(); + chatWindow_->setUnreadMessageCount(0); + onUnreadCountChanged(); } - unreadMessages_.clear(); - chatWindow_->setUnreadMessageCount(0); } -void ChatControllerBase::handleSendMessageRequest(const std::string &body) { +int ChatControllerBase::getUnreadCount() { + return unreadMessages_.size(); +} + +void ChatControllerBase::handleSendMessageRequest(const std::string &body, bool isCorrectionMessage) { if (!stanzaChannel_->isAvailable() || body.empty()) { return; } @@ -104,8 +120,13 @@ void ChatControllerBase::handleSendMessageRequest(const std::string &body) { boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); message->addPayload(boost::shared_ptr<Delay>(new Delay(now, selfJID_))); } + if (isCorrectionMessage) { + message->addPayload(boost::shared_ptr<Replace> (new Replace(lastSentMessageStanzaID_))); + } + message->setID(lastSentMessageStanzaID_ = idGenerator_.generateID()); stanzaChannel_->sendMessage(message); postSendMessage(message->getBody(), boost::dynamic_pointer_cast<Stanza>(message)); + onActivity(message->getBody()); } void ChatControllerBase::handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog> catalog, ErrorPayload::ref error) { @@ -152,7 +173,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m boost::shared_ptr<Message> message = messageEvent->getStanza(); std::string body = message->getBody(); if (message->isError()) { - std::string errorMessage = getErrorMessage(message->getPayload<ErrorPayload>()); + std::string errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't send message: %1%")) % getErrorMessage(message->getPayload<ErrorPayload>())); chatWindow_->addErrorMessage(errorMessage); } else { @@ -163,7 +184,7 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m JID from = message->getFrom(); std::vector<boost::shared_ptr<Delay> > delayPayloads = message->getPayloads<Delay>(); for (size_t i = 0; useDelayForLatency_ && i < delayPayloads.size(); i++) { - if (!delayPayloads[i]->getFrom()) { + if (!delayPayloads[i]->getFrom()) { continue; } boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); @@ -179,11 +200,25 @@ void ChatControllerBase::handleIncomingMessage(boost::shared_ptr<MessageEvent> m if (messageTimeStamp) { timeStamp = *messageTimeStamp; } + onActivity(body); - addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp); + boost::shared_ptr<Replace> replace = message->getPayload<Replace>(); + if (replace) { + std::string body = message->getBody(); + // Should check if the user has a previous message + std::map<JID, std::string>::iterator lastMessage; + lastMessage = lastMessagesUIID_.find(from); + if (lastMessage != lastMessagesUIID_.end()) { + chatWindow_->replaceMessage(body, lastMessagesUIID_[from], timeStamp); + } + } + else { + lastMessagesUIID_[from] = addMessage(body, senderDisplayNameFromMessage(from), isIncomingMessageFromMe(message), label, std::string(avatarManager_->getAvatarPath(from).string()), timeStamp); + } } chatWindow_->show(); chatWindow_->setUnreadMessageCount(unreadMessages_.size()); + onUnreadCountChanged(); postHandleIncomingMessage(messageEvent); } diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 9573b1b..67bd74f 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ChatControllerBase_H -#define SWIFTEN_ChatControllerBase_H +#pragma once #include <map> #include <vector> @@ -26,6 +25,7 @@ #include "Swiften/Elements/ErrorPayload.h" #include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Queries/IQRouter.h" +#include "Swiften/Base/IDGenerator.h" namespace Swift { class IQRouter; @@ -35,6 +35,7 @@ namespace Swift { class AvatarManager; class UIEventStream; class EventController; + class EntityCapsProvider; class ChatControllerBase : public boost::bsignals::trackable { public: @@ -47,8 +48,14 @@ namespace Swift { virtual void setOnline(bool online); virtual void setEnabled(bool enabled); virtual void setToJID(const JID& jid) {toJID_ = jid;}; + /** Used for determining when something is recent.*/ + boost::signal<void (const std::string& /*activity*/)> onActivity; + boost::signal<void ()> onUnreadCountChanged; + int getUnreadCount(); + const JID& getToJID() {return toJID_;} + void handleCapsChanged(const JID& jid); protected: - ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory); + ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider); /** * Pass the Message appended, and the stanza used to send it. @@ -62,13 +69,16 @@ namespace Swift { virtual bool isFromContact(const JID& from); virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const = 0; virtual void dayTicked() {}; + virtual void handleBareJIDCapsChanged(const JID& jid) = 0; + std::string getErrorMessage(boost::shared_ptr<ErrorPayload>); private: + IDGenerator idGenerator_; + std::string lastSentMessageStanzaID_; void createDayChangeTimer(); - void handleSendMessageRequest(const std::string &body); + void handleSendMessageRequest(const std::string &body, bool isCorrectionMessage); void handleAllMessagesRead(); void handleSecurityLabelsCatalogResponse(boost::shared_ptr<SecurityLabelsCatalog>, ErrorPayload::ref error); - std::string getErrorMessage(boost::shared_ptr<ErrorPayload>); void handleDayChangeTick(); protected: @@ -80,13 +90,13 @@ namespace Swift { ChatWindow* chatWindow_; JID toJID_; bool labelsEnabled_; + std::map<JID, std::string> lastMessagesUIID_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; bool useDelayForLatency_; EventController* eventController_; boost::shared_ptr<Timer> dateChangeTimer_; TimerFactory* timerFactory_; + EntityCapsProvider* entityCapsProvider_; }; } - -#endif diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 94d4b9a..edc1a79 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,31 +7,40 @@ #include "Swift/Controllers/Chat/ChatsManager.h" #include <boost/bind.hpp> - -#include "Swift/Controllers/Chat/ChatController.h" -#include "Swift/Controllers/Chat/MUCSearchController.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swift/Controllers/Chat/MUCController.h" -#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" -#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" -#include "Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h" -#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h" -#include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h" -#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h" -#include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h" -#include "Swift/Controllers/UIInterfaces/JoinMUCWindow.h" -#include "Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h" -#include "Swiften/Presence/PresenceSender.h" -#include "Swiften/Client/NickResolver.h" -#include "Swiften/MUC/MUCManager.h" -#include "Swiften/Elements/ChatState.h" -#include "Swiften/MUC/MUCBookmarkManager.h" +#include <boost/algorithm/string.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swift/Controllers/Chat/ChatController.h> +#include <Swift/Controllers/Chat/ChatControllerBase.h> +#include <Swift/Controllers/Chat/MUCSearchController.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> +#include <Swift/Controllers/Chat/MUCController.h> +#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> +#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h> +#include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h> +#include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h> +#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h> +#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h> +#include <Swiften/Presence/PresenceSender.h> +#include <Swiften/Client/NickResolver.h> +#include <Swiften/MUC/MUCManager.h> +#include <Swiften/Elements/ChatState.h> +#include <Swiften/MUC/MUCBookmarkManager.h> +#include <Swift/Controllers/FileTransfer/FileTransferController.h> +#include <Swift/Controllers/FileTransfer/FileTransferOverview.h> +#include <Swift/Controllers/ProfileSettingsProvider.h> +#include <Swiften/Avatars/AvatarManager.h> namespace Swift { typedef std::pair<JID, ChatController*> JIDChatControllerPair; typedef std::pair<JID, MUCController*> JIDMUCControllerPair; +#define RECENT_CHATS "recent_chats" + ChatsManager::ChatsManager( JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, @@ -49,13 +58,15 @@ ChatsManager::ChatsManager( EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, - SettingsProvider* settings) : + ProfileSettingsProvider* settings, + FileTransferOverview* ftOverview) : jid_(jid), joinMUCWindowFactory_(joinMUCWindowFactory), useDelayForLatency_(useDelayForLatency), mucRegistry_(mucRegistry), entityCapsProvider_(entityCapsProvider), - mucManager(mucManager) { + mucManager(mucManager), + ftOverview_(ftOverview) { timerFactory_ = timerFactory; eventController_ = eventController; stanzaChannel_ = stanzaChannel; @@ -68,13 +79,21 @@ ChatsManager::ChatsManager( presenceSender_ = presenceSender; uiEventStream_ = uiEventStream; mucBookmarkManager_ = NULL; + profileSettings_ = settings; presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1)); uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1)); + chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_); + chatListWindow_->onMUCBookmarkActivated.connect(boost::bind(&ChatsManager::handleMUCBookmarkActivated, this, _1)); + chatListWindow_->onRecentActivated.connect(boost::bind(&ChatsManager::handleRecentActivated, this, _1)); + chatListWindow_->onClearRecentsRequested.connect(boost::bind(&ChatsManager::handleClearRecentsRequested, this)); + joinMUCWindow_ = NULL; mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, settings); mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1)); + ftOverview_->onNewFileTransferController.connect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1)); setupBookmarks(); + loadRecents(); } ChatsManager::~ChatsManager() { @@ -89,6 +108,72 @@ ChatsManager::~ChatsManager() { delete mucSearchController_; } +void ChatsManager::saveRecents() { + std::string recents; + int i = 1; + foreach (ChatListWindow::Chat chat, recentChats_) { + std::vector<std::string> activity; + boost::split(activity, chat.activity, boost::is_any_of("\t\n")); + if (activity.size() == 0) { + /* Work around Boost bug https://svn.boost.org/trac/boost/ticket/4751 */ + activity.push_back(""); + } + std::string recent = chat.jid.toString() + "\t" + activity[0] + "\t" + (chat.isMUC ? "true" : "false") + "\t" + chat.nick; + recents += recent + "\n"; + if (i++ > 25) { + break; + } + } + profileSettings_->storeString(RECENT_CHATS, recents); +} + +void ChatsManager::handleClearRecentsRequested() { + recentChats_.clear(); + saveRecents(); + handleUnreadCountChanged(NULL); +} + +void ChatsManager::loadRecents() { + std::string recentsString(profileSettings_->getStringSetting(RECENT_CHATS)); + std::vector<std::string> recents; + boost::split(recents, recentsString, boost::is_any_of("\n")); + int i = 0; + foreach (std::string recentString, recents) { + if (i++ > 30) { + break; + } + std::vector<std::string> recent; + boost::split(recent, recentString, boost::is_any_of("\t")); + if (recent.size() < 4) { + continue; + } + JID jid(recent[0]); + if (!jid.isValid()) { + continue; + } + std::string activity(recent[1]); + bool isMUC = recent[2] == "true"; + std::string nick(recent[3]); + StatusShow::Type type = StatusShow::None; + boost::filesystem::path path; + if (isMUC) { + if (mucControllers_.find(jid.toBare()) != mucControllers_.end()) { + type = StatusShow::Online; + } + } else { + if (avatarManager_) { + path = avatarManager_->getAvatarPath(jid); + } + Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid.toBare()); + type = presence ? presence->getShow() : StatusShow::None; + } + + ChatListWindow::Chat chat(jid, nickResolver_->jidToNick(jid), activity, 0, type, path, isMUC, nick); + prependRecent(chat); + } + handleUnreadCountChanged(NULL); +} + void ChatsManager::setupBookmarks() { if (!mucBookmarkManager_) { mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_); @@ -98,7 +183,7 @@ void ChatsManager::setupBookmarks() { if (chatListWindow_) { chatListWindow_->setBookmarksEnabled(false); - chatListWindow_->clear(); + chatListWindow_->clearBookmarks(); } } } @@ -122,10 +207,90 @@ void ChatsManager::handleMUCBookmarkRemoved(const MUCBookmark& bookmark) { chatListWindow_->removeMUCBookmark(bookmark); } +ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const std::string& activity) { + int unreadCount = 0; + if (mucRegistry_->isMUC(jid)) { + MUCController* controller = mucControllers_[jid.toBare()]; + StatusShow::Type type = StatusShow::None; + std::string nick = ""; + if (controller) { + unreadCount = controller->getUnreadCount(); + if (controller->isJoined()) { + type = StatusShow::Online; + } + nick = controller->getNick(); + } + return ChatListWindow::Chat(jid, jid.toString(), activity, unreadCount, type, boost::filesystem::path(), true, nick); + + } else { + ChatController* controller = getChatControllerIfExists(jid, false); + if (controller) { + unreadCount = controller->getUnreadCount(); + } + JID bareishJID = mucRegistry_->isMUC(jid.toBare()) ? jid : jid.toBare(); + Presence::ref presence = presenceOracle_->getHighestPriorityPresence(bareishJID); + StatusShow::Type type = presence ? presence->getShow() : StatusShow::None; + boost::filesystem::path avatarPath = avatarManager_ ? avatarManager_->getAvatarPath(bareishJID) : boost::filesystem::path(); + return ChatListWindow::Chat(bareishJID, nickResolver_->jidToNick(bareishJID), activity, unreadCount, type, avatarPath, false); + } +} + +void ChatsManager::handleChatActivity(const JID& jid, const std::string& activity, bool isMUC) { + if (mucRegistry_->isMUC(jid.toBare()) && !isMUC) { + /* Don't include PMs in MUC rooms.*/ + return; + } + ChatListWindow::Chat chat = createChatListChatItem(jid, activity); + /* FIXME: handle nick changes */ + appendRecent(chat); + handleUnreadCountChanged(NULL); + saveRecents(); +} + +void ChatsManager::handleUnreadCountChanged(ChatControllerBase* controller) { + int unreadTotal = 0; + bool controllerIsMUC = dynamic_cast<MUCController*>(controller); + bool isPM = controller && !controllerIsMUC && mucRegistry_->isMUC(controller->getToJID().toBare()); + foreach (ChatListWindow::Chat& chatItem, recentChats_) { + bool match = false; + if (controller) { + /* Matching MUC item */ + match |= chatItem.isMUC == controllerIsMUC && chatItem.jid.toBare() == controller->getToJID().toBare(); + /* Matching PM */ + match |= isPM && chatItem.jid == controller->getToJID(); + /* Matching non-PM */ + match |= !isPM && !controllerIsMUC && chatItem.jid.toBare() == controller->getToJID().toBare(); + } + if (match) { + chatItem.setUnreadCount(controller->getUnreadCount()); + } + unreadTotal += chatItem.unreadCount; + } + chatListWindow_->setRecents(recentChats_); + chatListWindow_->setUnreadCount(unreadTotal); +} + +void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) { + recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end()); + recentChats_.push_front(chat); +} + +void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) { + recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end()); + recentChats_.push_back(chat); +} + void ChatsManager::handleUserLeftMUC(MUCController* mucController) { std::map<JID, MUCController*>::iterator it; - for (it = mucControllers_.begin(); it != mucControllers_.end(); it++) { + for (it = mucControllers_.begin(); it != mucControllers_.end(); ++it) { if ((*it).second == mucController) { + foreach (ChatListWindow::Chat& chat, recentChats_) { + if (chat.isMUC && chat.jid == (*it).first) { + chat.statusType = StatusShow::None; + chatListWindow_->setRecents(recentChats_); + break; + } + } mucControllers_.erase(it); delete mucController; return; @@ -155,15 +320,15 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark()); } else if (JoinMUCUIEvent::ref joinEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event)) { - handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getNick(), false); + handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getNick(), joinEvent->getShouldJoinAutomatically()); + mucControllers_[joinEvent->getJID()]->activateChatWindow(); } - else if (boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) { + else if (boost::shared_ptr<RequestJoinMUCUIEvent> joinEvent = boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) { if (!joinMUCWindow_) { - joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow(); - joinMUCWindow_->onJoinMUC.connect(boost::bind(&ChatsManager::handleJoinMUCRequest, this, _1, _2, _3)); + joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow(uiEventStream_); joinMUCWindow_->onSearchMUC.connect(boost::bind(&ChatsManager::handleSearchMUCRequest, this)); } - joinMUCWindow_->setMUC(""); + joinMUCWindow_->setMUC(joinEvent->getRoom()); joinMUCWindow_->setNick(nickResolver_->jidToNick(jid_)); joinMUCWindow_->show(); } @@ -174,6 +339,16 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { */ void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> newPresence) { if (mucRegistry_->isMUC(newPresence->getFrom().toBare())) return; + + foreach (ChatListWindow::Chat& chat, recentChats_) { + if (newPresence->getFrom().toBare() == chat.jid.toBare() && !chat.isMUC) { + Presence::ref presence = presenceOracle_->getHighestPriorityPresence(chat.jid.toBare()); + chat.setStatusType(presence ? presence->getShow() : StatusShow::None); + chatListWindow_->setRecents(recentChats_); + break; + } + } + //if (newPresence->getType() != Presence::Unavailable) return; JID fullJID(newPresence->getFrom()); std::map<JID, ChatController*>::iterator it = chatControllers_.find(fullJID); @@ -185,7 +360,25 @@ void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> newPresence) } void ChatsManager::setAvatarManager(AvatarManager* avatarManager) { + if (avatarManager_) { + avatarManager_->onAvatarChanged.disconnect(boost::bind(&ChatsManager::handleAvatarChanged, this, _1)); + } avatarManager_ = avatarManager; + foreach (ChatListWindow::Chat& chat, recentChats_) { + if (!chat.isMUC) { + chat.setAvatarPath(avatarManager_->getAvatarPath(chat.jid)); + } + } + avatarManager_->onAvatarChanged.connect(boost::bind(&ChatsManager::handleAvatarChanged, this, _1)); +} + +void ChatsManager::handleAvatarChanged(const JID& jid) { + foreach (ChatListWindow::Chat& chat, recentChats_) { + if (!chat.isMUC && jid.toBare() == chat.jid.toBare()) { + chat.setAvatarPath(avatarManager_->getAvatarPath(jid)); + break; + } + } } void ChatsManager::setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info) { @@ -244,6 +437,8 @@ ChatController* ChatsManager::createNewChatController(const JID& contact) { ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_); chatControllers_[contact] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); + controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false)); + controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller)); return controller; } @@ -252,7 +447,7 @@ ChatController* ChatsManager::getChatControllerOrCreate(const JID &contact) { return controller ? controller : createNewChatController(contact); } -ChatController* ChatsManager::getChatControllerIfExists(const JID &contact) { +ChatController* ChatsManager::getChatControllerIfExists(const JID &contact, bool rebindIfNeeded) { if (chatControllers_.find(contact) == chatControllers_.end()) { if (mucRegistry_->isMUC(contact.toBare())) { return NULL; @@ -264,8 +459,13 @@ ChatController* ChatsManager::getChatControllerIfExists(const JID &contact) { } else { foreach (JIDChatControllerPair pair, chatControllers_) { if (pair.first.toBare() == contact.toBare()) { - rebindControllerJID(pair.first, contact); - return chatControllers_[contact]; + if (rebindIfNeeded) { + rebindControllerJID(pair.first, contact); + return chatControllers_[contact]; + } else { + return pair.second; + } + } } return NULL; @@ -280,8 +480,8 @@ void ChatsManager::rebindControllerJID(const JID& from, const JID& to) { chatControllers_[to]->setToJID(to); } -void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& nickMaybe, bool autoJoin) { - if (autoJoin) { +void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& nickMaybe, bool addAutoJoin) { + if (addAutoJoin) { MUCBookmark bookmark(mucJID, mucJID.getNode()); bookmark.setAutojoin(true); if (nickMaybe) { @@ -296,12 +496,17 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional } else { std::string nick = nickMaybe ? nickMaybe.get() : jid_.getNode(); MUC::ref muc = mucManager->createMUC(mucJID); - MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_); + MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_); mucControllers_[mucJID] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller)); + controller->onUserJoined.connect(boost::bind(&ChatsManager::handleChatActivity, this, mucJID.toBare(), "", true)); + controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, mucJID.toBare(), _1, true)); + controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller)); + handleChatActivity(mucJID.toBare(), "", true); } - mucControllers_[mucJID]->activateChatWindow(); + + mucControllers_[mucJID]->showChatWindow(); } void ChatsManager::handleSearchMUCRequest() { @@ -311,7 +516,7 @@ void ChatsManager::handleSearchMUCRequest() { void ChatsManager::handleIncomingMessage(boost::shared_ptr<Message> message) { JID jid = message->getFrom(); boost::shared_ptr<MessageEvent> event(new MessageEvent(message)); - if (!event->isReadable() && !message->getPayload<ChatState>() && message->getSubject().empty()) { + if (!event->isReadable() && !message->getPayload<ChatState>() && !message->hasSubject()) { return; } @@ -338,5 +543,24 @@ void ChatsManager::handleMUCSelectedAfterSearch(const JID& muc) { } } +void ChatsManager::handleMUCBookmarkActivated(const MUCBookmark& mucBookmark) { + uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(mucBookmark.getRoom(), mucBookmark.getNick())); +} + +void ChatsManager::handleNewFileTransferController(FileTransferController* ftc) { + ChatController* chatController = getChatControllerOrCreate(ftc->getOtherParty()); + chatController->handleNewFileTransferController(ftc); + chatController->activateChatWindow(); +} + +void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) { + if (chat.isMUC) { + uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(chat.jid, chat.nick)); + } + else { + uiEventStream_->send(boost::make_shared<RequestChatUIEvent>(chat.jid)); + } +} + } diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 3740186..57643eb 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,17 +11,19 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/JID/JID.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swift/Controllers/UIEvents/UIEventStream.h" -#include "Swiften/MUC/MUCBookmark.h" +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/JID/JID.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIInterfaces/ChatListWindow.h> +#include <Swiften/MUC/MUCBookmark.h> namespace Swift { class EventController; class ChatController; + class ChatControllerBase; class MUCController; class MUCManager; class ChatWindowFactory; @@ -34,26 +36,29 @@ namespace Swift { class IQRouter; class PresenceSender; class MUCBookmarkManager; - class ChatListWindow; class ChatListWindowFactory; class TimerFactory; class EntityCapsProvider; class DirectedPresenceSender; class MUCSearchWindowFactory; - class SettingsProvider; + class ProfileSettingsProvider; class MUCSearchController; - + class FileTransferOverview; + class FileTransferController; + class ChatsManager { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, SettingsProvider* settings); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* settings, FileTransferOverview* ftOverview); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setOnline(bool enabled); void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info); void handleIncomingMessage(boost::shared_ptr<Message> message); + private: + ChatListWindow::Chat createChatListChatItem(const JID& jid, const std::string& activity); void handleChatRequest(const std::string& contact); - void handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& nick, bool autoJoin); + void handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& nick, bool addAutoJoin); void handleSearchMUCRequest(); void handleMUCSelectedAfterSearch(const JID&); void rebindControllerJID(const JID& from, const JID& to); @@ -63,11 +68,26 @@ namespace Swift { void handleMUCBookmarkRemoved(const MUCBookmark& bookmark); void handleUserLeftMUC(MUCController* mucController); void handleBookmarksReady(); + void handleChatActivity(const JID& jid, const std::string& activity, bool isMUC); + void handleNewFileTransferController(FileTransferController*); + void appendRecent(const ChatListWindow::Chat& chat); + void prependRecent(const ChatListWindow::Chat& chat); void setupBookmarks(); + void loadRecents(); + void saveRecents(); + void handleChatMadeRecent(); + void handleMUCBookmarkActivated(const MUCBookmark&); + void handleRecentActivated(const ChatListWindow::Chat&); + void handleUnreadCountChanged(ChatControllerBase* controller); + void handleAvatarChanged(const JID& jid); + void handleClearRecentsRequested(); + ChatController* getChatControllerOrFindAnother(const JID &contact); ChatController* createNewChatController(const JID &contact); ChatController* getChatControllerOrCreate(const JID &contact); - ChatController* getChatControllerIfExists(const JID &contact); + ChatController* getChatControllerIfExists(const JID &contact, bool rebindIfNeeded = true); + + private: std::map<JID, MUCController*> mucControllers_; std::map<JID, ChatController*> chatControllers_; EventController* eventController_; @@ -92,5 +112,8 @@ namespace Swift { EntityCapsProvider* entityCapsProvider_; MUCManager* mucManager; MUCSearchController* mucSearchController_; + std::list<ChatListWindow::Chat> recentChats_; + ProfileSettingsProvider* profileSettings_; + FileTransferOverview* ftOverview_; }; } diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 2914116..e1d02ae 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swift/Controllers/Chat/MUCController.h" +#include <Swift/Controllers/Chat/MUCController.h> #include <boost/bind.hpp> #include <boost/regex.hpp> @@ -12,23 +12,26 @@ #include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> -#include "Swiften/Network/Timer.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Base/foreach.h" -#include "SwifTools/TabComplete.h" -#include "Swiften/Base/foreach.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swift/Controllers/UIInterfaces/ChatWindow.h" -#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" -#include "Swift/Controllers/UIEvents/UIEventStream.h" -#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" -#include "Swiften/Avatars/AvatarManager.h" -#include "Swiften/Elements/Delay.h" -#include "Swiften/MUC/MUC.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swift/Controllers/Roster/Roster.h" -#include "Swift/Controllers/Roster/SetAvatar.h" -#include "Swift/Controllers/Roster/SetPresence.h" +#include <Swiften/Network/Timer.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Base/foreach.h> +#include <SwifTools/TabComplete.h> +#include <Swiften/Base/foreach.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swiften/Avatars/AvatarManager.h> +#include <Swiften/Elements/Delay.h> +#include <Swiften/MUC/MUC.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/SetAvatar.h> +#include <Swift/Controllers/Roster/SetPresence.h> +#include <Swiften/Disco/EntityCapsProvider.h> #define MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS 60000 @@ -50,8 +53,9 @@ MUCController::MUCController ( UIEventStream* uiEventStream, bool useDelayForLatency, TimerFactory* timerFactory, - EventController* eventController) : - ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory), muc_(muc), nick_(nick), desiredNick_(nick) { + EventController* eventController, + EntityCapsProvider* entityCapsProvider) : + ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider), muc_(muc), nick_(nick), desiredNick_(nick) { parting_ = true; joined_ = false; lastWasPresence_ = false; @@ -65,12 +69,19 @@ MUCController::MUCController ( chatWindow_->setTabComplete(completer_); chatWindow_->setName(muc->getJID().getNode()); chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this)); + chatWindow_->onOccupantSelectionChanged.connect(boost::bind(&MUCController::handleWindowOccupantSelectionChanged, this, _1)); + chatWindow_->onOccupantActionSelected.connect(boost::bind(&MUCController::handleActionRequestedOnOccupant, this, _1, _2)); + chatWindow_->onChangeSubjectRequest.connect(boost::bind(&MUCController::handleChangeSubjectRequest, this, _1)); + chatWindow_->onConfigureRequest.connect(boost::bind(&MUCController::handleConfigureRequest, this, _1)); + chatWindow_->onDestroyRequest.connect(boost::bind(&MUCController::handleDestroyRoomRequest, this)); muc_->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1)); muc_->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1)); muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); muc_->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1)); muc_->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); muc_->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3)); + muc_->onConfigurationFailed.connect(boost::bind(&MUCController::handleConfigurationFailed, this, _1)); + muc_->onConfigurationFormReceived.connect(boost::bind(&MUCController::handleConfigurationFormReceived, this, _1)); if (timerFactory) { loginCheckTimer_ = boost::shared_ptr<Timer>(timerFactory->createTimer(MUC_JOIN_WARNING_TIMEOUT_MILLISECONDS)); loginCheckTimer_->onTick.connect(boost::bind(&MUCController::handleJoinTimeoutTick, this)); @@ -81,6 +92,7 @@ MUCController::MUCController ( if (avatarManager_ != NULL) { avatarChangedConnection_ = (avatarManager_->onAvatarChanged.connect(boost::bind(&MUCController::handleAvatarChanged, this, _1))); } + handleBareJIDCapsChanged(muc->getJID()); } MUCController::~MUCController() { @@ -93,6 +105,38 @@ MUCController::~MUCController() { delete completer_; } +void MUCController::handleWindowOccupantSelectionChanged(ContactRosterItem* item) { + std::vector<ChatWindow::OccupantAction> actions; + //FIXME + if (item) { + actions.push_back(ChatWindow::Kick); + } + chatWindow_->setAvailableOccupantActions(actions); +} + +void MUCController::handleActionRequestedOnOccupant(ChatWindow::OccupantAction action, ContactRosterItem* item) { + switch (action) { + case ChatWindow::Kick: muc_->kickUser(item->getJID());break; + } +} + +void MUCController::handleBareJIDCapsChanged(const JID& /*jid*/) { + ChatWindow::Tristate support = ChatWindow::Yes; + bool any = false; + foreach (const std::string& nick, currentOccupants_) { + DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_.toBare().toString() + "/" + nick); + if (disco && disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) { + any = true; + } else { + support = ChatWindow::Maybe; + } + } + if (!any) { + support = ChatWindow::No; + } + chatWindow_->setCorrectionEnabled(support); +} + /** * Join the MUC if not already in it. */ @@ -109,6 +153,14 @@ void MUCController::rejoin() { } } +bool MUCController::isJoined() { + return joined_; +} + +const std::string& MUCController::getNick() { + return nick_; +} + void MUCController::handleJoinTimeoutTick() { receivedActivity(); chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "Room %1% is not responding. This operation may never complete.")) % toJID_.toString())); @@ -158,7 +210,7 @@ void MUCController::handleJoinFailed(boost::shared_ptr<ErrorPayload> error) { default: break; } } - errorMessage += "."; + errorMessage = str(format(QT_TRANSLATE_NOOP("", "Couldn't join room: %1%.")) % errorMessage); chatWindow_->addErrorMessage(errorMessage); if (!rejoinNick.empty()) { nick_ = rejoinNick; @@ -176,6 +228,7 @@ void MUCController::handleJoinComplete(const std::string& nick) { clearPresenceQueue(); shouldJoinOnReconnect_ = true; setEnabled(true); + onUserJoined(); } void MUCController::handleAvatarChanged(const JID& jid) { @@ -206,7 +259,9 @@ void MUCController::handleOccupantJoined(const MUCOccupant& occupant) { currentOccupants_.insert(occupant.getNick()); NickJoinPart event(occupant.getNick(), Join); appendToJoinParts(joinParts_, event); - roster_->addContact(jid, realJID, occupant.getNick(), roleToGroupName(occupant.getRole()), avatarManager_->getAvatarPath(jid).string()); + std::string groupName(roleToGroupName(occupant.getRole())); + roster_->addContact(jid, realJID, occupant.getNick(), groupName, avatarManager_->getAvatarPath(jid).string()); + roster_->getGroup(groupName)->setManualSort(roleToSortName(occupant.getRole())); if (joined_) { std::string joinString; MUCOccupant::Role role = occupant.getRole(); @@ -248,6 +303,16 @@ std::string MUCController::roleToFriendlyName(MUCOccupant::Role role) { return ""; } +std::string MUCController::roleToSortName(MUCOccupant::Role role) { + switch (role) { + case MUCOccupant::Moderator: return "1"; + case MUCOccupant::Participant: return "2"; + case MUCOccupant::Visitor: return "3"; + case MUCOccupant::NoRole: return "4"; + } + return "5"; +} + JID MUCController::nickToJID(const std::string& nick) { return JID(toJID_.getNode(), toJID_.getDomain(), nick); } @@ -279,8 +344,9 @@ void MUCController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> mes receivedActivity(); joined_ = true; - if (!message->getSubject().empty() && message->getBody().empty()) { + if (message->hasSubject() && message->getBody().empty()) { chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "The room subject is now: %1%")) % message->getSubject()));; + chatWindow_->setSubject(message->getSubject()); doneGettingHistory_ = true; } @@ -309,7 +375,9 @@ void MUCController::handleOccupantRoleChanged(const std::string& nick, const MUC if (occupant.getRealJID()) { realJID = occupant.getRealJID().get(); } - roster_->addContact(jid, realJID, nick, roleToGroupName(occupant.getRole()), avatarManager_->getAvatarPath(jid).string()); + std::string group(roleToGroupName(occupant.getRole())); + roster_->addContact(jid, realJID, nick, group, avatarManager_->getAvatarPath(jid).string()); + roster_->getGroup(group)->setManualSort(roleToSortName(occupant.getRole())); chatWindow_->addSystemMessage(str(format(QT_TRANSLATE_NOOP("", "%1% is now a %2%")) % nick % roleToFriendlyName(occupant.getRole()))); } @@ -411,7 +479,7 @@ void MUCController::updateJoinParts() { void MUCController::appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent) { std::vector<NickJoinPart>::iterator it = joinParts.begin(); bool matched = false; - for (; it != joinParts.end(); it++) { + for (; it != joinParts.end(); ++it) { if ((*it).nick == newEvent.nick) { matched = true; JoinPart type = (*it).type; @@ -508,4 +576,31 @@ std::string MUCController::generateJoinPartString(const std::vector<NickJoinPart return result; } +void MUCController::handleChangeSubjectRequest(const std::string& subject) { + muc_->changeSubject(subject); +} + +void MUCController::handleConfigureRequest(Form::ref form) { + if (form) { + muc_->configureRoom(form); + } + else { + muc_->requestConfigurationForm(); + } +} + +void MUCController::handleConfigurationFailed(ErrorPayload::ref error) { + std::string errorMessage = getErrorMessage(error); + errorMessage = str(format(QT_TRANSLATE_NOOP("", "Room configuration failed: %1%.")) % errorMessage); + chatWindow_->addErrorMessage(errorMessage); +} + +void MUCController::handleConfigurationFormReceived(Form::ref form) { + chatWindow_->showRoomConfigurationForm(form); +} + +void MUCController::handleDestroyRoomRequest() { + muc_->destroyRoom(); +} + } diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index ebdd6cd..7a7461b 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -7,23 +7,24 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/signals/connection.hpp> -#include <set> +#include <set> #include <string> -#include "Swiften/Network/Timer.h" -#include "Swift/Controllers/Chat/ChatControllerBase.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/JID/JID.h" -#include "Swiften/MUC/MUC.h" -#include "Swiften/Elements/MUCOccupant.h" +#include <Swiften/Network/Timer.h> +#include <Swift/Controllers/Chat/ChatControllerBase.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/JID/JID.h> +#include <Swiften/MUC/MUC.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swift/Controllers/Roster/RosterItem.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> namespace Swift { class StanzaChannel; class IQRouter; - class ChatWindow; class ChatWindowFactory; class Roster; class AvatarManager; @@ -41,14 +42,17 @@ namespace Swift { class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController); + MUCController(const JID& self, MUC::ref muc, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider); ~MUCController(); boost::signal<void ()> onUserLeft; + boost::signal<void ()> onUserJoined; virtual void setOnline(bool online); void rejoin(); static void appendToJoinParts(std::vector<NickJoinPart>& joinParts, const NickJoinPart& newEvent); static std::string generateJoinPartString(const std::vector<NickJoinPart>& joinParts); static std::string concatenateListOfNames(const std::vector<NickJoinPart>& joinParts); + bool isJoined(); + const std::string& getNick(); protected: void preSendMessageRequest(boost::shared_ptr<Message> message); @@ -61,6 +65,8 @@ namespace Swift { private: void clearPresenceQueue(); void addPresenceMessage(const std::string& message); + void handleWindowOccupantSelectionChanged(ContactRosterItem* item); + void handleActionRequestedOnOccupant(ChatWindow::OccupantAction, ContactRosterItem* item); void handleWindowClosed(); void handleAvatarChanged(const JID& jid); void handleOccupantJoined(const MUCOccupant& occupant); @@ -70,7 +76,9 @@ namespace Swift { void handleJoinComplete(const std::string& nick); void handleJoinFailed(boost::shared_ptr<ErrorPayload> error); void handleJoinTimeoutTick(); + void handleChangeSubjectRequest(const std::string&); std::string roleToGroupName(MUCOccupant::Role role); + std::string roleToSortName(MUCOccupant::Role role); JID nickToJID(const std::string& nick); std::string roleToFriendlyName(MUCOccupant::Role role); void receivedActivity(); @@ -79,6 +87,11 @@ namespace Swift { bool shouldUpdateJoinParts(); void dayTicked() {lastWasPresence_ = false;} void processUserPart(); + void handleBareJIDCapsChanged(const JID& jid); + void handleConfigureRequest(Form::ref); + void handleConfigurationFailed(ErrorPayload::ref); + void handleConfigurationFormReceived(Form::ref); + void handleDestroyRoomRequest(); private: MUC::ref muc_; diff --git a/Swift/Controllers/Chat/MUCSearchController.cpp b/Swift/Controllers/Chat/MUCSearchController.cpp index 743aabb..5312fa7 100644 --- a/Swift/Controllers/Chat/MUCSearchController.cpp +++ b/Swift/Controllers/Chat/MUCSearchController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,19 +11,20 @@ #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/foreach.h> #include <Swiften/Disco/GetDiscoItemsRequest.h> #include <Swiften/Base/Log.h> #include <Swiften/Base/String.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h> -#include <Swift/Controllers/DiscoServiceWalker.h> +#include <Swiften/Disco/DiscoServiceWalker.h> #include <Swiften/Client/NickResolver.h> namespace Swift { static const std::string SEARCHED_SERVICES = "searchedServices"; -MUCSearchController::MUCSearchController(const JID& jid, MUCSearchWindowFactory* factory, IQRouter* iqRouter, SettingsProvider* settings) : jid_(jid), factory_(factory), iqRouter_(iqRouter), settings_(settings), window_(NULL), walker_(NULL) { +MUCSearchController::MUCSearchController(const JID& jid, MUCSearchWindowFactory* factory, IQRouter* iqRouter, ProfileSettingsProvider* settings) : jid_(jid), factory_(factory), iqRouter_(iqRouter), settings_(settings), window_(NULL), walker_(NULL) { itemsInProgress_ = 0; loadSavedServices(); } diff --git a/Swift/Controllers/Chat/MUCSearchController.h b/Swift/Controllers/Chat/MUCSearchController.h index c8040ed..f90e4a7 100644 --- a/Swift/Controllers/Chat/MUCSearchController.h +++ b/Swift/Controllers/Chat/MUCSearchController.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -16,7 +16,7 @@ #include "Swiften/JID/JID.h" #include "Swift/Controllers/UIEvents/UIEvent.h" -#include "Swift/Controllers/Settings/SettingsProvider.h" +#include "Swift/Controllers/ProfileSettingsProvider.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Elements/DiscoItems.h" #include "Swiften/Elements/ErrorPayload.h" @@ -87,7 +87,7 @@ namespace Swift { class MUCSearchController { public: - MUCSearchController(const JID& jid, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter, SettingsProvider* settings); + MUCSearchController(const JID& jid, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter, ProfileSettingsProvider* settings); ~MUCSearchController(); void openSearchWindow(); @@ -112,7 +112,7 @@ namespace Swift { JID jid_; MUCSearchWindowFactory* factory_; IQRouter* iqRouter_; - SettingsProvider* settings_; + ProfileSettingsProvider* settings_; MUCSearchWindow* window_; DiscoServiceWalker* walker_; std::list<JID> services_; diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 40f7445..5339703 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -8,8 +8,11 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include "3rdParty/hippomocks.h" +#include <boost/bind.hpp> + #include "Swift/Controllers/Chat/ChatsManager.h" +#include "Swift/Controllers/Chat/UnitTest/MockChatListWindow.h" #include "Swift/Controllers/UIInterfaces/ChatWindow.h" #include "Swift/Controllers/Settings/DummySettingsProvider.h" #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" @@ -35,10 +38,14 @@ #include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Queries/DummyIQChannel.h" #include "Swiften/Presence/PresenceOracle.h" +#include "Swiften/Jingle/JingleSessionManager.h" +#include "Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h" #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" - +#include <Swift/Controllers/ProfileSettingsProvider.h> +#include "Swift/Controllers/FileTransfer/FileTransferOverview.h" +#include <Swiften/Base/Algorithm.h> using namespace Swift; @@ -59,7 +66,7 @@ class ChatsManagerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE_END(); public: - void setUp() { + void setUp() { mocks_ = new MockRepository(); jid_ = JID("test@test.com/resource"); stanzaChannel_ = new DummyStanzaChannel(); @@ -82,19 +89,25 @@ public: chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>(); mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>(); settings_ = new DummySettingsProvider(); - mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(NULL); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, settings_); + profileSettings_ = new ProfileSettingsProvider("a", settings_); + chatListWindow_ = new MockChatListWindow(); + ftManager_ = new DummyFileTransferManager(); + ftOverview_ = new FileTransferOverview(ftManager_); + mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_); + manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_); avatarManager_ = new NullAvatarManager(); manager_->setAvatarManager(avatarManager_); }; void tearDown() { - //delete chatListWindowFactory_; + //delete chatListWindowFactory delete settings_; - delete mocks_; + delete profileSettings_; delete avatarManager_; delete manager_; + delete ftOverview_; + delete ftManager_; delete directedPresenceSender_; delete presenceSender_; delete presenceOracle_; @@ -109,6 +122,8 @@ public: delete xmppRoster_; delete entityCapsManager_; delete capsProvider_; + delete chatListWindow_; + delete mocks_; } void testFirstOpenWindowIncoming() { @@ -346,6 +361,10 @@ private: CapsProvider* capsProvider_; MUCManager* mucManager_; DummySettingsProvider* settings_; + ProfileSettingsProvider* profileSettings_; + ChatListWindow* chatListWindow_; + FileTransferOverview* ftOverview_; + FileTransferManager* ftManager_; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest); diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 5f5e44d..ad5ceac 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -25,6 +25,7 @@ #include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Network/TimerFactory.h" #include "Swiften/Elements/MUCUserPayload.h" +#include "Swiften/Disco/DummyEntityCapsProvider.h" using namespace Swift; @@ -56,12 +57,14 @@ public: TimerFactory* timerFactory = NULL; window_ = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mucRegistry_ = new MUCRegistry(); + entityCapsProvider_ = new DummyEntityCapsProvider(); muc_ = MUC::ref(new MUC(stanzaChannel_, iqRouter_, directedPresenceSender_, JID("teaparty@rooms.wonderland.lit"), mucRegistry_)); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(muc_->getJID(), uiEventStream_).Return(window_); - controller_ = new MUCController (self_, muc_, nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_); + controller_ = new MUCController (self_, muc_, nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_); }; void tearDown() { + delete entityCapsProvider_; delete controller_; delete eventController_; delete presenceOracle_; @@ -240,6 +243,7 @@ private: UIEventStream* uiEventStream_; MockChatWindow* window_; MUCRegistry* mucRegistry_; + DummyEntityCapsProvider* entityCapsProvider_; }; CPPUNIT_TEST_SUITE_REGISTRATION(MUCControllerTest); diff --git a/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h new file mode 100644 index 0000000..6ac8d4a --- /dev/null +++ b/Swift/Controllers/Chat/UnitTest/MockChatListWindow.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swift/Controllers/UIInterfaces/ChatListWindow.h" + +namespace Swift { + + class MockChatListWindow : public ChatListWindow { + public: + MockChatListWindow() {}; + virtual ~MockChatListWindow() {}; + void addMUCBookmark(const MUCBookmark& /*bookmark*/) {} + void removeMUCBookmark(const MUCBookmark& /*bookmark*/) {} + void setBookmarksEnabled(bool /*enabled*/) {} + void setRecents(const std::list<ChatListWindow::Chat>& /*recents*/) {} + void setUnreadCount(int /*unread*/) {} + void clearBookmarks() {} + }; + +} diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp index b3403d7..3e734df 100644 --- a/Swift/Controllers/Chat/UserSearchController.cpp +++ b/Swift/Controllers/Chat/UserSearchController.cpp @@ -9,10 +9,10 @@ #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/foreach.h> #include <Swiften/Disco/GetDiscoInfoRequest.h> #include <Swiften/Disco/GetDiscoItemsRequest.h> - -#include <Swift/Controllers/DiscoServiceWalker.h> +#include <Swiften/Disco/DiscoServiceWalker.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h> #include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> @@ -85,12 +85,12 @@ void UserSearchController::endDiscoWalker() { void UserSearchController::handleDiscoServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> info) { - bool isUserDirectory = false; + //bool isUserDirectory = false; bool supports55 = false; foreach (DiscoInfo::Identity identity, info->getIdentities()) { if ((identity.getCategory() == "directory" && identity.getType() == "user")) { - isUserDirectory = true; + //isUserDirectory = true; } } std::vector<std::string> features = info->getFeatures(); diff --git a/Swift/Controllers/ChatMessageSummarizer.cpp b/Swift/Controllers/ChatMessageSummarizer.cpp new file mode 100644 index 0000000..d95a177 --- /dev/null +++ b/Swift/Controllers/ChatMessageSummarizer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/ChatMessageSummarizer.h> + +#include <Swiften/Base/format.h> +#include <Swift/Controllers/Intl.h> +#include <Swiften/Base/foreach.h> + +using namespace Swift; +using namespace std; + +string ChatMessageSummarizer::getSummary(const string& current, const vector<UnreadPair>& unreads) { + vector<UnreadPair> others; + int currentUnread = 0; + int otherCount = 0; + foreach (UnreadPair unread, unreads) { + if (unread.first == current) { + currentUnread += unread.second; + } else { + if (unread.second > 0) { + otherCount += unread.second; + others.push_back(unread); + } + } + } + string myString(current); + + if (currentUnread > 0) { + string result(QT_TRANSLATE_NOOP("", "%1% (%2%)")); + myString = str(format(result) % current % currentUnread); + } + + if (others.size() > 1) { + string result(QT_TRANSLATE_NOOP("", "%1% and %2% others (%3%)")); + myString = str(format(result) % myString % others.size() % otherCount); + } else if (!others.empty()) { + string result(QT_TRANSLATE_NOOP("", "%1%, %2% (%3%)")); + myString = str(format(result) % myString % others[0].first % otherCount); + } + return myString; +} diff --git a/Swift/Controllers/ChatMessageSummarizer.h b/Swift/Controllers/ChatMessageSummarizer.h new file mode 100644 index 0000000..d4ff188 --- /dev/null +++ b/Swift/Controllers/ChatMessageSummarizer.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <utility> +#include <string> + +namespace Swift { +typedef std::pair<std::string, int> UnreadPair; + + class ChatMessageSummarizer { + public: + std::string getSummary(const std::string& current, const std::vector<UnreadPair>& unreads); + }; +} diff --git a/Swift/Controllers/EventWindowController.cpp b/Swift/Controllers/EventWindowController.cpp index fbe9a8a..47554ce 100644 --- a/Swift/Controllers/EventWindowController.cpp +++ b/Swift/Controllers/EventWindowController.cpp @@ -27,8 +27,11 @@ void EventWindowController::handleEventQueueEventAdded(boost::shared_ptr<StanzaE if (event->getConcluded()) { handleEventConcluded(event); } else { - event->onConclusion.connect(boost::bind(&EventWindowController::handleEventConcluded, this, event)); - window_->addEvent(event, true); + boost::shared_ptr<MessageEvent> message = boost::dynamic_pointer_cast<MessageEvent>(event); + if (!(message && message->isReadable())) { + event->onConclusion.connect(boost::bind(&EventWindowController::handleEventConcluded, this, event)); + window_->addEvent(event, true); + } } } diff --git a/Swift/Controllers/FileTransfer/FileTransferController.cpp b/Swift/Controllers/FileTransfer/FileTransferController.cpp new file mode 100644 index 0000000..afa907d --- /dev/null +++ b/Swift/Controllers/FileTransfer/FileTransferController.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "FileTransferController.h" +#include "Swiften/FileTransfer/OutgoingJingleFileTransfer.h" +#include "Swiften/FileTransfer/FileTransferManager.h" +#include <Swiften/FileTransfer/FileReadBytestream.h> +#include <Swiften/Base/boost_bsignals.h> +#include <boost/bind.hpp> +#include "Swift/Controllers/UIInterfaces/ChatWindow.h" + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +FileTransferController::FileTransferController(const JID& receipient, const std::string& filename, FileTransferManager* fileTransferManager) : + sending(true), otherParty(receipient), filename(filename), ftManager(fileTransferManager), ftProgressInfo(0), chatWindow(0), currentState(FileTransfer::State::WaitingForStart) { + +} + +FileTransferController::FileTransferController(IncomingFileTransfer::ref transfer) : + sending(false), otherParty(transfer->getSender()), filename(transfer->filename), transfer(transfer), ftManager(0), ftProgressInfo(0), chatWindow(0), currentState(FileTransfer::State::WaitingForStart) { + +} + +FileTransferController::~FileTransferController() { + delete ftProgressInfo; +} + +const JID &FileTransferController::getOtherParty() const { + return otherParty; +} + +std::string FileTransferController::setChatWindow(ChatWindow* wnd, std::string nickname) { + chatWindow = wnd; + if (sending) { + uiID = wnd->addFileTransfer("me", true, filename, boost::filesystem::file_size(boost::filesystem::path(filename))); + } else { + uiID = wnd->addFileTransfer(nickname, false, filename, transfer->fileSizeInBytes); + } + return uiID; +} + +void FileTransferController::setReceipient(const JID& receipient) { + this->otherParty = receipient; +} + +bool FileTransferController::isIncoming() const { + return !sending; +} + +FileTransfer::State FileTransferController::getState() const { + return currentState; +} + +int FileTransferController::getProgress() const { + return ftProgressInfo ? ftProgressInfo->getPercentage() : 0; +} + +boost::uintmax_t FileTransferController::getSize() const { + if (transfer) { + return transfer->fileSizeInBytes; + } else { + return 0; + } +} + +void FileTransferController::start(std::string& description) { + std::cout << "FileTransferController::start" << std::endl; + fileReadStream = boost::make_shared<FileReadBytestream>(boost::filesystem::path(filename)); + OutgoingFileTransfer::ref outgoingTransfer = ftManager->createOutgoingFileTransfer(otherParty, boost::filesystem::path(filename), description, fileReadStream); + if (outgoingTransfer) { + ftProgressInfo = new FileTransferProgressInfo(outgoingTransfer->fileSizeInBytes); + ftProgressInfo->onProgressPercentage.connect(boost::bind(&FileTransferController::handleProgressPercentageChange, this, _1)); + outgoingTransfer->onStateChange.connect(boost::bind(&FileTransferController::handleFileTransferStateChange, this, _1)); + outgoingTransfer->onProcessedBytes.connect(boost::bind(&FileTransferProgressInfo::setBytesProcessed, ftProgressInfo, _1)); + outgoingTransfer->start(); + transfer = outgoingTransfer; + } else { + std::cerr << "File transfer not supported!" << std::endl; + } +} + +void FileTransferController::accept(std::string& file) { + std::cout << "FileTransferController::accept" << std::endl; + IncomingFileTransfer::ref incomingTransfer = boost::dynamic_pointer_cast<IncomingFileTransfer>(transfer); + if (incomingTransfer) { + fileWriteStream = boost::make_shared<FileWriteBytestream>(boost::filesystem::path(file)); + + ftProgressInfo = new FileTransferProgressInfo(transfer->fileSizeInBytes); + ftProgressInfo->onProgressPercentage.connect(boost::bind(&FileTransferController::handleProgressPercentageChange, this, _1)); + transfer->onStateChange.connect(boost::bind(&FileTransferController::handleFileTransferStateChange, this, _1)); + transfer->onProcessedBytes.connect(boost::bind(&FileTransferProgressInfo::setBytesProcessed, ftProgressInfo, _1)); + incomingTransfer->accept(fileWriteStream); + } else { + std::cerr << "Expected an incoming transfer in this situation!" << std::endl; + } +} + +void FileTransferController::cancel() { + if (transfer) { + transfer->cancel(); + } else { + chatWindow->setFileTransferStatus(uiID, ChatWindow::Canceled); + } +} + +void FileTransferController::handleFileTransferStateChange(FileTransfer::State state) { + currentState = state; + onStateChage(); + switch(state.state) { + case FileTransfer::State::Negotiating: + chatWindow->setFileTransferStatus(uiID, ChatWindow::Negotiating); + return; + case FileTransfer::State::Transferring: + chatWindow->setFileTransferStatus(uiID, ChatWindow::Transferring); + return; + case FileTransfer::State::Canceled: + chatWindow->setFileTransferStatus(uiID, ChatWindow::Canceled); + return; + case FileTransfer::State::Finished: + chatWindow->setFileTransferStatus(uiID, ChatWindow::Finished); + if (fileWriteStream) { + fileWriteStream->close(); + } + return; + case FileTransfer::State::Failed: + chatWindow->setFileTransferStatus(uiID, ChatWindow::FTFailed); + return; + case FileTransfer::State::WaitingForAccept: + chatWindow->setFileTransferStatus(uiID, ChatWindow::WaitingForAccept); + return; + case FileTransfer::State::WaitingForStart: + return; + } + std::cerr << "Unhandled FileTransfer::State!" << std::endl; +} + +void FileTransferController::handleProgressPercentageChange(int percentage) { + onProgressChange(); + chatWindow->setFileTransferProgress(uiID, percentage); +} + +} diff --git a/Swift/Controllers/FileTransfer/FileTransferController.h b/Swift/Controllers/FileTransfer/FileTransferController.h new file mode 100644 index 0000000..3d6f7d5 --- /dev/null +++ b/Swift/Controllers/FileTransfer/FileTransferController.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +#include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> + +#include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/FileTransfer.h> +#include <Swiften/FileTransfer/IncomingFileTransfer.h> +#include <Swiften/FileTransfer/FileReadBytestream.h> +#include <Swiften/FileTransfer/FileWriteBytestream.h> +#include <Swift/Controllers/FileTransfer/FileTransferProgressInfo.h> + +namespace Swift { + +class FileTransferManager; +class ChatWindow; + +class FileTransferController { +public: + /** + * For outgoing file transfers. It'll create a file transfer via FileTransferManager as soon as the descriptive information is available. + */ + FileTransferController(const JID&, const std::string&, FileTransferManager*); + + /** + * For incoming file transfers. + */ + FileTransferController(IncomingFileTransfer::ref transfer); + ~FileTransferController(); + + std::string setChatWindow(ChatWindow*, std::string nickname); + void setReceipient(const JID& otherParty); + + void start(std::string& description); + void accept(std::string& file); + void cancel(); + + const JID &getOtherParty() const; + bool isIncoming() const; + FileTransfer::State getState() const; + int getProgress() const; + boost::uintmax_t getSize() const; + + boost::signal<void ()> onStateChage; + boost::signal<void ()> onProgressChange; + +private: + void handleFileTransferStateChange(FileTransfer::State); + void handleProgressPercentageChange(int percentage); + +private: + bool sending; + JID otherParty; + std::string filename; + FileTransfer::ref transfer; + boost::shared_ptr<FileReadBytestream> fileReadStream; + boost::shared_ptr<FileWriteBytestream> fileWriteStream; + FileTransferManager* ftManager; + FileTransferProgressInfo* ftProgressInfo; + ChatWindow* chatWindow; + std::string uiID; + FileTransfer::State currentState; +}; + +} diff --git a/Swift/Controllers/FileTransfer/FileTransferOverview.cpp b/Swift/Controllers/FileTransfer/FileTransferOverview.cpp new file mode 100644 index 0000000..c3ffc5c --- /dev/null +++ b/Swift/Controllers/FileTransfer/FileTransferOverview.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "FileTransferOverview.h" + +#include <boost/bind.hpp> +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/FileTransfer/FileTransferManager.h> + +namespace Swift { + +FileTransferOverview::FileTransferOverview(FileTransferManager* ftm) : fileTransferManager(ftm) { + fileTransferManager->onIncomingFileTransfer.connect(boost::bind(&FileTransferOverview::handleIncomingFileTransfer, this, _1)); +} + +FileTransferOverview::~FileTransferOverview() { + +} + +void FileTransferOverview::sendFile(const JID& jid, const std::string& filename) { + FileTransferController* controller = new FileTransferController(jid, filename, fileTransferManager); + fileTransfers.push_back(controller); + + onNewFileTransferController(controller); +} + +void FileTransferOverview::handleIncomingFileTransfer(IncomingFileTransfer::ref transfer) { + FileTransferController* controller = new FileTransferController(transfer); + fileTransfers.push_back(controller); + onNewFileTransferController(controller); +} + +const std::vector<FileTransferController*>& FileTransferOverview::getFileTransfers() const { + return fileTransfers; +} + +} diff --git a/Swift/Controllers/FileTransfer/FileTransferOverview.h b/Swift/Controllers/FileTransfer/FileTransferOverview.h new file mode 100644 index 0000000..716666a --- /dev/null +++ b/Swift/Controllers/FileTransfer/FileTransferOverview.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> + +#include "Swift/Controllers/FileTransfer/FileTransferController.h" + +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + +class ChatsManager; +class FileTransferManager; + +class FileTransferOverview { +public: + FileTransferOverview(FileTransferManager*); + ~FileTransferOverview(); + + void sendFile(const JID&, const std::string&); + const std::vector<FileTransferController*>& getFileTransfers() const; + + boost::signal<void (FileTransferController*)> onNewFileTransferController; + +private: + void handleIncomingFileTransfer(IncomingFileTransfer::ref transfer); + +private: + std::vector<FileTransferController*> fileTransfers; + FileTransferManager *fileTransferManager; +}; + +} diff --git a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp new file mode 100644 index 0000000..6d19fa1 --- /dev/null +++ b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "FileTransferProgressInfo.h" + +#include <Swiften/Base/Log.h> + +namespace Swift { + +FileTransferProgressInfo::FileTransferProgressInfo(boost::uintmax_t completeBytes) : completeBytes(completeBytes), completedBytes(0), percentage(0) { + onProgressPercentage(0); +} + +void FileTransferProgressInfo::setBytesProcessed(int processedBytes) { + int oldPercentage = int(double(completedBytes) / double(completeBytes) * 100.0); + completedBytes += processedBytes; + int newPercentage = int(double(completedBytes) / double(completeBytes) * 100.0); + if (oldPercentage != newPercentage) { + onProgressPercentage(newPercentage); + } + percentage = newPercentage; +} + +int FileTransferProgressInfo::getPercentage() const { + return percentage; +} + +} diff --git a/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h new file mode 100644 index 0000000..bb3c0fc --- /dev/null +++ b/Swift/Controllers/FileTransfer/FileTransferProgressInfo.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + +class FileTransferProgressInfo { +public: + FileTransferProgressInfo(boost::uintmax_t completeBytes); + +public: + void setBytesProcessed(int processedBytes); + + int getPercentage() const; + boost::signal<void (int)> onProgressPercentage; + +private: + boost::uintmax_t completeBytes; + boost::uintmax_t completedBytes; + int percentage; +}; + +} diff --git a/Swift/Controllers/FileTransferListController.cpp b/Swift/Controllers/FileTransferListController.cpp new file mode 100644 index 0000000..093a3c4 --- /dev/null +++ b/Swift/Controllers/FileTransferListController.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "Swift/Controllers/FileTransferListController.h" + +#include <boost/bind.hpp> + +#include "Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h" +#include "Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h" + +namespace Swift { + +FileTransferListController::FileTransferListController(UIEventStream* uiEventStream, FileTransferListWidgetFactory* fileTransferListWidgetFactory) : fileTransferListWidgetFactory(fileTransferListWidgetFactory), fileTransferListWidget(NULL), fileTransferOverview(0) { + uiEventStream->onUIEvent.connect(boost::bind(&FileTransferListController::handleUIEvent, this, _1)); +} + +FileTransferListController::~FileTransferListController() { + delete fileTransferListWidget; +} + +void FileTransferListController::setFileTransferOverview(FileTransferOverview *overview) { + fileTransferOverview = overview; + if (fileTransferListWidget) { + fileTransferListWidget->setFileTransferOverview(fileTransferOverview); + } +} + +void FileTransferListController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) { + boost::shared_ptr<RequestFileTransferListUIEvent> event = boost::dynamic_pointer_cast<RequestFileTransferListUIEvent>(rawEvent); + if (event != NULL) { + if (fileTransferListWidget == NULL) { + fileTransferListWidget = fileTransferListWidgetFactory->createFileTransferListWidget(); + if (fileTransferOverview) { + fileTransferListWidget->setFileTransferOverview(fileTransferOverview); + } + } + fileTransferListWidget->show(); + fileTransferListWidget->activate(); + } +} + +} diff --git a/Swift/Controllers/FileTransferListController.h b/Swift/Controllers/FileTransferListController.h new file mode 100644 index 0000000..c5c8893 --- /dev/null +++ b/Swift/Controllers/FileTransferListController.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include "Swift/Controllers/UIEvents/UIEventStream.h" + +namespace Swift { + +class FileTransferListWidgetFactory; +class FileTransferListWidget; +class FileTransferOverview; + +class FileTransferListController { +public: + FileTransferListController(UIEventStream* uiEventStream, FileTransferListWidgetFactory* fileTransferListWidgetFactory); + ~FileTransferListController(); + + void setFileTransferOverview(FileTransferOverview* overview); + +private: + void handleUIEvent(boost::shared_ptr<UIEvent> event); + +private: + FileTransferListWidgetFactory* fileTransferListWidgetFactory; + FileTransferListWidget* fileTransferListWidget; + FileTransferOverview* fileTransferOverview; +}; + +} diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 9a35cc1..364dd57 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -14,14 +14,13 @@ #include <stdlib.h> #include <Swiften/Base/format.h> +#include <Swiften/Base/Algorithm.h> #include <Swift/Controllers/Intl.h> #include <Swift/Controllers/UIInterfaces/UIFactory.h> #include "Swiften/Network/TimerFactory.h" #include "Swift/Controllers/BuildVersion.h" -#include "Swift/Controllers/StoragesFactory.h" #include "Swiften/Client/Storages.h" #include "Swiften/VCards/VCardManager.h" -#include "Swift/Controllers/Chat/MUCSearchController.h" #include "Swift/Controllers/Chat/UserSearchController.h" #include "Swift/Controllers/Chat/ChatsManager.h" #include "Swift/Controllers/XMPPEvents/EventController.h" @@ -38,9 +37,11 @@ #include "Swift/Controllers/SystemTray.h" #include "Swift/Controllers/SystemTrayController.h" #include "Swift/Controllers/XMLConsoleController.h" +#include "Swift/Controllers/FileTransferListController.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/Controllers/PresenceNotifier.h" #include "Swift/Controllers/EventNotifier.h" +#include "Swift/Controllers/Storages/StoragesFactory.h" #include "SwifTools/Dock/Dock.h" #include "SwifTools/Notifier/TogglableNotifier.h" #include "Swiften/Base/foreach.h" @@ -60,11 +61,17 @@ #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" #include "Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" -#include "Swift/Controllers/CertificateStorageFactory.h" -#include "Swift/Controllers/CertificateStorageTrustChecker.h" +#include "Swift/Controllers/Storages/CertificateStorageFactory.h" +#include "Swift/Controllers/Storages/CertificateStorageTrustChecker.h" #include "Swiften/Network/NetworkFactories.h" #include <Swift/Controllers/ProfileController.h> #include <Swift/Controllers/ContactEditController.h> +#include <Swift/Controllers/XMPPURIController.h> +#include "Swift/Controllers/AdHocManager.h" +#include <SwifTools/Idle/IdleDetector.h> +#include <Swift/Controllers/FileTransfer/FileTransferOverview.h> +#include <Swiften/FileTransfer/FileTransferManager.h> +#include <Swiften/Client/ClientXMLTracer.h> namespace Swift { @@ -84,16 +91,22 @@ MainController::MainController( CertificateStorageFactory* certificateStorageFactory, Dock* dock, Notifier* notifier, - bool useDelayForLatency) : + URIHandler* uriHandler, + IdleDetector* idleDetector, + bool useDelayForLatency, + bool eagleMode) : eventLoop_(eventLoop), networkFactories_(networkFactories), uiFactory_(uiFactories), - idleDetector_(&idleQuerier_, networkFactories_->getTimerFactory(), 100), storagesFactory_(storagesFactory), certificateStorageFactory_(certificateStorageFactory), settings_(settings), + uriHandler_(uriHandler), + idleDetector_(idleDetector), loginWindow_(NULL) , - useDelayForLatency_(useDelayForLatency) { + useDelayForLatency_(useDelayForLatency), + eagleMode_(eagleMode), + ftOverview_(NULL) { storages_ = NULL; certificateStorage_ = NULL; statusTracker_ = NULL; @@ -121,33 +134,43 @@ MainController::MainController( loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_); soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, uiEventStream_); + xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_); + std::string selectedLoginJID = settings_->getStringSetting("lastLoginJID"); bool loginAutomatically = settings_->getBoolSetting("loginAutomatically", false); std::string cachedPassword; std::string cachedCertificate; - foreach (std::string profile, settings->getAvailableProfiles()) { - ProfileSettingsProvider profileSettings(profile, settings); - std::string password = profileSettings.getStringSetting("pass"); - std::string certificate = profileSettings.getStringSetting("certificate"); - std::string jid = profileSettings.getStringSetting("jid"); - loginWindow_->addAvailableAccount(jid, password, certificate); - if (jid == selectedLoginJID) { - cachedPassword = password; - cachedCertificate = certificate; + if (!eagleMode_) { + foreach (std::string profile, settings->getAvailableProfiles()) { + ProfileSettingsProvider profileSettings(profile, settings); + std::string password = eagleMode ? "" : profileSettings.getStringSetting("pass"); + std::string certificate = profileSettings.getStringSetting("certificate"); + std::string jid = profileSettings.getStringSetting("jid"); + loginWindow_->addAvailableAccount(jid, password, certificate); + if (jid == selectedLoginJID) { + cachedPassword = password; + cachedCertificate = certificate; + } } + loginWindow_->selectUser(selectedLoginJID); + loginWindow_->setLoginAutomatically(loginAutomatically); + } else { + loginWindow_->setRememberingAllowed(false); } - loginWindow_->selectUser(selectedLoginJID); - loginWindow_->setLoginAutomatically(loginAutomatically); + + loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5)); loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&MainController::handlePurgeSavedLoginRequest, this, _1)); loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this)); loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this)); - idleDetector_.setIdleTimeSeconds(600); - idleDetector_.onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1)); + idleDetector_->setIdleTimeSeconds(600); + idleDetector_->onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1)); xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_); + fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_); + uiEventStream_->onUIEvent.connect(boost::bind(&MainController::handleUIEvent, this, _1)); bool enabled = settings_->getBoolSetting(SHOW_NOTIFICATIONS, true); uiEventStream_->send(boost::shared_ptr<ToggleNotificationsUIEvent>(new ToggleNotificationsUIEvent(enabled))); @@ -161,12 +184,16 @@ MainController::MainController( } MainController::~MainController() { + idleDetector_->onIdleChanged.disconnect(boost::bind(&MainController::handleInputIdleChanged, this, _1)); + + purgeCachedCredentials(); //setManagersOffline(); eventController_->disconnectAll(); resetClient(); - + delete fileTransferListController_; delete xmlConsoleController_; + delete xmppURIController_; delete soundEventController_; delete systemTrayController_; delete eventController_; @@ -174,7 +201,12 @@ MainController::~MainController() { delete uiEventStream_; } +void MainController::purgeCachedCredentials() { + safeClear(password_); +} + void MainController::resetClient() { + purgeCachedCredentials(); resetCurrentError(); resetPendingReconnects(); vCardPhotoHash_.clear(); @@ -186,6 +218,8 @@ void MainController::resetClient() { eventWindowController_ = NULL; delete chatsManager_; chatsManager_ = NULL; + delete ftOverview_; + ftOverview_ = NULL; delete rosterController_; rosterController_ = NULL; delete eventNotifier_; @@ -234,20 +268,30 @@ void MainController::resetCurrentError() { void MainController::handleConnected() { boundJID_ = client_->getJID(); - loginWindow_->setIsLoggingIn(false); resetCurrentError(); resetPendingReconnects(); + + if (eagleMode_) { + purgeCachedCredentials(); + } + bool freshLogin = rosterController_ == NULL; myStatusLooksOnline_ = true; if (freshLogin) { profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_); - rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_); + srand(time(NULL)); + int randomPort = 10000 + rand() % 10000; + client_->getFileTransferManager()->startListeningOnPort(randomPort); + ftOverview_ = new FileTransferOverview(client_->getFileTransferManager()); + fileTransferListController_->setFileTransferOverview(ftOverview_); + rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); contactEditController_ = new ContactEditController(rosterController_, uiFactory_, uiEventStream_); - chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, settings_); + chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_); + client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(client_->getAvatarManager()); @@ -259,17 +303,25 @@ void MainController::handleConnected() { discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); discoInfo.addFeature(DiscoInfo::ChatStatesFeature); discoInfo.addFeature(DiscoInfo::SecurityLabelsFeature); + discoInfo.addFeature(DiscoInfo::MessageCorrectionFeature); +#ifdef SWIFT_EXPERIMENTAL_FT + discoInfo.addFeature(DiscoInfo::JingleFeature); + discoInfo.addFeature(DiscoInfo::JingleFTFeature); + discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature); + discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature); +#endif client_->getDiscoManager()->setCapsNode(CLIENT_NODE); client_->getDiscoManager()->setDiscoInfo(discoInfo); - userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_); userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_); + adHocManager_ = new AdHocManager(boundJID_, uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow()); } - + loginWindow_->setIsLoggingIn(false); + client_->requestRoster(); - GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(), client_->getIQRouter()); + GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(boundJID_.toBare(), client_->getIQRouter()); discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); @@ -356,19 +408,27 @@ void MainController::handleInputIdleChanged(bool idle) { } void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificateFile, bool remember, bool loginAutomatically) { - loginWindow_->setMessage(""); - loginWindow_->setIsLoggingIn(true); - profileSettings_ = new ProfileSettingsProvider(username, settings_); - profileSettings_->storeString("jid", username); - profileSettings_->storeString("certificate", certificateFile); - profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : ""); - settings_->storeString("lastLoginJID", username); - settings_->storeBool("loginAutomatically", loginAutomatically); - loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate")); jid_ = JID(username); - password_ = password; - certificateFile_ = certificateFile; - performLoginFromCachedCredentials(); + if (!jid_.isValid() || jid_.getNode().empty()) { + loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'")); + loginWindow_->setIsLoggingIn(false); + } else { + loginWindow_->setMessage(""); + loginWindow_->setIsLoggingIn(true); + profileSettings_ = new ProfileSettingsProvider(username, settings_); + if (!eagleMode_) { + profileSettings_->storeString("jid", username); + profileSettings_->storeString("certificate", certificateFile); + profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : ""); + settings_->storeString("lastLoginJID", username); + settings_->storeBool("loginAutomatically", loginAutomatically); + loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate")); + } + + password_ = password; + certificateFile_ = certificateFile; + performLoginFromCachedCredentials(); + } } void MainController::handlePurgeSavedLoginRequest(const std::string& username) { @@ -377,6 +437,10 @@ void MainController::handlePurgeSavedLoginRequest(const std::string& username) { } void MainController::performLoginFromCachedCredentials() { + if (eagleMode_ && password_.empty()) { + /* Then we can't try to login again. */ + return; + } /* If we logged in with a bare JID, and we have a full bound JID, re-login with the * bound JID to try and keep dynamically assigned resources */ JID clientJID = jid_; @@ -392,7 +456,7 @@ void MainController::performLoginFromCachedCredentials() { certificateStorage_ = certificateStorageFactory_->createCertificateStorage(jid_.toBare()); certificateTrustChecker_ = new CertificateStorageTrustChecker(certificateStorage_); - client_ = boost::make_shared<Swift::Client>(clientJID, password_, networkFactories_, storages_); + client_ = boost::make_shared<Swift::Client>(clientJID, createSafeByteArray(password_.c_str()), networkFactories_, storages_); clientInitialized_ = true; client_->setCertificateTrustChecker(certificateTrustChecker_); client_->onDataRead.connect(boost::bind(&XMLConsoleController::handleDataRead, xmlConsoleController_, _1)); @@ -422,11 +486,16 @@ void MainController::performLoginFromCachedCredentials() { if (rosterController_) { rosterController_->getWindow()->setConnecting(); } - - client_->connect(); + ClientOptions clientOptions; + clientOptions.forgetPassword = eagleMode_; + clientOptions.useTLS = eagleMode_ ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable; + client_->connect(clientOptions); } void MainController::handleDisconnected(const boost::optional<ClientError>& error) { + if (eagleMode_) { + purgeCachedCredentials(); + } if (quitRequested_) { resetClient(); loginWindow_->quit(); @@ -483,19 +552,27 @@ void MainController::handleDisconnected(const boost::optional<ClientError>& erro else if (!rosterController_) { //hasn't been logged in yet signOut(); loginWindow_->setMessage(message); + loginWindow_->setIsLoggingIn(false); } else { logout(); - setReconnectTimer(); - if (lastDisconnectError_) { - message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % boost::lexical_cast<std::string>(timeBeforeNextReconnect_)); - lastDisconnectError_->conclude(); + if (eagleMode_) { + message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%. To reconnect, Sign Out and provide your password again.")) % jid_.getDomain() % message); } else { - message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%.")) % jid_.getDomain() % message); + setReconnectTimer(); + if (lastDisconnectError_) { + message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % boost::lexical_cast<std::string>(timeBeforeNextReconnect_)); + lastDisconnectError_->conclude(); + } else { + message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%.")) % jid_.getDomain() % message); + } + lastDisconnectError_ = boost::shared_ptr<ErrorEvent>(new ErrorEvent(JID(jid_.getDomain()), message)); + eventController_->handleIncomingEvent(lastDisconnectError_); } - lastDisconnectError_ = boost::shared_ptr<ErrorEvent>(new ErrorEvent(JID(jid_.getDomain()), message)); - eventController_->handleIncomingEvent(lastDisconnectError_); } } + else if (!rosterController_) { //hasn't been logged in yet + loginWindow_->setIsLoggingIn(false); + } } void MainController::setReconnectTimer() { @@ -517,6 +594,9 @@ void MainController::handleCancelLoginRequest() { } void MainController::signOut() { + if (eagleMode_) { + purgeCachedCredentials(); + } eventController_->clear(); logout(); loginWindow_->loggedOut(); @@ -524,6 +604,9 @@ void MainController::signOut() { } void MainController::logout() { + if (eagleMode_) { + purgeCachedCredentials(); + } systemTrayController_->setMyStatusType(StatusShow::None); if (clientInitialized_ /*&& client_->isAvailable()*/) { client_->disconnect(); @@ -554,11 +637,12 @@ void MainController::setManagersOffline() { void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) { if (!error) { chatsManager_->setServerDiscoInfo(info); + adHocManager_->setServerDiscoInfo(info); } } void MainController::handleVCardReceived(const JID& jid, VCard::ref vCard) { - if (!jid.equals(jid_, JID::WithoutResource) || !vCard || vCard->getPhoto().isEmpty()) { + if (!jid.equals(jid_, JID::WithoutResource) || !vCard || vCard->getPhoto().empty()) { return; } std::string hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index f402f8f..12028d7 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,8 +11,6 @@ #include <vector> #include "Swiften/Network/Timer.h" -#include "SwifTools/Idle/PlatformIdleQuerier.h" -#include "SwifTools/Idle/ActualIdleDetector.h" #include <string> #include "Swiften/Client/ClientError.h" #include "Swiften/JID/JID.h" @@ -25,8 +23,10 @@ #include "Swiften/Elements/CapsInfo.h" #include "Swift/Controllers/XMPPEvents/ErrorEvent.h" #include "Swift/Controllers/UIEvents/UIEvent.h" +#include "Swiften/Client/ClientXMLTracer.h" namespace Swift { + class IdleDetector; class UIFactory; class EventLoop; class Client; @@ -52,6 +52,7 @@ namespace Swift { class SoundEventController; class SoundPlayer; class XMLConsoleController; + class FileTransferListController; class UIEventStream; class EventWindowFactory; class EventWindowController; @@ -62,6 +63,11 @@ namespace Swift { class Storages; class StoragesFactory; class NetworkFactories; + class URIHandler; + class XMPPURIController; + class AdHocManager; + class AdHocCommandWindowFactory; + class FileTransferOverview; class MainController { public: @@ -76,7 +82,10 @@ namespace Swift { CertificateStorageFactory* certificateStorageFactory, Dock* dock, Notifier* notifier, - bool useDelayForLatency); + URIHandler* uriHandler, + IdleDetector* idleDetector, + bool useDelayForLatency, + bool eagleMode); ~MainController(); @@ -106,13 +115,12 @@ namespace Swift { void setManagersOffline(); void handleNotificationClicked(const JID& jid); void handleForceQuit(); + void purgeCachedCredentials(); private: EventLoop* eventLoop_; NetworkFactories* networkFactories_; UIFactory* uiFactory_; - PlatformIdleQuerier idleQuerier_; - ActualIdleDetector idleDetector_; StoragesFactory* storagesFactory_; Storages* storages_; CertificateStorageFactory* certificateStorageFactory_; @@ -123,15 +131,19 @@ namespace Swift { SettingsProvider *settings_; ProfileSettingsProvider* profileSettings_; Dock* dock_; + URIHandler* uriHandler_; + IdleDetector* idleDetector_; TogglableNotifier* notifier_; PresenceNotifier* presenceNotifier_; EventNotifier* eventNotifier_; RosterController* rosterController_; EventController* eventController_; EventWindowController* eventWindowController_; + AdHocManager* adHocManager_; LoginWindow* loginWindow_; UIEventStream* uiEventStream_; XMLConsoleController* xmlConsoleController_; + FileTransferListController* fileTransferListController_; ChatsManager* chatsManager_; ProfileController* profileController_; ContactEditController* contactEditController_; @@ -139,6 +151,7 @@ namespace Swift { JID boundJID_; SystemTrayController* systemTrayController_; SoundEventController* soundEventController_; + XMPPURIController* xmppURIController_; std::string vCardPhotoHash_; std::string password_; std::string certificateFile_; @@ -152,5 +165,7 @@ namespace Swift { bool myStatusLooksOnline_; bool quitRequested_; static const int SecondsToWaitBeforeForceQuitting; + bool eagleMode_; + FileTransferOverview* ftOverview_; }; } diff --git a/Swift/Controllers/PreviousStatusStore.cpp b/Swift/Controllers/PreviousStatusStore.cpp index 947cdc7..ca0a12e 100644 --- a/Swift/Controllers/PreviousStatusStore.cpp +++ b/Swift/Controllers/PreviousStatusStore.cpp @@ -40,7 +40,7 @@ std::vector<TypeStringPair> PreviousStatusStore::getSuggestions(const std::strin suggestions.push_back(status); } } - if (suggestions.size() == 0) { + if (suggestions.empty()) { TypeStringPair suggestion(StatusShow::Online, message); suggestions.push_back(suggestion); } diff --git a/Swift/Controllers/ProfileSettingsProvider.h b/Swift/Controllers/ProfileSettingsProvider.h index 74bcd12..8ba250c 100644 --- a/Swift/Controllers/ProfileSettingsProvider.h +++ b/Swift/Controllers/ProfileSettingsProvider.h @@ -7,6 +7,7 @@ #pragma once #include "Swift/Controllers/Settings/SettingsProvider.h" +#include <Swiften/Base/foreach.h> namespace Swift { diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp index 0fe88aa..8c388bf 100644 --- a/Swift/Controllers/Roster/ContactRosterItem.cpp +++ b/Swift/Controllers/Roster/ContactRosterItem.cpp @@ -7,6 +7,8 @@ #include "Swift/Controllers/Roster/ContactRosterItem.h" #include "Swift/Controllers/Roster/GroupRosterItem.h" +#include <Swiften/Base/foreach.h> + namespace Swift { @@ -89,7 +91,7 @@ void ContactRosterItem::applyPresence(const std::string& resource, boost::shared presences_.erase(resource); } } - if (presences_.size() == 0) { + if (presences_.empty()) { offlinePresence_ = presence; } } else { @@ -111,6 +113,14 @@ void ContactRosterItem::removeGroup(const std::string& group) { groups_.erase(std::remove(groups_.begin(), groups_.end(), group), groups_.end()); } +void ContactRosterItem::setSupportedFeatures(const std::set<Feature>& features) { + features_ = features; +} + +bool ContactRosterItem::supportsFeature(const Feature feature) const { + return features_.find(feature) != features_.end(); +} + } diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h index 7aa948c..9932dc4 100644 --- a/Swift/Controllers/Roster/ContactRosterItem.h +++ b/Swift/Controllers/Roster/ContactRosterItem.h @@ -13,6 +13,7 @@ #include "Swiften/Elements/Presence.h" #include <map> +#include <set> #include <boost/bind.hpp> #include "Swiften/Base/boost_bsignals.h" #include <boost/shared_ptr.hpp> @@ -22,6 +23,11 @@ namespace Swift { class GroupRosterItem; class ContactRosterItem : public RosterItem { public: + enum Feature { + FileTransferFeature, + }; + + public: ContactRosterItem(const JID& jid, const JID& displayJID, const std::string& name, GroupRosterItem* parent); virtual ~ContactRosterItem(); @@ -40,6 +46,9 @@ class ContactRosterItem : public RosterItem { /** Only used so a contact can know about the groups it's in*/ void addGroup(const std::string& group); void removeGroup(const std::string& group); + + void setSupportedFeatures(const std::set<Feature>& features); + bool supportsFeature(Feature feature) const; private: JID jid_; JID displayJID_; @@ -48,6 +57,7 @@ class ContactRosterItem : public RosterItem { boost::shared_ptr<Presence> offlinePresence_; boost::shared_ptr<Presence> shownPresence_; std::vector<std::string> groups_; + std::set<Feature> features_; }; } diff --git a/Swift/Controllers/Roster/GroupRosterItem.cpp b/Swift/Controllers/Roster/GroupRosterItem.cpp index f0a377a..2a7bfa5 100644 --- a/Swift/Controllers/Roster/GroupRosterItem.cpp +++ b/Swift/Controllers/Roster/GroupRosterItem.cpp @@ -12,7 +12,7 @@ namespace Swift { -GroupRosterItem::GroupRosterItem(const std::string& name, GroupRosterItem* parent, bool sortByStatus) : RosterItem(name, parent), sortByStatus_(sortByStatus) { +GroupRosterItem::GroupRosterItem(const std::string& name, GroupRosterItem* parent, bool sortByStatus) : RosterItem(name, parent), sortByStatus_(sortByStatus), manualSort_(false) { expanded_ = true; } @@ -20,6 +20,20 @@ GroupRosterItem::~GroupRosterItem() { } +void GroupRosterItem::setManualSort(const std::string& manualSortValue) { + manualSort_ = true; + bool changed = manualSortValue_ != manualSortValue; + manualSortValue_ = manualSortValue; + if (changed) { + onChildrenChanged(); + onDataChanged(); + } +} + +const std::string& GroupRosterItem::getSortableDisplayName() const { + return manualSort_ ? manualSortValue_ : RosterItem::getSortableDisplayName(); +} + bool GroupRosterItem::isExpanded() const { return expanded_; } @@ -75,7 +89,7 @@ void GroupRosterItem::removeAll() { delete group; } } - it++; + ++it; } children_.clear(); } @@ -103,7 +117,7 @@ ContactRosterItem* GroupRosterItem::removeChild(const JID& jid) { removed = groupRemoved; } } - it++; + ++it; } onChildrenChanged(); onDataChanged(); @@ -122,7 +136,7 @@ GroupRosterItem* GroupRosterItem::removeGroupChild(const std::string& groupName) it = children_.erase(it); continue; } - it++; + ++it; } onChildrenChanged(); onDataChanged(); @@ -210,7 +224,8 @@ void GroupRosterItem::handleChildrenChanged(GroupRosterItem* group) { } else { displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end()); } - if (oldSize != getDisplayedChildren().size()) { + + if (oldSize != getDisplayedChildren().size() || sortDisplayed()) { onChildrenChanged(); onDataChanged(); } diff --git a/Swift/Controllers/Roster/GroupRosterItem.h b/Swift/Controllers/Roster/GroupRosterItem.h index 57fa9fa..beb7705 100644 --- a/Swift/Controllers/Roster/GroupRosterItem.h +++ b/Swift/Controllers/Roster/GroupRosterItem.h @@ -31,6 +31,8 @@ class GroupRosterItem : public RosterItem { void setExpanded(bool expanded); bool isExpanded() const; boost::signal<void (bool)> onExpandedChanged; + void setManualSort(const std::string& manualSortValue); + virtual const std::string& getSortableDisplayName() const; private: void handleChildrenChanged(GroupRosterItem* group); void handleDataChanged(RosterItem* item); @@ -40,6 +42,8 @@ class GroupRosterItem : public RosterItem { std::vector<RosterItem*> children_; std::vector<RosterItem*> displayedChildren_; bool sortByStatus_; + bool manualSort_; + std::string manualSortValue_; }; } diff --git a/Swift/Controllers/Roster/LeastCommonSubsequence.h b/Swift/Controllers/Roster/LeastCommonSubsequence.h new file mode 100644 index 0000000..dd3c95a --- /dev/null +++ b/Swift/Controllers/Roster/LeastCommonSubsequence.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +namespace Swift { + using std::equal_to; + + namespace Detail { + template<typename XIt, typename YIt, typename Length, typename Predicate> + void computeLeastCommonSubsequenceMatrix(XIt xBegin, XIt xEnd, YIt yBegin, YIt yEnd, std::vector<Length>& result) { + size_t width = std::distance(xBegin, xEnd) + 1; + size_t height = std::distance(yBegin, yEnd) + 1; + result.resize(width * height); + + // Initialize first row & column + for (size_t i = 0; i < width; ++i) { + result[i] = 0; + } + for (size_t j = 0; j < height; ++j) { + result[j*width] = 0; + } + + // Compute the LCS lengths for subsets + Predicate predicate; + for (size_t i = 1; i < width; ++i) { + for (size_t j = 1; j < height; ++j) { + result[i + j*width] = (predicate(*(xBegin + i-1), *(yBegin + j-1)) ? result[(i-1) + (j-1)*width] + 1 : std::max(result[i + (j-1)*width], result[i-1 + (j*width)])); + } + } + } + } + + template<typename X, typename InsertRemovePredicate, typename UpdatePredicate> + void computeIndexDiff(const std::vector<X>& x, const std::vector<X>& y, std::vector<size_t>& updates, std::vector<size_t>& postUpdates, std::vector<size_t>& removes, std::vector<size_t>& inserts) { + InsertRemovePredicate insertRemovePredicate; + UpdatePredicate updatePredicate; + + // Find & handle common prefix (Optimization to reduce LCS matrix size) + typename std::vector<X>::const_iterator xBegin = x.begin(); + typename std::vector<X>::const_iterator yBegin = y.begin(); + while (xBegin < x.end() && yBegin < y.end() && insertRemovePredicate(*xBegin, *yBegin)) { + if (updatePredicate(*xBegin, *yBegin)) { + updates.push_back(std::distance(x.begin(), xBegin)); + postUpdates.push_back(std::distance(y.begin(), yBegin)); + } + ++xBegin; + ++yBegin; + } + size_t prefixLength = std::distance(x.begin(), xBegin); + + // Find & handle common suffix (Optimization to reduce LCS matrix size) + typename std::vector<X>::const_reverse_iterator xEnd = x.rbegin(); + typename std::vector<X>::const_reverse_iterator yEnd = y.rbegin(); + while (xEnd.base() > xBegin && yEnd.base() > yBegin && insertRemovePredicate(*xEnd, *yEnd)) { + if (updatePredicate(*xEnd, *yEnd)) { + updates.push_back(std::distance(x.begin(), xEnd.base()) - 1); + postUpdates.push_back(std::distance(y.begin(), yEnd.base()) - 1); + } + ++xEnd; + ++yEnd; + } + + // Compute lengths + size_t xLength = std::distance(xBegin, xEnd.base()); + size_t yLength = std::distance(yBegin, yEnd.base()); + + // Compute LCS matrix + std::vector<unsigned int> lcs; + Detail::computeLeastCommonSubsequenceMatrix<typename std::vector<X>::const_iterator, typename std::vector<X>::const_iterator, unsigned int, InsertRemovePredicate>(xBegin, xEnd.base(), yBegin, yEnd.base(), lcs); + + // Process LCS matrix + size_t i = xLength; + size_t j = yLength; + const size_t width = xLength + 1; + while (true) { + if (i > 0 && j > 0 && insertRemovePredicate(x[prefixLength + i-1], y[prefixLength + j-1])) { + // x[i-1] same + if (updatePredicate(x[prefixLength + i - 1], y[prefixLength + j - 1])) { + updates.push_back(prefixLength + i-1); + postUpdates.push_back(prefixLength + j-1); + } + i -= 1; + j -= 1; + } + else if (j > 0 && (i == 0 || lcs[i + (j-1)*width] >= lcs[i-1 + j*width])) { + // y[j-1] added + inserts.push_back(prefixLength + j-1); + j -= 1; + } + else if (i > 0 && (j == 0 || lcs[i + (j-1)*width] < lcs[i-1 + j*width])) { + // x[i-1] removed + removes.push_back(prefixLength + i-1); + i -= 1; + } + else { + break; + } + } + } +} diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp index 4e34105..83837b1 100644 --- a/Swift/Controllers/Roster/Roster.cpp +++ b/Swift/Controllers/Roster/Roster.cpp @@ -17,6 +17,7 @@ #include <boost/bind.hpp> #include <iostream> +#include <set> #include <deque> namespace Swift { @@ -60,6 +61,16 @@ GroupRosterItem* Roster::getGroup(const std::string& groupName) { return group; } +void Roster::setAvailableFeatures(const JID& jid, const std::set<ContactRosterItem::Feature>& features) { + JID actualJID = fullJIDMapping_ ? jid : jid.toBare(); + if (itemMap_[actualJID].empty()) { + return; + } + foreach(ContactRosterItem* item, itemMap_[actualJID]) { + item->setSupportedFeatures(features); + } +} + void Roster::removeGroup(const std::string& group) { root_->removeGroupChild(group); } @@ -74,7 +85,7 @@ void Roster::handleChildrenChanged(GroupRosterItem* item) { void Roster::addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& groupName, const std::string& avatarPath) { GroupRosterItem* group(getGroup(groupName)); - ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group); + ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group); item->setAvatarPath(avatarPath); group->addChild(item); if (itemMap_[fullJIDMapping_ ? jid : jid.toBare()].size() > 0) { @@ -107,7 +118,7 @@ void Roster::removeAll() { void Roster::removeContact(const JID& jid) { std::vector<ContactRosterItem*>* items = &itemMap_[fullJIDMapping_ ? jid : jid.toBare()]; items->erase(std::remove_if(items->begin(), items->end(), JIDEqualsTo(jid)), items->end()); - if (items->size() == 0) { + if (items->empty()) { itemMap_.erase(fullJIDMapping_ ? jid : jid.toBare()); } //Causes the delete @@ -124,7 +135,7 @@ void Roster::removeContactFromGroup(const JID& jid, const std::string& groupName std::vector<ContactRosterItem*>* items = &itemMap_[fullJIDMapping_ ? jid : jid.toBare()]; items->erase(std::remove(items->begin(), items->end(), deleted), items->end()); } - it++; + ++it; } foreach (ContactRosterItem* item, itemMap_[fullJIDMapping_ ? jid : jid.toBare()]) { item->removeGroup(groupName); @@ -179,7 +190,7 @@ void Roster::filterContact(ContactRosterItem* contact, GroupRosterItem* group) { foreach (RosterFilter *filter, filters_) { hide &= (*filter)(contact); } - group->setDisplayed(contact, filters_.size() == 0 || !hide); + group->setDisplayed(contact, filters_.empty() || !hide); int newDisplayedSize = group->getDisplayedChildren().size(); if (oldDisplayedSize == 0 && newDisplayedSize > 0) { onGroupAdded(group); diff --git a/Swift/Controllers/Roster/Roster.h b/Swift/Controllers/Roster/Roster.h index 53161a8..2b4dd27 100644 --- a/Swift/Controllers/Roster/Roster.h +++ b/Swift/Controllers/Roster/Roster.h @@ -10,6 +10,7 @@ #include "Swiften/JID/JID.h" #include "Swift/Controllers/Roster/RosterItemOperation.h" #include "Swift/Controllers/Roster/RosterFilter.h" +#include <Swift/Controllers/Roster/ContactRosterItem.h> #include <vector> #include <map> @@ -43,6 +44,8 @@ class Roster { boost::signal<void (GroupRosterItem*)> onGroupAdded; boost::signal<void (RosterItem*)> onDataChanged; GroupRosterItem* getGroup(const std::string& groupName); + void setAvailableFeatures(const JID& jid, const std::set<ContactRosterItem::Feature>& features); + private: void handleDataChanged(RosterItem* item); void handleChildrenChanged(GroupRosterItem* item); diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp index 5b61abf..66948c1 100644 --- a/Swift/Controllers/Roster/RosterController.cpp +++ b/Swift/Controllers/Roster/RosterController.cpp @@ -36,9 +36,14 @@ #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h" #include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h" #include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h" +#include "Swift/Controllers/UIEvents/SendFileUIEvent.h" +#include <Swiften/FileTransfer/FileTransferManager.h> #include <Swiften/Client/NickManager.h> #include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Jingle/JingleSessionManager.h> namespace Swift { @@ -47,8 +52,9 @@ static const std::string SHOW_OFFLINE = "showOffline"; /** * The controller does not gain ownership of these parameters. */ -RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings) - : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream) { +RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview) + : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview) { + assert(fileTransferOverview); iqRouter_ = iqRouter; presenceOracle_ = presenceOracle; subscriptionManager_ = subscriptionManager; @@ -74,15 +80,17 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata nickManager_->onOwnNickChanged.connect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1)); mainWindow_->setMyJID(jid); mainWindow_->setMyNick(nickManager_->getOwnNick()); + + entityCapsManager_->onCapsChanged.connect(boost::bind(&RosterController::handleOnCapsChanged, this, _1)); if (settings->getBoolSetting(SHOW_OFFLINE, false)) { uiEventStream->onUIEvent(boost::shared_ptr<UIEvent>(new ToggleShowOfflineUIEvent(true))); } } -RosterController::~RosterController() { +RosterController::~RosterController() { nickManager_->onOwnNickChanged.disconnect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1)); - + delete offlineFilter_; delete expandiness_; @@ -91,6 +99,7 @@ RosterController::~RosterController() { delete mainWindow_; } delete roster_; + } void RosterController::setEnabled(bool enabled) { @@ -226,6 +235,10 @@ void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) { } } } + else if (boost::shared_ptr<SendFileUIEvent> sendFileEvent = boost::dynamic_pointer_cast<SendFileUIEvent>(event)) { + //TODO add send file dialog to ChatView of receipient jid + ftOverview_->sendFile(sendFileEvent->getJID(), sendFileEvent->getFilename()); + } } void RosterController::setContactGroups(const JID& jid, const std::vector<std::string>& groups) { @@ -302,4 +315,15 @@ std::set<std::string> RosterController::getGroups() const { return xmppRoster_->getGroups(); } +void RosterController::handleOnCapsChanged(const JID& jid) { + DiscoInfo::ref info = entityCapsManager_->getCaps(jid); + if (info) { + std::set<ContactRosterItem::Feature> features; + if (info->hasFeature(DiscoInfo::JingleFeature) && info->hasFeature(DiscoInfo::JingleFTFeature) && info->hasFeature(DiscoInfo::JingleTransportsIBBFeature)) { + features.insert(ContactRosterItem::FileTransferFeature); + } + roster_->setAvailableFeatures(jid, features); + } +} + } diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h index 0a2b818..66748ca 100644 --- a/Swift/Controllers/Roster/RosterController.h +++ b/Swift/Controllers/Roster/RosterController.h @@ -8,12 +8,14 @@ #include "Swiften/JID/JID.h" #include <string> +#include <set> #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/ErrorPayload.h" #include "Swiften/Elements/RosterPayload.h" #include "Swiften/Avatars/AvatarManager.h" #include "Swift/Controllers/UIEvents/UIEvent.h" #include "RosterGroupExpandinessPersister.h" +#include "Swift/Controllers/FileTransfer/FileTransferOverview.h" #include "Swiften/Base/boost_bsignals.h" #include <boost/shared_ptr.hpp> @@ -35,10 +37,12 @@ namespace Swift { class IQRouter; class SettingsProvider; class NickManager; - + class EntityCapsProvider; + class FileTransferManager; + class RosterController { public: - RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings); + RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview); ~RosterController(); void showRosterWindow(); MainWindow* getWindow() {return mainWindow_;}; @@ -69,6 +73,7 @@ namespace Swift { void handleRosterSetError(ErrorPayload::ref error, boost::shared_ptr<RosterPayload> rosterPayload); void applyAllPresenceTo(const JID& jid); void handleEditProfileRequest(); + void handleOnCapsChanged(const JID& jid); JID myJID_; XMPPRoster* xmppRoster_; @@ -86,6 +91,9 @@ namespace Swift { IQRouter* iqRouter_; SettingsProvider* settings_; UIEventStream* uiEventStream_; + EntityCapsProvider* entityCapsManager_; + FileTransferOverview* ftOverview_; + boost::bsignals::scoped_connection changeStatusConnection_; boost::bsignals::scoped_connection signOutConnection_; boost::bsignals::scoped_connection uiEventConnection_; diff --git a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp index c1045ee..0a242ae 100644 --- a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp +++ b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp @@ -9,6 +9,7 @@ #include <boost/bind.hpp> #include <vector> +#include <Swiften/Base/foreach.h> #include "Swiften/Base/String.h" #include "Swift/Controllers/Roster/GroupRosterItem.h" diff --git a/Swift/Controllers/Roster/RosterItem.cpp b/Swift/Controllers/Roster/RosterItem.cpp index 3f130bb..77db8a3 100644 --- a/Swift/Controllers/Roster/RosterItem.cpp +++ b/Swift/Controllers/Roster/RosterItem.cpp @@ -33,11 +33,11 @@ void RosterItem::setDisplayName(const std::string& name) { onDataChanged(); } -std::string RosterItem::getDisplayName() const { +const std::string& RosterItem::getDisplayName() const { return name_; } -std::string RosterItem::getSortableDisplayName() const { +const std::string& RosterItem::getSortableDisplayName() const { return sortableDisplayName_; } diff --git a/Swift/Controllers/Roster/RosterItem.h b/Swift/Controllers/Roster/RosterItem.h index ed8cb16..769f72d 100644 --- a/Swift/Controllers/Roster/RosterItem.h +++ b/Swift/Controllers/Roster/RosterItem.h @@ -20,8 +20,8 @@ class RosterItem { boost::signal<void ()> onDataChanged; GroupRosterItem* getParent() const; void setDisplayName(const std::string& name); - std::string getDisplayName() const; - std::string getSortableDisplayName() const; + const std::string& getDisplayName() const; + virtual const std::string& getSortableDisplayName() const; private: std::string name_; std::string sortableDisplayName_; diff --git a/Swift/Controllers/Roster/TableRoster.cpp b/Swift/Controllers/Roster/TableRoster.cpp new file mode 100644 index 0000000..c00bf4f --- /dev/null +++ b/Swift/Controllers/Roster/TableRoster.cpp @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/Roster/TableRoster.h> + +#include <boost/cast.hpp> +#include <cassert> +#include <algorithm> +#include <Swiften/Base/foreach.h> + +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/Timer.h> +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/Roster/LeastCommonSubsequence.h> + +namespace Swift { + struct SectionNameEquals { + bool operator()(const TableRoster::Section& s1, const TableRoster::Section& s2) const { + return s1.name == s2.name; + } + }; + + template<typename T> + struct True { + bool operator()(const T&, const T&) const { + return true; + } + }; + + struct ItemEquals { + bool operator()(const TableRoster::Item& i1, const TableRoster::Item& i2) const { + return i1.jid == i2.jid; + } + }; + + + struct ItemNeedsUpdate { + bool operator()(const TableRoster::Item& i1, const TableRoster::Item& i2) const { + return i1.status != i2.status || i1.description != i2.description || i1.name != i2.name || i1.avatarPath.empty() != i2.avatarPath.empty(); + } + }; + + struct CreateIndexForSection { + CreateIndexForSection(size_t section) : section(section) { + } + + TableRoster::Index operator()(size_t row) const { + return TableRoster::Index(section, row); + } + + size_t section; + }; +} + +using namespace Swift; + +TableRoster::TableRoster(Roster* model, TimerFactory* timerFactory, int updateDelay) : model(model), updatePending(false) { + updateTimer = timerFactory->createTimer(updateDelay); + updateTimer->onTick.connect(boost::bind(&TableRoster::handleUpdateTimerTick, this)); + if (model) { + model->onChildrenChanged.connect(boost::bind(&TableRoster::scheduleUpdate, this)); + model->onGroupAdded.connect(boost::bind(&TableRoster::scheduleUpdate, this)); + model->onDataChanged.connect(boost::bind(&TableRoster::scheduleUpdate, this)); + } +} + +TableRoster::~TableRoster() { + updateTimer->stop(); + updateTimer->onTick.disconnect(boost::bind(&TableRoster::handleUpdateTimerTick, this)); + if (model) { + model->onDataChanged.disconnect(boost::bind(&TableRoster::scheduleUpdate, this)); + model->onGroupAdded.disconnect(boost::bind(&TableRoster::scheduleUpdate, this)); + model->onChildrenChanged.disconnect(boost::bind(&TableRoster::scheduleUpdate, this)); + } +} + +size_t TableRoster::getNumberOfSections() const { + return sections.size(); +} + +const std::string& TableRoster::getSectionTitle(size_t section) { + return sections[section].name; +} + +size_t TableRoster::getNumberOfRowsInSection(size_t section) const { + return sections[section].items.size(); +} + +const TableRoster::Item& TableRoster::getItem(const Index& index) const { + return sections[index.section].items[index.row]; +} + +void TableRoster::handleUpdateTimerTick() { + updateTimer->stop(); + updatePending = false; + + // Get a model for the new roster + std::vector<Section> newSections; + if (model) { + foreach(RosterItem* item, model->getRoot()->getDisplayedChildren()) { + if (GroupRosterItem* groupItem = boost::polymorphic_downcast<GroupRosterItem*>(item)) { + //std::cerr << "* " << groupItem->getDisplayName() << std::endl; + Section section(groupItem->getDisplayName()); + foreach(RosterItem* groupChildItem, groupItem->getDisplayedChildren()) { + if (ContactRosterItem* contact = boost::polymorphic_downcast<ContactRosterItem*>(groupChildItem)) { + //std::cerr << " - " << contact->getDisplayJID() << std::endl; + section.items.push_back(Item(contact->getDisplayName(), contact->getStatusText(), contact->getDisplayJID(), contact->getStatusShow(), contact->getAvatarPath())); + } + } + newSections.push_back(section); + } + } + } + + // Do a diff with the previous roster + Update update; + std::vector<size_t> sectionUpdates; + std::vector<size_t> sectionPostUpdates; + computeIndexDiff<Section,SectionNameEquals,True<Section> >(sections, newSections, sectionUpdates, sectionPostUpdates, update.deletedSections, update.insertedSections); + assert(sectionUpdates.size() == sectionPostUpdates.size()); + for (size_t i = 0; i < sectionUpdates.size(); ++i) { + assert(sectionUpdates[i] < sections.size()); + assert(sectionPostUpdates[i] < newSections.size()); + std::vector<size_t> itemUpdates; + std::vector<size_t> itemPostUpdates; + std::vector<size_t> itemRemoves; + std::vector<size_t> itemInserts; + computeIndexDiff<Item, ItemEquals, ItemNeedsUpdate >(sections[sectionUpdates[i]].items, newSections[sectionPostUpdates[i]].items, itemUpdates, itemPostUpdates, itemRemoves, itemInserts); + size_t end = update.insertedRows.size(); + update.insertedRows.resize(update.insertedRows.size() + itemInserts.size()); + std::transform(itemInserts.begin(), itemInserts.end(), update.insertedRows.begin() + end, CreateIndexForSection(sectionPostUpdates[i])); + end = update.deletedRows.size(); + update.deletedRows.resize(update.deletedRows.size() + itemRemoves.size()); + std::transform(itemRemoves.begin(), itemRemoves.end(), update.deletedRows.begin() + end, CreateIndexForSection(sectionUpdates[i])); + end = update.updatedRows.size(); + update.updatedRows.resize(update.updatedRows.size() + itemUpdates.size()); + std::transform(itemUpdates.begin(), itemUpdates.end(), update.updatedRows.begin() + end, CreateIndexForSection(sectionPostUpdates[i])); + } + + // Switch the old model with the new + sections.swap(newSections); + + /* + std::cerr << "-S: "; + for (size_t i = 0; i < update.deletedSections.size(); ++i) { + std::cerr << update.deletedSections[i] << " "; + } + std::cerr << std::endl; + std::cerr << "+S: "; + for (size_t i = 0; i < update.insertedSections.size(); ++i) { + std::cerr << update.insertedSections[i] << " "; + } + std::cerr << std::endl; + std::cerr << "-R: "; + for (size_t i = 0; i < update.deletedRows.size(); ++i) { + std::cerr << update.deletedRows[i].section << "," << update.deletedRows[i].row << " "; + } + std::cerr << std::endl; + std::cerr << "*R: "; + for (size_t i = 0; i < update.updatedRows.size(); ++i) { + std::cerr << update.updatedRows[i].section << "," << update.updatedRows[i].row << " "; + } + std::cerr << std::endl; + std::cerr << "+R: "; + for (size_t i = 0; i < update.insertedRows.size(); ++i) { + std::cerr << update.insertedRows[i].section << "," << update.insertedRows[i].row << " "; + } + std::cerr << std::endl; + */ + + // Emit the update + onUpdate(update); +} + +void TableRoster::scheduleUpdate() { + if (!updatePending) { + updatePending = true; + updateTimer->start(); + } +} diff --git a/Swift/Controllers/Roster/TableRoster.h b/Swift/Controllers/Roster/TableRoster.h new file mode 100644 index 0000000..8ff16d0 --- /dev/null +++ b/Swift/Controllers/Roster/TableRoster.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <vector> +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/StatusShow.h> + +namespace Swift { + class Roster; + class TimerFactory; + class Timer; + + class TableRoster { + public: + struct Item { + Item(const std::string& name, const std::string& description, const JID& jid, StatusShow::Type status, const std::string& avatarPath) : name(name), description(description), jid(jid), status(status), avatarPath(avatarPath) { + } + std::string name; + std::string description; + JID jid; + StatusShow::Type status; + std::string avatarPath; + }; + + struct Index { + Index(size_t section = 0, size_t row = 0) : section(section), row(row) { + } + size_t section; + size_t row; + + bool operator==(const Index& o) const { + return o.section == section && o.row == row; + } + }; + + struct Update { + std::vector<Index> updatedRows; + std::vector<Index> insertedRows; + std::vector<Index> deletedRows; + std::vector<size_t> insertedSections; + std::vector<size_t> deletedSections; + }; + + TableRoster(Roster* model, TimerFactory* timerFactory, int updateDelay); + ~TableRoster(); + + size_t getNumberOfSections() const; + size_t getNumberOfRowsInSection(size_t section) const; + + const std::string& getSectionTitle(size_t); + + const Item& getItem(const Index&) const; + + boost::signal<void (const Update&)> onUpdate; + + private: + void handleUpdateTimerTick(); + void scheduleUpdate(); + + private: + friend class SectionNameEquals; + struct Section { + Section(const std::string& name) : name(name) { + } + + std::string name; + std::vector<Item> items; + }; + + Roster* model; + std::vector<Section> sections; + bool updatePending; + boost::shared_ptr<Timer> updateTimer; + }; +} diff --git a/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp b/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp new file mode 100644 index 0000000..963c5cd --- /dev/null +++ b/Swift/Controllers/Roster/UnitTest/LeastCommonSubsequenceTest.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <boost/assign/list_of.hpp> +#include <functional> + +#include <QA/Checker/IO.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <Swift/Controllers/Roster/LeastCommonSubsequence.h> + +using namespace Swift; + +struct IsBOrC { + bool operator()(char c, char c2) const { + CPPUNIT_ASSERT_EQUAL(c, c2); + return c == 'b' || c == 'c'; + } +}; + +struct IsXOrY { + bool operator()(char c, char c2) const { + CPPUNIT_ASSERT_EQUAL(c, c2); + return c == 'x' || c == 'y'; + } +}; + +struct IsArizonaOrNewJersey { + bool operator()(const std::string& s, const std::string& s2) const { + CPPUNIT_ASSERT_EQUAL(s, s2); + return s == "Arizona" || s == "New Jersey"; + } +}; + +class LeastCommonSubsequenceTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(LeastCommonSubsequenceTest); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_1); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_2); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_Sequence1Empty); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_Sequence2Empty); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_BothSequencesEmpty); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_NoCommonSequence); + CPPUNIT_TEST(testComputeLeastCommonSubsequenceMatrix_SameSequences); + CPPUNIT_TEST(testComputeIndexDiff_1); + CPPUNIT_TEST(testComputeIndexDiff_2); + CPPUNIT_TEST(testComputeIndexDiff_Sequence1Empty); + CPPUNIT_TEST(testComputeIndexDiff_Sequence2Empty); + CPPUNIT_TEST(testComputeIndexDiff_BothSequencesEmpty); + CPPUNIT_TEST(testComputeIndexDiff_NoCommonSequence); + CPPUNIT_TEST(testComputeIndexDiff_SameSequences); + CPPUNIT_TEST(testComputeIndexDiff_CommonPrefixAndSuffix); + CPPUNIT_TEST_SUITE_END(); + + public: + void testComputeLeastCommonSubsequenceMatrix_1() { + std::vector<char> x = boost::assign::list_of('x')('m')('j')('y')('a')('u')('z'); + std::vector<char> y = boost::assign::list_of('m')('z')('j')('a')('w')('x')('u'); + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of + (0)(0)(0)(0)(0)(0)(0)(0) + (0)(0)(1)(1)(1)(1)(1)(1) + (0)(0)(1)(1)(1)(1)(1)(2) + (0)(0)(1)(2)(2)(2)(2)(2) + (0)(0)(1)(2)(2)(3)(3)(3) + (0)(0)(1)(2)(2)(3)(3)(3) + (0)(1)(1)(2)(2)(3)(3)(3) + (0)(1)(1)(2)(2)(3)(4)(4); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeLeastCommonSubsequenceMatrix_2() { + std::vector<char> x = boost::assign::list_of('x')('x')('x')('m')('j')('y')('a')('u')('z'); + std::vector<char> y = boost::assign::list_of('m')('z')('j')('a')('w')('x')('u'); + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of + (0)(0)(0)(0)(0)(0)(0)(0)(0)(0) + (0)(0)(0)(0)(1)(1)(1)(1)(1)(1) + (0)(0)(0)(0)(1)(1)(1)(1)(1)(2) + (0)(0)(0)(0)(1)(2)(2)(2)(2)(2) + (0)(0)(0)(0)(1)(2)(2)(3)(3)(3) + (0)(0)(0)(0)(1)(2)(2)(3)(3)(3) + (0)(1)(1)(1)(1)(2)(2)(3)(3)(3) + (0)(1)(1)(1)(1)(2)(2)(3)(4)(4); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeLeastCommonSubsequenceMatrix_Sequence1Empty() { + std::vector<char> x; + std::vector<char> y = boost::assign::list_of('a')('b')('c'); + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of + (0) + (0) + (0) + (0); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeLeastCommonSubsequenceMatrix_Sequence2Empty() { + std::vector<char> x = boost::assign::list_of('a')('b')('c'); + std::vector<char> y; + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of + (0)(0)(0)(0); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeLeastCommonSubsequenceMatrix_BothSequencesEmpty() { + std::vector<char> x; + std::vector<char> y; + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of(0); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeLeastCommonSubsequenceMatrix_NoCommonSequence() { + std::vector<char> x = boost::assign::list_of('a')('b')('c'); + std::vector<char> y = boost::assign::list_of('d')('e')('f')('g'); + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of + (0)(0)(0)(0) + (0)(0)(0)(0) + (0)(0)(0)(0) + (0)(0)(0)(0) + (0)(0)(0)(0); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeLeastCommonSubsequenceMatrix_SameSequences() { + std::vector<char> x = boost::assign::list_of('a')('b')('c'); + std::vector<char> y = boost::assign::list_of('a')('b')('c'); + + std::vector<int> result; + Detail::computeLeastCommonSubsequenceMatrix<std::vector<char>::const_iterator, std::vector<char>::const_iterator, int, std::equal_to<char> >(x.begin(), x.end(), y.begin(), y.end(), result); + + std::vector<int> expected = boost::assign::list_of + (0)(0)(0)(0) + (0)(1)(1)(1) + (0)(1)(2)(2) + (0)(1)(2)(3); + CPPUNIT_ASSERT_EQUAL(expected, result); + } + + void testComputeIndexDiff_1() { + std::vector<std::string> x = boost::assign::list_of("Arizona")("California")("Delaware")("New Jersey")("Washington"); + std::vector<std::string> y = boost::assign::list_of("Alaska")("Arizona")("California")("Georgia")("New Jersey")("Virginia"); + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<std::string, std::equal_to<std::string>, IsArizonaOrNewJersey >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedUpdates = boost::assign::list_of(3)(0); + std::vector<size_t> expectedPostUpdates = boost::assign::list_of(4)(1); + std::vector<size_t> expectedRemoves = boost::assign::list_of(4)(2); + std::vector<size_t> expectedInserts = boost::assign::list_of(5)(3)(0); + CPPUNIT_ASSERT_EQUAL(expectedUpdates, updates); + CPPUNIT_ASSERT_EQUAL(expectedPostUpdates, postUpdates); + CPPUNIT_ASSERT_EQUAL(expectedRemoves, removes); + CPPUNIT_ASSERT_EQUAL(expectedInserts, inserts); + } + + void testComputeIndexDiff_2() { + std::vector<char> x = boost::assign::list_of('x')('y'); + std::vector<char> y = boost::assign::list_of('x'); + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedRemoves = boost::assign::list_of(1); + CPPUNIT_ASSERT(updates.empty()); + CPPUNIT_ASSERT(postUpdates.empty()); + CPPUNIT_ASSERT(inserts.empty()); + CPPUNIT_ASSERT_EQUAL(expectedRemoves, removes); + } + + void testComputeIndexDiff_Sequence1Empty() { + std::vector<char> x; + std::vector<char> y = boost::assign::list_of('a')('b')('c'); + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedInserts = boost::assign::list_of(2)(1)(0); + CPPUNIT_ASSERT(updates.empty()); + CPPUNIT_ASSERT(postUpdates.empty()); + CPPUNIT_ASSERT(removes.empty()); + CPPUNIT_ASSERT_EQUAL(expectedInserts, inserts); + } + + void testComputeIndexDiff_Sequence2Empty() { + std::vector<char> x = boost::assign::list_of('a')('b')('c'); + std::vector<char> y; + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedRemoves = boost::assign::list_of(2)(1)(0); + CPPUNIT_ASSERT(updates.empty()); + CPPUNIT_ASSERT(postUpdates.empty()); + CPPUNIT_ASSERT_EQUAL(expectedRemoves, removes); + CPPUNIT_ASSERT(inserts.empty()); + } + + void testComputeIndexDiff_BothSequencesEmpty() { + std::vector<char> x; + std::vector<char> y; + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts); + + CPPUNIT_ASSERT(updates.empty()); + CPPUNIT_ASSERT(postUpdates.empty()); + CPPUNIT_ASSERT(removes.empty()); + CPPUNIT_ASSERT(inserts.empty()); + } + + void testComputeIndexDiff_NoCommonSequence() { + std::vector<char> x = boost::assign::list_of('a')('b')('c'); + std::vector<char> y = boost::assign::list_of('d')('e')('f')('g'); + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedRemoves = boost::assign::list_of(2)(1)(0); + std::vector<size_t> expectedInserts = boost::assign::list_of(3)(2)(1)(0); + CPPUNIT_ASSERT(updates.empty()); + CPPUNIT_ASSERT(postUpdates.empty()); + CPPUNIT_ASSERT_EQUAL(expectedRemoves, removes); + CPPUNIT_ASSERT_EQUAL(expectedInserts, inserts); + } + + void testComputeIndexDiff_SameSequences() { + std::vector<char> x = boost::assign::list_of('a')('b')('c'); + std::vector<char> y = boost::assign::list_of('a')('b')('c'); + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsBOrC >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedUpdates = boost::assign::list_of(1)(2); + CPPUNIT_ASSERT_EQUAL(expectedUpdates, updates); + CPPUNIT_ASSERT_EQUAL(expectedUpdates, postUpdates); + CPPUNIT_ASSERT(removes.empty()); + CPPUNIT_ASSERT(inserts.empty()); + } + + void testComputeIndexDiff_CommonPrefixAndSuffix() { + std::vector<char> x = boost::assign::list_of('x')('x')('x')('x')('a')('b')('c')('d')('e')('y')('y')('y'); + std::vector<char> y = boost::assign::list_of('x')('x')('x')('x')('e')('a')('b')('f')('d')('g')('y')('y')('y'); + + std::vector<size_t> updates; + std::vector<size_t> postUpdates; + std::vector<size_t> removes; + std::vector<size_t> inserts; + computeIndexDiff<char, std::equal_to<char>, IsXOrY >(x, y, updates, postUpdates, removes, inserts); + + std::vector<size_t> expectedUpdates = boost::assign::list_of(0)(1)(2)(3)(11)(10)(9); + std::vector<size_t> expectedPostUpdates = boost::assign::list_of(0)(1)(2)(3)(12)(11)(10); + std::vector<size_t> expectedRemoves = boost::assign::list_of(8)(6); + std::vector<size_t> expectedInserts = boost::assign::list_of(9)(7)(4); + CPPUNIT_ASSERT_EQUAL(expectedUpdates, updates); + CPPUNIT_ASSERT_EQUAL(expectedPostUpdates, postUpdates); + CPPUNIT_ASSERT_EQUAL(expectedRemoves, removes); + CPPUNIT_ASSERT_EQUAL(expectedInserts, inserts); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(LeastCommonSubsequenceTest); diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp index 16f2745..fbee894 100644 --- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp +++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp @@ -8,6 +8,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <Swiften/Base/foreach.h> #include "Swift/Controllers/Roster/RosterController.h" #include "Swift/Controllers/UnitTest/MockMainWindowFactory.h" // #include "Swiften/Elements/Payload.h" @@ -30,11 +31,21 @@ #include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h" #include "Swiften/MUC/MUCRegistry.h" #include <Swiften/Client/DummyNickManager.h> +#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Disco/CapsProvider.h> +#include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; #define CHILDREN mainWindow_->roster->getRoot()->getChildren() +class DummyCapsProvider : public CapsProvider { + DiscoInfo::ref getCaps(const std::string&) const {return DiscoInfo::ref(new DiscoInfo());} +}; + class RosterControllerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(RosterControllerTest); CPPUNIT_TEST(testAdd); @@ -65,12 +76,21 @@ class RosterControllerTest : public CppUnit::TestFixture { uiEventStream_ = new UIEventStream(); settings_ = new DummySettingsProvider(); nickManager_ = new DummyNickManager(); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_); + capsProvider_ = new DummyCapsProvider(); + entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_); + jingleSessionManager_ = new JingleSessionManager(router_); + + ftManager_ = new DummyFileTransferManager(); + ftOverview_ = new FileTransferOverview(ftManager_); + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_); mainWindow_ = mainWindowFactory_->last; }; void tearDown() { delete rosterController_; + delete ftManager_; + delete jingleSessionManager_; + delete nickManager_; delete nickResolver_; delete mucRegistry_; @@ -312,6 +332,11 @@ class RosterControllerTest : public CppUnit::TestFixture { UIEventStream* uiEventStream_; MockMainWindow* mainWindow_; DummySettingsProvider* settings_; + DummyCapsProvider* capsProvider_; + EntityCapsManager* entityCapsManager_; + JingleSessionManager* jingleSessionManager_; + FileTransferManager* ftManager_; + FileTransferOverview* ftOverview_; }; CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest); diff --git a/Swift/Controllers/Roster/UnitTest/RosterTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterTest.cpp index cbef787..4444e8a 100644 --- a/Swift/Controllers/Roster/UnitTest/RosterTest.cpp +++ b/Swift/Controllers/Roster/UnitTest/RosterTest.cpp @@ -21,6 +21,7 @@ class RosterTest : public CppUnit::TestFixture { CPPUNIT_TEST(testRemoveSecondContact); CPPUNIT_TEST(testRemoveSecondContactSameBare); CPPUNIT_TEST(testApplyPresenceLikeMUC); + CPPUNIT_TEST(testReSortLikeMUC); CPPUNIT_TEST_SUITE_END(); public: @@ -117,6 +118,22 @@ class RosterTest : public CppUnit::TestFixture { } + void testReSortLikeMUC() { + JID jid4a("a@b/c"); + JID jid4b("a@b/d"); + JID jid4c("a@b/e"); + roster_->addContact(jid4a, JID(), "Bird", "group1", ""); + roster_->addContact(jid4b, JID(), "Cookie", "group2", ""); + roster_->addContact(jid4b, JID(), "Ernie", "group1", ""); + roster_->getGroup("group1")->setManualSort("2"); + roster_->getGroup("group2")->setManualSort("1"); + GroupRosterItem* root = roster_->getRoot(); + const std::vector<RosterItem*> kids = root->getDisplayedChildren(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), kids.size()); + CPPUNIT_ASSERT_EQUAL(std::string("group2"), kids[0]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(std::string("group1"), kids[1]->getDisplayName()); + } + private: Roster *roster_; JID jid1_; diff --git a/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp b/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp new file mode 100644 index 0000000..e433b50 --- /dev/null +++ b/Swift/Controllers/Roster/UnitTest/TableRosterTest.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/Roster/TableRoster.h> + +std::ostream& operator<<(std::ostream& os, const Swift::TableRoster::Index& i) { + os << "(" << i.section << ", " << i.row << ")"; + return os; +} + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <boost/shared_ptr.hpp> +#include <boost/variant.hpp> + +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/Roster/SetPresence.h> + +using namespace Swift; + +class TableRosterTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TableRosterTest); + CPPUNIT_TEST(testAddContact_EmptyRoster); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + timerFactory = new DummyTimerFactory(); + roster = new Roster(); + jid1 = JID("jid1@example.com"); + jid2 = JID("jid2@example.com"); + } + + void tearDown() { + delete roster; + delete timerFactory; + } + + void testAddContact_EmptyRoster() { + /* + boost::shared_ptr<TableRoster> tableRoster(createTestling()); + + addContact(jid1, "1", "group1"); + + CPPUNIT_ASSERT_EQUAL(4, static_cast<int>(events.size())); + CPPUNIT_ASSERT(boost::get<BeginUpdatesEvent>(&events[0])); + CPPUNIT_ASSERT(boost::get<SectionsInsertedEvent>(&events[1])); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(boost::get<SectionsInsertedEvent>(events[1]).sections.size())); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(boost::get<SectionsInsertedEvent>(events[1]).sections[0])); + CPPUNIT_ASSERT(boost::get<RowsInsertedEvent>(&events[2])); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(boost::get<RowsInsertedEvent>(events[2]).rows.size())); + CPPUNIT_ASSERT_EQUAL(TableRoster::Index(0, 0), boost::get<RowsInsertedEvent>(events[2]).rows[0]); + CPPUNIT_ASSERT(boost::get<EndUpdatesEvent>(&events[3])); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(tableRoster->getNumberOfSections())); + CPPUNIT_ASSERT_EQUAL(std::string("group1"), tableRoster->getSectionTitle(0)); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(tableRoster->getNumberOfRowsInSection(0))); + CPPUNIT_ASSERT_EQUAL(jid1, tableRoster->getItem(TableRoster::Index(0, 0)).jid); + */ + } + + private: + void addContact(const JID& jid, const std::string& name, const std::string& group) { + roster->addContact(jid, JID(), name, group, ""); + } + + TableRoster* createTestling() { + TableRoster* result = new TableRoster(roster, timerFactory, 10); + result->onUpdate.connect(boost::bind(&TableRosterTest::handleUpdate, this, _1)); + return result; + } + + void handleUpdate(const TableRoster::Update& update) { + updates.push_back(update); + } + + private: + DummyTimerFactory* timerFactory; + Roster* roster; + JID jid1; + JID jid2; + std::vector<TableRoster::Update> updates; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TableRosterTest); + diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript index 61da9fb..e48f382 100644 --- a/Swift/Controllers/SConscript +++ b/Swift/Controllers/SConscript @@ -27,41 +27,57 @@ if env["SCONS_STAGE"] == "build" : "Chat/MUCController.cpp", "Chat/MUCSearchController.cpp", "Chat/UserSearchController.cpp", - "DiscoServiceWalker.cpp", "MainController.cpp", "ProfileController.cpp", "ContactEditController.cpp", + "FileTransfer/FileTransferController.cpp", + "FileTransfer/FileTransferOverview.cpp", + "FileTransfer/FileTransferProgressInfo.cpp", "Roster/RosterController.cpp", "Roster/RosterGroupExpandinessPersister.cpp", "Roster/ContactRosterItem.cpp", "Roster/GroupRosterItem.cpp", "Roster/RosterItem.cpp", "Roster/Roster.cpp", + "Roster/TableRoster.cpp", "EventWindowController.cpp", "SoundEventController.cpp", "SystemTrayController.cpp", "XMLConsoleController.cpp", + "FileTransferListController.cpp", "StatusTracker.cpp", "PresenceNotifier.cpp", "EventNotifier.cpp", + "AdHocManager.cpp", "XMPPEvents/EventController.cpp", "UIEvents/UIEvent.cpp", "UIInterfaces/XMLConsoleWidget.cpp", "UIInterfaces/ChatListWindow.cpp", "PreviousStatusStore.cpp", - "CertificateStorageFactory.cpp", - "CertificateStorage.cpp", - "CertificateFileStorage.cpp", + "Storages/CertificateStorageFactory.cpp", + "Storages/CertificateStorage.cpp", + "Storages/CertificateFileStorage.cpp", + "Storages/CertificateMemoryStorage.cpp", + "Storages/AvatarFileStorage.cpp", + "Storages/FileStorages.cpp", + "Storages/RosterFileStorage.cpp", + "Storages/CapsFileStorage.cpp", + "Storages/VCardFileStorage.cpp", "StatusUtil.cpp", "Translator.cpp", + "XMPPURIController.cpp", + "ChatMessageSummarizer.cpp", ]) env.Append(UNITTEST_SOURCES = [ File("Roster/UnitTest/RosterControllerTest.cpp"), File("Roster/UnitTest/RosterTest.cpp"), + File("Roster/UnitTest/LeastCommonSubsequenceTest.cpp"), + File("Roster/UnitTest/TableRosterTest.cpp"), File("UnitTest/PreviousStatusStoreTest.cpp"), File("UnitTest/PresenceNotifierTest.cpp"), File("Chat/UnitTest/ChatsManagerTest.cpp"), File("Chat/UnitTest/MUCControllerTest.cpp"), File("UnitTest/MockChatWindow.cpp"), + File("UnitTest/ChatMessageSummarizerTest.cpp"), ]) diff --git a/Swiften/Avatars/AvatarFileStorage.cpp b/Swift/Controllers/Storages/AvatarFileStorage.cpp index 4f76c80..b39e586 100644 --- a/Swiften/Avatars/AvatarFileStorage.cpp +++ b/Swift/Controllers/Storages/AvatarFileStorage.cpp @@ -4,10 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <Swiften/Avatars/AvatarFileStorage.h> +#include <Swift/Controllers/Storages/AvatarFileStorage.h> #include <iostream> #include <boost/filesystem/fstream.hpp> +#include <boost/filesystem.hpp> #include <Swiften/Base/foreach.h> #include <Swiften/Base/String.h> @@ -58,7 +59,7 @@ void AvatarFileStorage::addAvatar(const std::string& hash, const ByteArray& avat } } boost::filesystem::ofstream file(avatarPath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); - file.write(reinterpret_cast<const char*>(avatar.getData()), avatar.getSize()); + file.write(reinterpret_cast<const char*>(vecptr(avatar)), static_cast<std::streamsize>(avatar.size())); file.close(); } @@ -68,7 +69,7 @@ boost::filesystem::path AvatarFileStorage::getAvatarPath(const std::string& hash ByteArray AvatarFileStorage::getAvatar(const std::string& hash) const { ByteArray data; - data.readFromFile(getAvatarPath(hash).string()); + readByteArrayFromFile(data, getAvatarPath(hash).string()); return data; } diff --git a/Swiften/Avatars/AvatarFileStorage.h b/Swift/Controllers/Storages/AvatarFileStorage.h index e736230..b7e73f5 100644 --- a/Swiften/Avatars/AvatarFileStorage.h +++ b/Swift/Controllers/Storages/AvatarFileStorage.h @@ -8,7 +8,7 @@ #include <map> #include <string> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <Swiften/JID/JID.h> #include "Swiften/Base/ByteArray.h" diff --git a/Swift/Controllers/Storages/CapsFileStorage.cpp b/Swift/Controllers/Storages/CapsFileStorage.cpp new file mode 100644 index 0000000..b7593fd --- /dev/null +++ b/Swift/Controllers/Storages/CapsFileStorage.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swift/Controllers/Storages/CapsFileStorage.h" + +#include <Swiften/Entity/GenericPayloadPersister.h> +#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h" +#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h" +#include "Swiften/StringCodecs/Hexify.h" +#include "Swiften/StringCodecs/Base64.h" + +using namespace Swift; + +typedef GenericPayloadPersister<DiscoInfo, DiscoInfoParser, DiscoInfoSerializer> DiscoInfoPersister; + +CapsFileStorage::CapsFileStorage(const boost::filesystem::path& path) : path(path) { +} + +DiscoInfo::ref CapsFileStorage::getDiscoInfo(const std::string& hash) const { + return DiscoInfoPersister().loadPayloadGeneric(getCapsPath(hash)); +} + +void CapsFileStorage::setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) { + DiscoInfo::ref bareDiscoInfo(new DiscoInfo(*discoInfo.get())); + bareDiscoInfo->setNode(""); + DiscoInfoPersister().savePayload(bareDiscoInfo, getCapsPath(hash)); +} + +boost::filesystem::path CapsFileStorage::getCapsPath(const std::string& hash) const { + return path / (Hexify::hexify(Base64::decode(hash)) + ".xml"); +} diff --git a/Swiften/Disco/CapsFileStorage.h b/Swift/Controllers/Storages/CapsFileStorage.h index 5faf08b..b3757e0 100644 --- a/Swiften/Disco/CapsFileStorage.h +++ b/Swift/Controllers/Storages/CapsFileStorage.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include "Swiften/Disco/CapsStorage.h" #include <string> diff --git a/Swift/Controllers/CertificateFileStorage.cpp b/Swift/Controllers/Storages/CertificateFileStorage.cpp index cf924ee..a4a95c7 100644 --- a/Swift/Controllers/CertificateFileStorage.cpp +++ b/Swift/Controllers/Storages/CertificateFileStorage.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <Swift/Controllers/CertificateFileStorage.h> +#include <Swift/Controllers/Storages/CertificateFileStorage.h> #include <iostream> #include <boost/filesystem/fstream.hpp> @@ -23,7 +23,7 @@ bool CertificateFileStorage::hasCertificate(Certificate::ref certificate) const boost::filesystem::path certificatePath = getCertificatePath(certificate); if (boost::filesystem::exists(certificatePath)) { ByteArray data; - data.readFromFile(certificatePath.string()); + readByteArrayFromFile(data, certificatePath.string()); Certificate::ref storedCertificate = certificateFactory->createCertificateFromDER(data); if (storedCertificate && storedCertificate->toDER() == certificate->toDER()) { return true; @@ -50,7 +50,7 @@ void CertificateFileStorage::addCertificate(Certificate::ref certificate) { } boost::filesystem::ofstream file(certificatePath, boost::filesystem::ofstream::binary|boost::filesystem::ofstream::out); ByteArray data = certificate->toDER(); - file.write(reinterpret_cast<const char*>(data.getData()), data.getSize()); + file.write(reinterpret_cast<const char*>(vecptr(data)), data.size()); file.close(); } diff --git a/Swift/Controllers/CertificateFileStorage.h b/Swift/Controllers/Storages/CertificateFileStorage.h index 2b853ed..f7a60b9 100644 --- a/Swift/Controllers/CertificateFileStorage.h +++ b/Swift/Controllers/Storages/CertificateFileStorage.h @@ -8,7 +8,7 @@ #include <boost/filesystem.hpp> -#include "Swift/Controllers/CertificateStorage.h" +#include "Swift/Controllers/Storages/CertificateStorage.h" namespace Swift { class CertificateFactory; diff --git a/Swift/Controllers/CertificateFileStorageFactory.h b/Swift/Controllers/Storages/CertificateFileStorageFactory.h index 7ed8287..b215165 100644 --- a/Swift/Controllers/CertificateFileStorageFactory.h +++ b/Swift/Controllers/Storages/CertificateFileStorageFactory.h @@ -6,8 +6,8 @@ #pragma once -#include <Swift/Controllers/CertificateStorageFactory.h> -#include <Swift/Controllers/CertificateFileStorage.h> +#include <Swift/Controllers/Storages/CertificateStorageFactory.h> +#include <Swift/Controllers/Storages/CertificateFileStorage.h> namespace Swift { class CertificateFactory; diff --git a/Swift/Controllers/Storages/CertificateMemoryStorage.cpp b/Swift/Controllers/Storages/CertificateMemoryStorage.cpp new file mode 100644 index 0000000..71d7c4a --- /dev/null +++ b/Swift/Controllers/Storages/CertificateMemoryStorage.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/Storages/CertificateMemoryStorage.h> + +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +CertificateMemoryStorage::CertificateMemoryStorage() { +} + +bool CertificateMemoryStorage::hasCertificate(Certificate::ref certificate) const { + foreach(Certificate::ref storedCert, certificates) { + if (storedCert->toDER() == certificate->toDER()) { + return true; + } + } + return false; +} + +void CertificateMemoryStorage::addCertificate(Certificate::ref certificate) { + certificates.push_back(certificate); +} diff --git a/Swift/Controllers/Storages/CertificateMemoryStorage.h b/Swift/Controllers/Storages/CertificateMemoryStorage.h new file mode 100644 index 0000000..5c0333d --- /dev/null +++ b/Swift/Controllers/Storages/CertificateMemoryStorage.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swift/Controllers/Storages/CertificateStorage.h> + +namespace Swift { + class CertificateMemoryStorage : public CertificateStorage { + public: + CertificateMemoryStorage(); + + virtual bool hasCertificate(Certificate::ref certificate) const; + virtual void addCertificate(Certificate::ref certificate); + + private: + std::vector<Certificate::ref> certificates; + }; + +} diff --git a/Swift/Controllers/CertificateStorage.cpp b/Swift/Controllers/Storages/CertificateStorage.cpp index 343fccd..ee942c0 100644 --- a/Swift/Controllers/CertificateStorage.cpp +++ b/Swift/Controllers/Storages/CertificateStorage.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swift/Controllers/CertificateStorage.h" +#include "Swift/Controllers/Storages/CertificateStorage.h" namespace Swift { diff --git a/Swift/Controllers/CertificateStorage.h b/Swift/Controllers/Storages/CertificateStorage.h index f8c6fb5..f8c6fb5 100644 --- a/Swift/Controllers/CertificateStorage.h +++ b/Swift/Controllers/Storages/CertificateStorage.h diff --git a/Swift/Controllers/CertificateStorageFactory.cpp b/Swift/Controllers/Storages/CertificateStorageFactory.cpp index 613a8c3..ba0179a 100644 --- a/Swift/Controllers/CertificateStorageFactory.cpp +++ b/Swift/Controllers/Storages/CertificateStorageFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <Swift/Controllers/CertificateStorageFactory.h> +#include <Swift/Controllers/Storages/CertificateStorageFactory.h> namespace Swift { diff --git a/Swift/Controllers/CertificateStorageFactory.h b/Swift/Controllers/Storages/CertificateStorageFactory.h index 5b85757..5b85757 100644 --- a/Swift/Controllers/CertificateStorageFactory.h +++ b/Swift/Controllers/Storages/CertificateStorageFactory.h diff --git a/Swift/Controllers/CertificateStorageTrustChecker.h b/Swift/Controllers/Storages/CertificateStorageTrustChecker.h index f33287c..40838dd 100644 --- a/Swift/Controllers/CertificateStorageTrustChecker.h +++ b/Swift/Controllers/Storages/CertificateStorageTrustChecker.h @@ -7,7 +7,7 @@ #pragma once #include <Swiften/TLS/CertificateTrustChecker.h> -#include <Swift/Controllers/CertificateStorage.h> +#include <Swift/Controllers/Storages/CertificateStorage.h> namespace Swift { /** diff --git a/Swiften/Client/FileStorages.cpp b/Swift/Controllers/Storages/FileStorages.cpp index 3c76c46..6447099 100644 --- a/Swiften/Client/FileStorages.cpp +++ b/Swift/Controllers/Storages/FileStorages.cpp @@ -4,10 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/FileStorages.h" -#include "Swiften/VCards/VCardFileStorage.h" -#include "Swiften/Avatars/AvatarFileStorage.h" -#include "Swiften/Disco/CapsFileStorage.h" +#include "Swift/Controllers/Storages/FileStorages.h" +#include "Swift/Controllers/Storages/VCardFileStorage.h" +#include "Swift/Controllers/Storages/AvatarFileStorage.h" +#include "Swift/Controllers/Storages/CapsFileStorage.h" +#include "Swift/Controllers/Storages/RosterFileStorage.h" namespace Swift { @@ -16,9 +17,11 @@ FileStorages::FileStorages(const boost::filesystem::path& baseDir, const JID& ji vcardStorage = new VCardFileStorage(baseDir / profile / "vcards"); capsStorage = new CapsFileStorage(baseDir / "caps"); avatarStorage = new AvatarFileStorage(baseDir / "avatars", baseDir / profile / "avatars"); + rosterStorage = new RosterFileStorage(baseDir / profile / "roster.xml"); } FileStorages::~FileStorages() { + delete rosterStorage; delete avatarStorage; delete capsStorage; delete vcardStorage; @@ -36,4 +39,8 @@ AvatarStorage* FileStorages::getAvatarStorage() const { return avatarStorage; } +RosterStorage* FileStorages::getRosterStorage() const { + return rosterStorage; +} + } diff --git a/Swiften/Client/FileStorages.h b/Swift/Controllers/Storages/FileStorages.h index 451105f..28df314 100644 --- a/Swiften/Client/FileStorages.h +++ b/Swift/Controllers/Storages/FileStorages.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include "Swiften/Client/Storages.h" @@ -14,6 +14,7 @@ namespace Swift { class VCardFileStorage; class AvatarFileStorage; class CapsFileStorage; + class RosterFileStorage; class JID; /** @@ -41,10 +42,12 @@ namespace Swift { virtual VCardStorage* getVCardStorage() const; virtual AvatarStorage* getAvatarStorage() const; virtual CapsStorage* getCapsStorage() const; + virtual RosterStorage* getRosterStorage() const; private: VCardFileStorage* vcardStorage; AvatarFileStorage* avatarStorage; CapsFileStorage* capsStorage; + RosterFileStorage* rosterStorage; }; } diff --git a/Swift/Controllers/FileStoragesFactory.h b/Swift/Controllers/Storages/FileStoragesFactory.h index bd7cdfb..0676bc3 100644 --- a/Swift/Controllers/FileStoragesFactory.h +++ b/Swift/Controllers/Storages/FileStoragesFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swift/Controllers/StoragesFactory.h" -#include "Swiften/Client/FileStorages.h" +#include "Swift/Controllers/Storages/StoragesFactory.h" +#include "Swift/Controllers/Storages/FileStorages.h" namespace Swift { class FileStoragesFactory : public StoragesFactory { diff --git a/Swift/Controllers/MemoryStoragesFactory.h b/Swift/Controllers/Storages/MemoryStoragesFactory.h index 8408e10..0dea349 100644 --- a/Swift/Controllers/MemoryStoragesFactory.h +++ b/Swift/Controllers/Storages/MemoryStoragesFactory.h @@ -6,10 +6,12 @@ #pragma once -#include "Swift/Controllers/StoragesFactory.h" +#include "Swift/Controllers/Storages/StoragesFactory.h" #include "Swiften/Client/MemoryStorages.h" namespace Swift { + class JID; + class MemoryStoragesFactory : public StoragesFactory { public: MemoryStoragesFactory() {} diff --git a/Swift/Controllers/Storages/RosterFileStorage.cpp b/Swift/Controllers/Storages/RosterFileStorage.cpp new file mode 100644 index 0000000..73e582f --- /dev/null +++ b/Swift/Controllers/Storages/RosterFileStorage.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/Storages/RosterFileStorage.h> + +#include <Swiften/Entity/GenericPayloadPersister.h> +#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h> +#include <Swiften/Parser/PayloadParsers/RosterParser.h> + +using namespace Swift; + +typedef GenericPayloadPersister<RosterPayload, RosterParser, RosterSerializer> RosterPersister; + +RosterFileStorage::RosterFileStorage(const boost::filesystem::path& path) : path(path) { +} + +boost::shared_ptr<RosterPayload> RosterFileStorage::getRoster() const { + return RosterPersister().loadPayloadGeneric(path); +} + +void RosterFileStorage::setRoster(boost::shared_ptr<RosterPayload> roster) { + RosterPersister().savePayload(roster, path); +} diff --git a/Swift/Controllers/Storages/RosterFileStorage.h b/Swift/Controllers/Storages/RosterFileStorage.h new file mode 100644 index 0000000..cb00969 --- /dev/null +++ b/Swift/Controllers/Storages/RosterFileStorage.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/filesystem/path.hpp> + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + class RosterFileStorage : public RosterStorage { + public: + RosterFileStorage(const boost::filesystem::path& path); + + virtual boost::shared_ptr<RosterPayload> getRoster() const; + virtual void setRoster(boost::shared_ptr<RosterPayload>); + + private: + boost::filesystem::path path; + }; +} diff --git a/Swift/Controllers/StoragesFactory.h b/Swift/Controllers/Storages/StoragesFactory.h index 441a4e9..203f9c9 100644 --- a/Swift/Controllers/StoragesFactory.h +++ b/Swift/Controllers/Storages/StoragesFactory.h @@ -8,6 +8,7 @@ namespace Swift { class Storages; + class JID; class StoragesFactory { public: diff --git a/Swiften/VCards/VCardFileStorage.cpp b/Swift/Controllers/Storages/VCardFileStorage.cpp index 476fde1..d799a90 100644 --- a/Swiften/VCards/VCardFileStorage.cpp +++ b/Swift/Controllers/Storages/VCardFileStorage.cpp @@ -4,22 +4,26 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/VCards/VCardFileStorage.h" +#include "Swift/Controllers/Storages/VCardFileStorage.h" #include <boost/filesystem/fstream.hpp> +#include <boost/filesystem.hpp> +#include <iostream> +#include <Swiften/Entity/GenericPayloadPersister.h> #include <Swiften/Base/String.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/StringCodecs/SHA1.h> #include <Swiften/Base/foreach.h> #include "Swiften/JID/JID.h" -#include "Swiften/Base/ByteArray.h" #include "Swiften/Elements/VCard.h" #include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" #include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" #include "Swiften/Parser/PayloadParsers/VCardParser.h" -namespace Swift { +using namespace Swift; + +typedef GenericPayloadPersister<VCard, VCardParser, VCardSerializer> VCardPersister; VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir) { cacheFile = vcardsPath / "phashes"; @@ -48,40 +52,14 @@ VCardFileStorage::VCardFileStorage(boost::filesystem::path dir) : vcardsPath(dir } boost::shared_ptr<VCard> VCardFileStorage::getVCard(const JID& jid) const { - boost::shared_ptr<VCard> result; - try { - boost::filesystem::path vcardPath(getVCardPath(jid)); - if (boost::filesystem::exists(vcardPath)) { - ByteArray data; - data.readFromFile(vcardPath.string()); - - VCardParser parser; - PayloadParserTester tester(&parser); - tester.parse(data.toString()); - result = boost::dynamic_pointer_cast<VCard>(parser.getPayload()); - } - } - catch (const boost::filesystem::filesystem_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - } + boost::shared_ptr<VCard> result = VCardPersister().loadPayloadGeneric(getVCardPath(jid)); getAndUpdatePhotoHash(jid, result); return result; } void VCardFileStorage::setVCard(const JID& jid, VCard::ref v) { - try { - boost::filesystem::path vcardPath(getVCardPath(jid)); - if (!boost::filesystem::exists(vcardPath.parent_path())) { - boost::filesystem::create_directories(vcardPath.parent_path()); - } - boost::filesystem::ofstream file(getVCardPath(jid)); - file << VCardSerializer().serializePayload(v); - file.close(); - getAndUpdatePhotoHash(jid, v); - } - catch (const boost::filesystem::filesystem_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - } + VCardPersister().savePayload(v, getVCardPath(jid)); + getAndUpdatePhotoHash(jid, v); } boost::filesystem::path VCardFileStorage::getVCardPath(const JID& jid) const { @@ -109,7 +87,7 @@ std::string VCardFileStorage::getPhotoHash(const JID& jid) const { std::string VCardFileStorage::getAndUpdatePhotoHash(const JID& jid, VCard::ref vCard) const { std::string hash; - if (vCard && !vCard->getPhoto().isEmpty()) { + if (vCard && !vCard->getPhoto().empty()) { hash = Hexify::hexify(SHA1::getHash(vCard->getPhoto())); } std::pair<PhotoHashMap::iterator, bool> r = photoHashes.insert(std::make_pair(jid, hash)); @@ -135,6 +113,3 @@ void VCardFileStorage::savePhotoHashes() const { std::cerr << "Error writing vcards file" << std::endl; } } - - -} diff --git a/Swiften/VCards/VCardFileStorage.h b/Swift/Controllers/Storages/VCardFileStorage.h index 26bf4b2..ba422f4 100644 --- a/Swiften/VCards/VCardFileStorage.h +++ b/Swift/Controllers/Storages/VCardFileStorage.h @@ -7,7 +7,7 @@ #pragma once #include <boost/shared_ptr.hpp> -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <string> #include <map> diff --git a/Swift/Controllers/SystemTrayController.cpp b/Swift/Controllers/SystemTrayController.cpp index 598771c..31fd4ff 100644 --- a/Swift/Controllers/SystemTrayController.cpp +++ b/Swift/Controllers/SystemTrayController.cpp @@ -22,7 +22,7 @@ SystemTrayController::SystemTrayController(EventController* eventController, Sys void SystemTrayController::handleEventQueueLengthChange(int /*length*/) { EventList events = eventController_->getEvents(); bool found = false; - for (EventList::iterator it = events.begin(); it != events.end(); it++) { + for (EventList::iterator it = events.begin(); it != events.end(); ++it) { if (boost::dynamic_pointer_cast<MessageEvent>(*it)) { found = true; break; diff --git a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h index c7f8be6..dea3ead 100644 --- a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h +++ b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h @@ -10,17 +10,21 @@ #include <boost/shared_ptr.hpp> #include <string> +#include <Swiften/JID/JID.h> + #include "Swift/Controllers/UIEvents/UIEvent.h" namespace Swift { class JoinMUCUIEvent : public UIEvent { public: typedef boost::shared_ptr<JoinMUCUIEvent> ref; - JoinMUCUIEvent(const JID& jid, const boost::optional<std::string>& nick = boost::optional<std::string>()) : jid_(jid), nick_(nick) {}; + JoinMUCUIEvent(const JID& jid, const boost::optional<std::string>& nick = boost::optional<std::string>(), bool joinAutomaticallyInFuture = false) : jid_(jid), nick_(nick), joinAutomatically_(joinAutomaticallyInFuture){}; boost::optional<std::string> getNick() {return nick_;}; JID getJID() {return jid_;}; + bool getShouldJoinAutomatically() {return joinAutomatically_;} private: JID jid_; boost::optional<std::string> nick_; + bool joinAutomatically_; }; } diff --git a/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h b/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h new file mode 100644 index 0000000..c3b4b49 --- /dev/null +++ b/Swift/Controllers/UIEvents/RequestAdHocUIEvent.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/UIInterfaces/MainWindow.h> + +#include <Swift/Controllers/UIEvents/UIEvent.h> + +namespace Swift { + class RequestAdHocUIEvent : public UIEvent { + public: + RequestAdHocUIEvent(const DiscoItems::Item& command) : command_(command) {}; + const DiscoItems::Item& getCommand() const {return command_;} + private: + DiscoItems::Item command_; + }; +} diff --git a/Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h b/Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h new file mode 100644 index 0000000..aff6909 --- /dev/null +++ b/Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/UIEvents/UIEvent.h> + +namespace Swift { + +class RequestFileTransferListUIEvent : public UIEvent { +}; + +} diff --git a/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h b/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h index dd2ff6c..2c7b105 100644 --- a/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h +++ b/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h @@ -6,18 +6,25 @@ #pragma once -#include <boost/optional.hpp> #include <boost/shared_ptr.hpp> - #include <string> + #include <Swift/Controllers/UIEvents/UIEvent.h> +#include <Swiften/JID/JID.h> namespace Swift { class RequestJoinMUCUIEvent : public UIEvent { public: typedef boost::shared_ptr<RequestJoinMUCUIEvent> ref; - RequestJoinMUCUIEvent() { + RequestJoinMUCUIEvent(const JID& room = JID()) : room(room) { } + + const JID& getRoom() const { + return room; + } + + private: + JID room; }; } diff --git a/Swift/Controllers/UIEvents/SendFileUIEvent.h b/Swift/Controllers/UIEvents/SendFileUIEvent.h new file mode 100644 index 0000000..3bfa69d --- /dev/null +++ b/Swift/Controllers/UIEvents/SendFileUIEvent.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/JID/JID.h> +#include <Swift/Controllers/UIEvents/UIEvent.h> + +namespace Swift { + class SendFileUIEvent : public UIEvent { + public: + typedef boost::shared_ptr<SendFileUIEvent> ref; + + SendFileUIEvent(const JID& jid, const std::string& filename) : jid(jid), filename(filename) { + } + + const JID& getJID() const { + return jid; + } + + const std::string& getFilename() const { + return filename; + } + + private: + JID jid; + std::string filename; + }; +} diff --git a/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h b/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h new file mode 100644 index 0000000..f7a5d39 --- /dev/null +++ b/Swift/Controllers/UIInterfaces/AdHocCommandWindow.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +namespace Swift { + class AdHocCommandWindow { + public: + virtual ~AdHocCommandWindow() {}; + }; +} diff --git a/Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h b/Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h new file mode 100644 index 0000000..ae77180 --- /dev/null +++ b/Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/UIInterfaces/AdHocCommandWindow.h> +#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h> + +namespace Swift { + class AdHocCommandWindowFactory { + public: + virtual ~AdHocCommandWindowFactory() {} + /** + * The UI should deal with the lifetime of this window (i.e. DeleteOnClose), + * so the result isn't returned. + */ + virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) = 0; + }; +} diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h index a2a0874..d047f8c 100644 --- a/Swift/Controllers/UIInterfaces/ChatListWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h @@ -1,23 +1,60 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once +#include <list> #include <boost/shared_ptr.hpp> +#include <Swiften/MUC/MUCBookmark.h> +#include <Swiften/Elements/StatusShow.h> +#include <boost/filesystem/path.hpp> -#include "Swiften/MUC/MUCBookmark.h" +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class ChatListWindow { public: + class Chat { + public: + Chat(const JID& jid, const std::string& chatName, const std::string& activity, int unreadCount, StatusShow::Type statusType, const boost::filesystem::path& avatarPath, bool isMUC, const std::string& nick = "") + : jid(jid), chatName(chatName), activity(activity), statusType(statusType), isMUC(isMUC), nick(nick), unreadCount(unreadCount), avatarPath(avatarPath) {} + /** Assume that nicks and other transient features aren't important for equality */ + bool operator==(const Chat& other) const { + return jid.toBare() == other.jid.toBare() + && isMUC == other.isMUC; + }; + void setUnreadCount(int unread) { + unreadCount = unread; + } + void setStatusType(StatusShow::Type type) { + statusType = type; + } + void setAvatarPath(const boost::filesystem::path& path) { + avatarPath = path; + } + JID jid; + std::string chatName; + std::string activity; + StatusShow::Type statusType; + bool isMUC; + std::string nick; + int unreadCount; + boost::filesystem::path avatarPath; + }; virtual ~ChatListWindow(); virtual void setBookmarksEnabled(bool enabled) = 0; virtual void addMUCBookmark(const MUCBookmark& bookmark) = 0; virtual void removeMUCBookmark(const MUCBookmark& bookmark) = 0; - virtual void clear() = 0; + virtual void setRecents(const std::list<Chat>& recents) = 0; + virtual void setUnreadCount(int unread) = 0; + virtual void clearBookmarks() = 0; + + boost::signal<void (const MUCBookmark&)> onMUCBookmarkActivated; + boost::signal<void (const Chat&)> onRecentActivated; + boost::signal<void ()> onClearRecentsRequested; }; } diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h index c7bcf1e..df57d80 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatWindow.h @@ -14,18 +14,26 @@ #include <vector> #include <string> -#include "Swiften/Elements/SecurityLabelsCatalog.h" -#include "Swiften/Elements/ChatState.h" +#include <Swiften/Elements/SecurityLabelsCatalog.h> +#include <Swiften/Elements/ChatState.h> +#include <Swiften/Elements/Form.h> + namespace Swift { class AvatarManager; class TreeWidget; class Roster; class TabComplete; + class RosterItem; + class ContactRosterItem; + class FileTransferController; class ChatWindow { public: enum AckState {Pending, Received, Failed}; + enum Tristate {Yes, No, Maybe}; + enum OccupantAction {Kick}; + enum FileTransferState {WaitingForAccept, Negotiating, Transferring, Canceled, Finished, FTFailed}; ChatWindow() {} virtual ~ChatWindow() {}; @@ -40,6 +48,12 @@ namespace Swift { virtual void addSystemMessage(const std::string& message) = 0; virtual void addPresenceMessage(const std::string& message) = 0; virtual void addErrorMessage(const std::string& message) = 0; + virtual void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) = 0; + + // File transfer related stuff + virtual std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes) = 0; + virtual void setFileTransferProgress(std::string, const int percentageDone) = 0; + virtual void setFileTransferStatus(std::string, const FileTransferState state, const std::string& msg = "") = 0; virtual void setContactChatState(ChatState::ChatStateType state) = 0; virtual void setName(const std::string& name) = 0; @@ -47,6 +61,7 @@ namespace Swift { virtual void activate() = 0; virtual void setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) = 0; virtual void setSecurityLabelsEnabled(bool enabled) = 0; + virtual void setCorrectionEnabled(Tristate enabled) = 0; virtual void setUnreadMessageCount(int count) = 0; virtual void convertToMUC() = 0; // virtual TreeWidget *getTreeWidget() = 0; @@ -58,12 +73,42 @@ namespace Swift { virtual void replaceLastMessage(const std::string& message) = 0; virtual void setAckState(const std::string& id, AckState state) = 0; virtual void flash() = 0; + virtual void setSubject(const std::string& subject) = 0; + /** + * Set an alert on the window. + * @param alertText Description of alert (required). + * @param buttonText Button text to use (optional, no button is shown if empty). + */ + virtual void setAlert(const std::string& alertText, const std::string& buttonText = "") = 0; + /** + * Removes an alert. + */ + virtual void cancelAlert() = 0; + + /** + * Actions that can be performed on the selected occupant. + */ + virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions) = 0; + virtual void showRoomConfigurationForm(Form::ref) = 0; boost::signal<void ()> onClosed; boost::signal<void ()> onAllMessagesRead; - boost::signal<void (const std::string&)> onSendMessageRequest; + boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest; + boost::signal<void ()> onSendCorrectionMessageRequest; boost::signal<void ()> onUserTyping; boost::signal<void ()> onUserCancelsTyping; + boost::signal<void ()> onAlertButtonClicked; + boost::signal<void (ContactRosterItem*)> onOccupantSelectionChanged; + boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected; + boost::signal<void (const std::string&)> onChangeSubjectRequest; + boost::signal<void (Form::ref)> onConfigureRequest; + boost::signal<void ()> onDestroyRequest; + + // File transfer related + boost::signal<void (std::string /* id */)> onFileTransferCancel; + boost::signal<void (std::string /* id */, std::string /* description */)> onFileTransferStart; + boost::signal<void (std::string /* id */, std::string /* path */)> onFileTransferAccept; + boost::signal<void (std::string /* path */)> onSendFileRequest; }; } #endif diff --git a/Swift/Controllers/UIInterfaces/EventWindow.h b/Swift/Controllers/UIInterfaces/EventWindow.h index e756655..3ca2c82 100644 --- a/Swift/Controllers/UIInterfaces/EventWindow.h +++ b/Swift/Controllers/UIInterfaces/EventWindow.h @@ -6,7 +6,8 @@ #pragma once -#include "boost/shared_ptr.hpp" +#include <boost/shared_ptr.hpp> + #include "Swift/Controllers/XMPPEvents/StanzaEvent.h" namespace Swift { diff --git a/Swift/Controllers/UIInterfaces/FileTransferListWidget.h b/Swift/Controllers/UIInterfaces/FileTransferListWidget.h new file mode 100644 index 0000000..01dcfd3 --- /dev/null +++ b/Swift/Controllers/UIInterfaces/FileTransferListWidget.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +namespace Swift { + +class FileTransferOverview; + +class FileTransferListWidget { +public: + virtual ~FileTransferListWidget() {} + + virtual void show() = 0; + virtual void activate() = 0; + + virtual void setFileTransferOverview(FileTransferOverview*) = 0; +}; + +} diff --git a/Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h b/Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h new file mode 100644 index 0000000..0b08fb3 --- /dev/null +++ b/Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swift/Controllers/UIInterfaces/FileTransferListWidget.h" + +namespace Swift { + +class FileTransferListWidgetFactory { +public: + virtual ~FileTransferListWidgetFactory() {} + + virtual FileTransferListWidget* createFileTransferListWidget() = 0; +}; + +} diff --git a/Swift/Controllers/UIInterfaces/JoinMUCWindow.h b/Swift/Controllers/UIInterfaces/JoinMUCWindow.h index 2e3d43c..4873c9b 100644 --- a/Swift/Controllers/UIInterfaces/JoinMUCWindow.h +++ b/Swift/Controllers/UIInterfaces/JoinMUCWindow.h @@ -21,7 +21,6 @@ namespace Swift { virtual void setMUC(const std::string& nick) = 0; virtual void show() = 0; - boost::signal<void (const JID& /* muc */, const std::string& /* nick */, bool /* autoJoin */)> onJoinMUC; boost::signal<void ()> onSearchMUC; }; } diff --git a/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h b/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h index 9c8bd77..cd8021b 100644 --- a/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h +++ b/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h @@ -9,10 +9,11 @@ #include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h> namespace Swift { + class UIEventStream; class JoinMUCWindowFactory { public: virtual ~JoinMUCWindowFactory() {}; - virtual JoinMUCWindow* createJoinMUCWindow() = 0; + virtual JoinMUCWindow* createJoinMUCWindow(UIEventStream* uiEventStream) = 0; }; } diff --git a/Swift/Controllers/UIInterfaces/LoginWindow.h b/Swift/Controllers/UIInterfaces/LoginWindow.h index 61fcaa1..fcaeb42 100644 --- a/Swift/Controllers/UIInterfaces/LoginWindow.h +++ b/Swift/Controllers/UIInterfaces/LoginWindow.h @@ -27,6 +27,8 @@ namespace Swift { boost::signal<void (const std::string&, const std::string&, const std::string& /* certificateFile */, bool /* remember password*/, bool /* login automatically */)> onLoginRequest; virtual void setLoginAutomatically(bool loginAutomatically) = 0; virtual void quit() = 0; + /** Disable any GUI elements that suggest saving of passwords. */ + virtual void setRememberingAllowed(bool allowed) = 0; /** Blocking request whether a cert should be permanently trusted.*/ virtual bool askUserToTrustCertificatePermanently(const std::string& message, Certificate::ref) = 0; diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h index 2fd463b..93584e7 100644 --- a/Swift/Controllers/UIInterfaces/MainWindow.h +++ b/Swift/Controllers/UIInterfaces/MainWindow.h @@ -9,6 +9,7 @@ #include <string> #include "Swiften/JID/JID.h" #include "Swiften/Elements/StatusShow.h" +#include "Swiften/Elements/DiscoItems.h" #include "Swiften/Base/boost_bsignals.h" #include <boost/shared_ptr.hpp> @@ -33,6 +34,7 @@ namespace Swift { /** Must be able to cope with NULL to clear the roster */ virtual void setRosterModel(Roster* roster) = 0; virtual void setConnecting() = 0; + virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) = 0; boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest; boost::signal<void ()> onSignOutRequest; diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h index 9b36ac5..cf89dab 100644 --- a/Swift/Controllers/UIInterfaces/UIFactory.h +++ b/Swift/Controllers/UIInterfaces/UIFactory.h @@ -17,6 +17,8 @@ #include <Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h> #include <Swift/Controllers/UIInterfaces/ProfileWindowFactory.h> #include <Swift/Controllers/UIInterfaces/ContactEditWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/AdHocCommandWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/FileTransferListWidgetFactory.h> namespace Swift { class UIFactory : @@ -26,11 +28,13 @@ namespace Swift { public LoginWindowFactory, public MainWindowFactory, public MUCSearchWindowFactory, - public XMLConsoleWidgetFactory, + public XMLConsoleWidgetFactory, public UserSearchWindowFactory, public JoinMUCWindowFactory, public ProfileWindowFactory, - public ContactEditWindowFactory { + public ContactEditWindowFactory, + public AdHocCommandWindowFactory, + public FileTransferListWidgetFactory { public: virtual ~UIFactory() {} }; diff --git a/Swift/Controllers/UIInterfaces/XMLConsoleWidget.h b/Swift/Controllers/UIInterfaces/XMLConsoleWidget.h index 3cd0947..caec38c 100644 --- a/Swift/Controllers/UIInterfaces/XMLConsoleWidget.h +++ b/Swift/Controllers/UIInterfaces/XMLConsoleWidget.h @@ -6,15 +6,15 @@ #pragma once -#include <string> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class XMLConsoleWidget { public: virtual ~XMLConsoleWidget(); - virtual void handleDataRead(const std::string& data) = 0; - virtual void handleDataWritten(const std::string& data) = 0; + virtual void handleDataRead(const SafeByteArray& data) = 0; + virtual void handleDataWritten(const SafeByteArray& data) = 0; virtual void show() = 0; virtual void activate() = 0; diff --git a/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp new file mode 100644 index 0000000..ee0ee9f --- /dev/null +++ b/Swift/Controllers/UnitTest/ChatMessageSummarizerTest.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swift/Controllers/ChatMessageSummarizer.h" + +using namespace Swift; +using namespace std; + +class ChatMessageSummarizerTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ChatMessageSummarizerTest); + CPPUNIT_TEST(testEmpty); + CPPUNIT_TEST(testCurrentNone); + CPPUNIT_TEST(testCurrentCount); + CPPUNIT_TEST(testCurrentCountOthersNone); + CPPUNIT_TEST(testCurrentCountOtherCount); + CPPUNIT_TEST(testCurrentNoneOtherCount); + CPPUNIT_TEST(testCurrentCountOthersCount); + CPPUNIT_TEST(testCurrentNoneOthersCount); + CPPUNIT_TEST(testCurrentCountSomeOthersCount); + CPPUNIT_TEST_SUITE_END(); + +public: + ChatMessageSummarizerTest() {}; + + void setUp() { + + } + + void testEmpty() { + string current(""); + vector<UnreadPair> unreads; + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(current, summary.getSummary(current, unreads)); + } + + void testCurrentNone() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bob", 0)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(current, summary.getSummary(current, unreads)); + } + + void testCurrentCount() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bob", 3)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob (3)"), summary.getSummary(current, unreads)); + } + + void testCurrentCountOthersNone() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bert", 0)); + unreads.push_back(UnreadPair("Bob", 3)); + unreads.push_back(UnreadPair("Betty", 0)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob (3)"), summary.getSummary(current, unreads)); + } + + void testCurrentCountOtherCount() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bert", 0)); + unreads.push_back(UnreadPair("Bob", 3)); + unreads.push_back(UnreadPair("Betty", 7)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob (3), Betty (7)"), summary.getSummary(current, unreads)); + } + + void testCurrentNoneOtherCount() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bert", 0)); + unreads.push_back(UnreadPair("Bob", 0)); + unreads.push_back(UnreadPair("Betty", 7)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob, Betty (7)"), summary.getSummary(current, unreads)); + } + + void testCurrentNoneOthersCount() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bert", 2)); + unreads.push_back(UnreadPair("Bob", 0)); + unreads.push_back(UnreadPair("Betty", 7)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob and 2 others (9)"), summary.getSummary(current, unreads)); + } + + void testCurrentCountOthersCount() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bert", 2)); + unreads.push_back(UnreadPair("Bob", 11)); + unreads.push_back(UnreadPair("Betty", 7)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob (11) and 2 others (9)"), summary.getSummary(current, unreads)); + } + + void testCurrentCountSomeOthersCount() { + string current("Bob"); + vector<UnreadPair> unreads; + unreads.push_back(UnreadPair("Bert", 2)); + unreads.push_back(UnreadPair("Beverly", 0)); + unreads.push_back(UnreadPair("Bob", 11)); + unreads.push_back(UnreadPair("Beatrice", 0)); + unreads.push_back(UnreadPair("Betty", 7)); + ChatMessageSummarizer summary; + CPPUNIT_ASSERT_EQUAL(string("Bob (11) and 2 others (9)"), summary.getSummary(current, unreads)); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ChatMessageSummarizerTest); diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h index 53a90a7..ad8856b 100644 --- a/Swift/Controllers/UnitTest/MockChatWindow.h +++ b/Swift/Controllers/UnitTest/MockChatWindow.h @@ -11,7 +11,7 @@ namespace Swift { class MockChatWindow : public ChatWindow { public: - MockChatWindow() {}; + MockChatWindow() : labelsEnabled_(false) {}; virtual ~MockChatWindow(); virtual std::string addMessage(const std::string& message, const std::string& /*senderName*/, bool /*senderIsSelf*/, boost::shared_ptr<SecurityLabel> /*label*/, const std::string& /*avatarPath*/, const boost::posix_time::ptime&) {lastMessageBody_ = message; return "";}; @@ -20,6 +20,11 @@ namespace Swift { virtual void addErrorMessage(const std::string& /*message*/) {}; virtual void addPresenceMessage(const std::string& /*message*/) {}; + // File transfer related stuff + virtual std::string addFileTransfer(const std::string& /*senderName*/, bool /*senderIsSelf*/,const std::string& /*filename*/, const boost::uintmax_t /*sizeInBytes*/) { return 0; }; + virtual void setFileTransferProgress(std::string /*id*/, const int /*alreadyTransferedBytes*/) { }; + virtual void setFileTransferStatus(std::string /*id*/, const FileTransferState /*state*/, const std::string& /*msg*/) { }; + virtual void setContactChatState(ChatState::ChatStateType /*state*/) {}; virtual void setName(const std::string& name) {name_ = name;}; virtual void show() {}; @@ -34,12 +39,19 @@ namespace Swift { virtual void setRosterModel(Roster* /*roster*/) {}; virtual void setTabComplete(TabComplete*) {}; virtual void replaceLastMessage(const std::string&) {}; + virtual void replaceMessage(const std::string&, const std::string&, const boost::posix_time::ptime&) {}; void setAckState(const std::string& /*id*/, AckState /*state*/) {}; virtual void flash() {}; + virtual void setAlert(const std::string& /*alertText*/, const std::string& /*buttonText*/) {}; + virtual void cancelAlert() {}; + virtual void setCorrectionEnabled(Tristate /*enabled*/) {} + void setAvailableOccupantActions(const std::vector<OccupantAction>&/* actions*/) {} + void setSubject(const std::string& /*subject*/) {} + virtual void showRoomConfigurationForm(Form::ref) {} boost::signal<void ()> onClosed; boost::signal<void ()> onAllMessagesRead; - boost::signal<void (const std::string&)> onSendMessageRequest; + boost::signal<void (const std::string&, bool isCorrection)> onSendMessageRequest; std::string name_; std::string lastMessageBody_; diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h index afa5c2a..f773062 100644 --- a/Swift/Controllers/UnitTest/MockMainWindow.h +++ b/Swift/Controllers/UnitTest/MockMainWindow.h @@ -20,6 +20,7 @@ namespace Swift { virtual void setMyAvatarPath(const std::string& /*path*/) {}; virtual void setMyStatusText(const std::string& /*status*/) {}; virtual void setMyStatusType(StatusShow::Type /*type*/) {}; + virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& /*commands*/) {}; virtual void setConnecting() {}; Roster* roster; diff --git a/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp b/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp index 42cfc5f..3e9be13 100644 --- a/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp +++ b/Swift/Controllers/UnitTest/PresenceNotifierTest.cpp @@ -70,7 +70,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveFirstPresenceCreatesAvailableNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Online); @@ -79,7 +79,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveSecondPresenceCreatesStatusChangeNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Away); notifier->notifications.clear(); @@ -90,7 +90,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveUnavailablePresenceAfterAvailablePresenceCreatesUnavailableNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Away); notifier->notifications.clear(); @@ -101,7 +101,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveUnavailablePresenceWithoutAvailableDoesNotCreateNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendUnavailablePresence(user1); @@ -109,7 +109,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveAvailablePresenceAfterUnavailableCreatesAvailableNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Away); sendUnavailablePresence(user1); notifier->notifications.clear(); @@ -121,7 +121,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveAvailablePresenceAfterReconnectCreatesAvailableNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Away); stanzaChannel->setAvailable(false); stanzaChannel->setAvailable(true); @@ -134,7 +134,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveAvailablePresenceFromMUCDoesNotCreateNotification() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); mucRegistry->addMUC(JID("teaparty@wonderland.lit")); sendPresence(JID("teaparty@wonderland.lit/Alice"), StatusShow::Away); @@ -143,8 +143,8 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testNotificationPicture() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); - avatarManager->avatars[user1] = ByteArray("abcdef"); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); + avatarManager->avatars[user1] = createByteArray("abcdef"); sendPresence(user1, StatusShow::Online); @@ -153,7 +153,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testNotificationActivationEmitsSignal() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Online); CPPUNIT_ASSERT(notifier->notifications[0].callback); @@ -164,7 +164,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testNotificationSubjectContainsNameForJIDInRoster() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); roster->addContact(user1.toBare(), "User 1", std::vector<std::string>(), RosterItemPayload::Both); sendPresence(user1, StatusShow::Online); @@ -175,7 +175,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testNotificationSubjectContainsJIDForJIDNotInRoster() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Online); @@ -185,7 +185,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testNotificationSubjectContainsStatus() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Away); @@ -195,7 +195,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testNotificationMessageContainsStatusMessage() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); sendPresence(user1, StatusShow::Away); @@ -204,7 +204,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveFirstPresenceWithQuietPeriodDoesNotNotify() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); testling->setInitialQuietPeriodMS(10); sendPresence(user1, StatusShow::Online); @@ -213,7 +213,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceivePresenceDuringQuietPeriodDoesNotNotify() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); testling->setInitialQuietPeriodMS(10); sendPresence(user1, StatusShow::Online); @@ -224,7 +224,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceivePresenceDuringQuietPeriodResetsTimer() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); testling->setInitialQuietPeriodMS(10); sendPresence(user1, StatusShow::Online); @@ -237,7 +237,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceivePresenceAfterQuietPeriodNotifies() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); testling->setInitialQuietPeriodMS(10); sendPresence(user1, StatusShow::Online); @@ -248,7 +248,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveFirstPresenceWithQuietPeriodDoesNotCountAsQuietPeriod() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); testling->setInitialQuietPeriodMS(10); timerFactory->setTime(11); @@ -258,7 +258,7 @@ class PresenceNotifierTest : public CppUnit::TestFixture { } void testReceiveFirstPresenceAfterReconnectWithQuietPeriodDoesNotNotify() { - std::auto_ptr<PresenceNotifier> testling = createNotifier(); + boost::shared_ptr<PresenceNotifier> testling = createNotifier(); testling->setInitialQuietPeriodMS(10); sendPresence(user1, StatusShow::Online); timerFactory->setTime(15); @@ -275,8 +275,8 @@ class PresenceNotifierTest : public CppUnit::TestFixture { private: - std::auto_ptr<PresenceNotifier> createNotifier() { - std::auto_ptr<PresenceNotifier> result(new PresenceNotifier(stanzaChannel, notifier, mucRegistry, avatarManager, nickResolver, presenceOracle, timerFactory)); + boost::shared_ptr<PresenceNotifier> createNotifier() { + boost::shared_ptr<PresenceNotifier> result(new PresenceNotifier(stanzaChannel, notifier, mucRegistry, avatarManager, nickResolver, presenceOracle, timerFactory)); result->onNotificationActivated.connect(boost::bind(&PresenceNotifierTest::handleNotificationActivated, this, _1)); result->setInitialQuietPeriodMS(0); return result; diff --git a/Swift/Controllers/XMLConsoleController.cpp b/Swift/Controllers/XMLConsoleController.cpp index a3510d1..d21f312 100644 --- a/Swift/Controllers/XMLConsoleController.cpp +++ b/Swift/Controllers/XMLConsoleController.cpp @@ -30,13 +30,13 @@ void XMLConsoleController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) { } } -void XMLConsoleController::handleDataRead(const std::string& data) { +void XMLConsoleController::handleDataRead(const SafeByteArray& data) { if (xmlConsoleWidget) { xmlConsoleWidget->handleDataRead(data); } } -void XMLConsoleController::handleDataWritten(const std::string& data) { +void XMLConsoleController::handleDataWritten(const SafeByteArray& data) { if (xmlConsoleWidget) { xmlConsoleWidget->handleDataWritten(data); } diff --git a/Swift/Controllers/XMLConsoleController.h b/Swift/Controllers/XMLConsoleController.h index d12982f..6426a85 100644 --- a/Swift/Controllers/XMLConsoleController.h +++ b/Swift/Controllers/XMLConsoleController.h @@ -11,6 +11,7 @@ #include <boost/shared_ptr.hpp> #include "Swift/Controllers/UIEvents/UIEventStream.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { @@ -23,8 +24,8 @@ namespace Swift { ~XMLConsoleController(); public: - void handleDataRead(const std::string& data); - void handleDataWritten(const std::string& data); + void handleDataRead(const SafeByteArray& data); + void handleDataWritten(const SafeByteArray& data); private: void handleUIEvent(boost::shared_ptr<UIEvent> event); diff --git a/Swift/Controllers/XMPPEvents/EventController.cpp b/Swift/Controllers/XMPPEvents/EventController.cpp index 7f8f216..98fd634 100644 --- a/Swift/Controllers/XMPPEvents/EventController.cpp +++ b/Swift/Controllers/XMPPEvents/EventController.cpp @@ -9,6 +9,7 @@ #include <boost/bind.hpp> #include <algorithm> +#include <Swiften/Base/foreach.h> #include "Swift/Controllers/XMPPEvents/MessageEvent.h" #include "Swift/Controllers/XMPPEvents/ErrorEvent.h" #include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h" diff --git a/Swift/Controllers/XMPPURIController.cpp b/Swift/Controllers/XMPPURIController.cpp new file mode 100644 index 0000000..00759b8 --- /dev/null +++ b/Swift/Controllers/XMPPURIController.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/XMPPURIController.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <SwifTools/URIHandler/URIHandler.h> +#include <SwifTools/URIHandler/XMPPURI.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> + +using namespace Swift; + +XMPPURIController::XMPPURIController(URIHandler* uriHandler, UIEventStream* uiEventStream) : uriHandler(uriHandler), uiEventStream(uiEventStream) { + uriHandler->onURI.connect(boost::bind(&XMPPURIController::handleURI, this, _1)); +} + +XMPPURIController::~XMPPURIController() { + uriHandler->onURI.disconnect(boost::bind(&XMPPURIController::handleURI, this, _1)); +} + +void XMPPURIController::handleURI(const std::string& s) { + XMPPURI uri = XMPPURI::fromString(s); + if (!uri.isNull()) { + if (uri.getQueryType() == "join") { + uiEventStream->send(boost::make_shared<RequestJoinMUCUIEvent>(uri.getPath())); + } + else { + uiEventStream->send(boost::make_shared<RequestChatUIEvent>(uri.getPath())); + } + } +} diff --git a/Swift/Controllers/XMPPURIController.h b/Swift/Controllers/XMPPURIController.h new file mode 100644 index 0000000..54534d4 --- /dev/null +++ b/Swift/Controllers/XMPPURIController.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class URIHandler; + class JID; + class UIEventStream; + + class XMPPURIController { + public: + XMPPURIController(URIHandler* uriHandler, UIEventStream* uiEventStream); + ~XMPPURIController(); + + boost::signal<void (const JID&)> onStartChat; + boost::signal<void (const JID&)> onJoinMUC; + + private: + void handleURI(const std::string&); + + private: + URIHandler* uriHandler; + UIEventStream* uiEventStream; + }; +} diff --git a/Swift/QtUI/.gitignore b/Swift/QtUI/.gitignore index f539e86..53acb9f 100644 --- a/Swift/QtUI/.gitignore +++ b/Swift/QtUI/.gitignore @@ -1,3 +1,4 @@ Swift BuildVersion.h *.dmg +swift-open-uri diff --git a/Swift/QtUI/ChatList/ChatListDelegate.cpp b/Swift/QtUI/ChatList/ChatListDelegate.cpp index 274a10a..29dba62 100644 --- a/Swift/QtUI/ChatList/ChatListDelegate.cpp +++ b/Swift/QtUI/ChatList/ChatListDelegate.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,6 +11,7 @@ #include "Swift/QtUI/Roster/GroupItemDelegate.h" #include "Swift/QtUI/ChatList/ChatListItem.h" #include "Swift/QtUI/ChatList/ChatListMUCItem.h" +#include "Swift/QtUI/ChatList/ChatListRecentItem.h" #include "Swift/QtUI/ChatList/ChatListGroupItem.h" namespace Swift { @@ -27,7 +28,11 @@ QSize ChatListDelegate::sizeHint(const QStyleOptionViewItem& option, const QMode ChatListItem* item = static_cast<ChatListItem*>(index.internalPointer()); if (item && dynamic_cast<ChatListMUCItem*>(item)) { return mucSizeHint(option, index); - } else if (item && dynamic_cast<ChatListGroupItem*>(item)) { + } + else if (item && dynamic_cast<ChatListRecentItem*>(item)) { + return common_.contactSizeHint(option, index); + } + else if (item && dynamic_cast<ChatListGroupItem*>(item)) { return groupDelegate_->sizeHint(option, index); } return QStyledItemDelegate::sizeHint(option, index); @@ -40,14 +45,23 @@ QSize ChatListDelegate::mucSizeHint(const QStyleOptionViewItem& /*option*/, cons return QSize(150, sizeByText); } +QSize ChatListDelegate::recentSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const { + return mucSizeHint(option, index); +} + void ChatListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { ChatListItem* item = static_cast<ChatListItem*>(index.internalPointer()); if (item && dynamic_cast<ChatListMUCItem*>(item)) { paintMUC(painter, option, dynamic_cast<ChatListMUCItem*>(item)); - } else if (item && dynamic_cast<ChatListGroupItem*>(item)) { + } + else if (item && dynamic_cast<ChatListRecentItem*>(item)) { + paintRecent(painter, option, dynamic_cast<ChatListRecentItem*>(item)); + } + else if (item && dynamic_cast<ChatListGroupItem*>(item)) { ChatListGroupItem* group = dynamic_cast<ChatListGroupItem*>(item); groupDelegate_->paint(painter, option, group->data(Qt::DisplayRole).toString(), group->rowCount(), option.state & QStyle::State_Open); - } else { + } + else { QStyledItemDelegate::paint(painter, option, index); } } @@ -78,9 +92,24 @@ void ChatListDelegate::paintMUC(QPainter* painter, const QStyleOptionViewItem& o painter->setPen(QPen(QColor(160,160,160))); QRect detailRegion(textRegion.adjusted(0, nameHeight, 0, 0)); - DelegateCommons::drawElidedText(painter, detailRegion, item->data(DetailTextRole).toString()); + DelegateCommons::drawElidedText(painter, detailRegion, item->data(ChatListMUCItem::DetailTextRole).toString()); painter->restore(); } +void ChatListDelegate::paintRecent(QPainter* painter, const QStyleOptionViewItem& option, ChatListRecentItem* item) const { + QColor nameColor = item->data(Qt::TextColorRole).value<QColor>(); + QString avatarPath; + if (item->data(ChatListRecentItem::AvatarRole).isValid() && !item->data(ChatListRecentItem::AvatarRole).value<QString>().isNull()) { + avatarPath = item->data(ChatListRecentItem::AvatarRole).value<QString>(); + } + QIcon presenceIcon = item->data(ChatListRecentItem::PresenceIconRole).isValid() && !item->data(ChatListRecentItem::PresenceIconRole).value<QIcon>().isNull() + ? item->data(ChatListRecentItem::PresenceIconRole).value<QIcon>() + : QIcon(":/icons/offline.png"); + QString name = item->data(Qt::DisplayRole).toString(); + //qDebug() << "Avatar for " << name << " = " << avatarPath; + QString statusText = item->data(ChatListRecentItem::DetailTextRole).toString(); + common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, item->getChat().unreadCount); +} + } diff --git a/Swift/QtUI/ChatList/ChatListDelegate.h b/Swift/QtUI/ChatList/ChatListDelegate.h index f6c6c40..a898df4 100644 --- a/Swift/QtUI/ChatList/ChatListDelegate.h +++ b/Swift/QtUI/ChatList/ChatListDelegate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -12,6 +12,7 @@ namespace Swift { class ChatListMUCItem; + class ChatListRecentItem; class ChatListDelegate : public QStyledItemDelegate { public: ChatListDelegate(); @@ -20,7 +21,9 @@ namespace Swift { void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; private: void paintMUC(QPainter* painter, const QStyleOptionViewItem& option, ChatListMUCItem* item) const; + void paintRecent(QPainter* painter, const QStyleOptionViewItem& option, ChatListRecentItem* item) const; QSize mucSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const; + QSize recentSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const; DelegateCommons common_; GroupItemDelegate* groupDelegate_; diff --git a/Swift/QtUI/ChatList/ChatListGroupItem.h b/Swift/QtUI/ChatList/ChatListGroupItem.h index cc4d4af..a1e479f 100644 --- a/Swift/QtUI/ChatList/ChatListGroupItem.h +++ b/Swift/QtUI/ChatList/ChatListGroupItem.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -13,8 +13,8 @@ namespace Swift { class ChatListGroupItem : public ChatListItem { public: - ChatListGroupItem(const QString& name, ChatListGroupItem* parent) : ChatListItem(parent), name_(name) {}; - void addItem(ChatListItem* item) {items_.push_back(item); qStableSort(items_.begin(), items_.end(), pointerItemLessThan);}; + ChatListGroupItem(const QString& name, ChatListGroupItem* parent, bool sorted = true) : ChatListItem(parent), name_(name), sorted_(sorted) {}; + void addItem(ChatListItem* item) {items_.push_back(item); if (sorted_) {qStableSort(items_.begin(), items_.end(), pointerItemLessThan);}}; void remove(int index) {items_.removeAt(index);}; int rowCount() {return items_.size();}; ChatListItem* item(int i) {return items_[i];}; @@ -30,5 +30,6 @@ namespace Swift { QString name_; QList<ChatListItem*> items_; + bool sorted_; }; } diff --git a/Swift/QtUI/ChatList/ChatListMUCItem.cpp b/Swift/QtUI/ChatList/ChatListMUCItem.cpp index e374ed5..68f9581 100644 --- a/Swift/QtUI/ChatList/ChatListMUCItem.cpp +++ b/Swift/QtUI/ChatList/ChatListMUCItem.cpp @@ -13,7 +13,7 @@ ChatListMUCItem::ChatListMUCItem(const MUCBookmark& bookmark, ChatListGroupItem* } -const MUCBookmark& ChatListMUCItem::getBookmark() { +const MUCBookmark& ChatListMUCItem::getBookmark() const { return bookmark_; } diff --git a/Swift/QtUI/ChatList/ChatListMUCItem.h b/Swift/QtUI/ChatList/ChatListMUCItem.h index 068f5d6..046d1d4 100644 --- a/Swift/QtUI/ChatList/ChatListMUCItem.h +++ b/Swift/QtUI/ChatList/ChatListMUCItem.h @@ -15,16 +15,16 @@ #include "Swift/QtUI/ChatList/ChatListItem.h" namespace Swift { - enum MUCItemRoles { - DetailTextRole = Qt::UserRole/*, - AvatarRole = Qt::UserRole + 1, - PresenceIconRole = Qt::UserRole + 2, - StatusShowTypeRole = Qt::UserRole + 3*/ - }; class ChatListMUCItem : public ChatListItem { public: + enum MUCItemRoles { + DetailTextRole = Qt::UserRole/*, + AvatarRole = Qt::UserRole + 1, + PresenceIconRole = Qt::UserRole + 2, + StatusShowTypeRole = Qt::UserRole + 3*/ + }; ChatListMUCItem(const MUCBookmark& bookmark, ChatListGroupItem* parent); - const MUCBookmark& getBookmark(); + const MUCBookmark& getBookmark() const; QVariant data(int role) const; private: MUCBookmark bookmark_; diff --git a/Swift/QtUI/ChatList/ChatListModel.cpp b/Swift/QtUI/ChatList/ChatListModel.cpp index ba7b766..681c1c2 100644 --- a/Swift/QtUI/ChatList/ChatListModel.cpp +++ b/Swift/QtUI/ChatList/ChatListModel.cpp @@ -1,22 +1,25 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swift/QtUI/ChatList/ChatListModel.h" +#include <Swift/QtUI/ChatList/ChatListModel.h> -#include "Swift/QtUI/ChatList/ChatListMUCItem.h" +#include <Swift/QtUI/ChatList/ChatListMUCItem.h> +#include <Swift/QtUI/ChatList/ChatListRecentItem.h> namespace Swift { ChatListModel::ChatListModel() { - root_ = new ChatListGroupItem("", NULL); + root_ = new ChatListGroupItem("", NULL, false); mucBookmarks_ = new ChatListGroupItem(tr("Bookmarked Rooms"), root_); + recents_ = new ChatListGroupItem(tr("Recent Chats"), root_, false); + root_->addItem(recents_); root_->addItem(mucBookmarks_); } -void ChatListModel::clear() { +void ChatListModel::clearBookmarks() { emit layoutAboutToBeChanged(); mucBookmarks_->clear(); emit layoutChanged(); @@ -43,6 +46,15 @@ void ChatListModel::removeMUCBookmark(const Swift::MUCBookmark& bookmark) { } } +void ChatListModel::setRecents(const std::list<ChatListWindow::Chat>& recents) { + emit layoutAboutToBeChanged(); + recents_->clear(); + foreach (const ChatListWindow::Chat chat, recents) { + recents_->addItem(new ChatListRecentItem(chat, recents_)); + } + emit layoutChanged(); +} + int ChatListModel::columnCount(const QModelIndex& /*parent*/) const { return 1; } diff --git a/Swift/QtUI/ChatList/ChatListModel.h b/Swift/QtUI/ChatList/ChatListModel.h index adde148..8e7828c 100644 --- a/Swift/QtUI/ChatList/ChatListModel.h +++ b/Swift/QtUI/ChatList/ChatListModel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -11,9 +11,10 @@ #include <QAbstractItemModel> #include <QList> -#include "Swiften/MUC/MUCBookmark.h" +#include <Swiften/MUC/MUCBookmark.h> +#include <Swift/Controllers/UIInterfaces/ChatListWindow.h> -#include "Swift/QtUI/ChatList/ChatListGroupItem.h" +#include <Swift/QtUI/ChatList/ChatListGroupItem.h> namespace Swift { class ChatListModel : public QAbstractItemModel { @@ -28,9 +29,11 @@ namespace Swift { QModelIndex parent(const QModelIndex& index) const; int rowCount(const QModelIndex& parent = QModelIndex()) const; ChatListItem* getItemForIndex(const QModelIndex& index) const; - void clear(); + void clearBookmarks(); + void setRecents(const std::list<ChatListWindow::Chat>& recents); private: ChatListGroupItem* mucBookmarks_; + ChatListGroupItem* recents_; ChatListGroupItem* root_; }; diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp new file mode 100644 index 0000000..6c9807f --- /dev/null +++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/QtUI/ChatList/ChatListRecentItem.h> + +#include <Swift/QtUI/QtSwiftUtil.h> + +namespace Swift { +ChatListRecentItem::ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) { + +} + +const ChatListWindow::Chat& ChatListRecentItem::getChat() const { + return chat_; +} + +QVariant ChatListRecentItem::data(int role) const { + switch (role) { + case Qt::DisplayRole: return P2QSTRING(chat_.chatName); + case DetailTextRole: return P2QSTRING(chat_.activity); + /*case Qt::TextColorRole: return textColor_; + case Qt::BackgroundColorRole: return backgroundColor_; + case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant(); + case StatusTextRole: return statusText_;*/ + case AvatarRole: return QVariant(QString(chat_.avatarPath.string().c_str())); + case PresenceIconRole: return getPresenceIcon(); + default: return QVariant(); + } +} + +QIcon ChatListRecentItem::getPresenceIcon() const { + QString iconString; + switch (chat_.statusType) { + case StatusShow::Online: iconString = "online";break; + case StatusShow::Away: iconString = "away";break; + case StatusShow::XA: iconString = "away";break; + case StatusShow::FFC: iconString = "online";break; + case StatusShow::DND: iconString = "dnd";break; + case StatusShow::None: iconString = "offline";break; + } + return QIcon(":/icons/" + iconString + ".png"); +} + +} diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.h b/Swift/QtUI/ChatList/ChatListRecentItem.h new file mode 100644 index 0000000..4e7bc3e --- /dev/null +++ b/Swift/QtUI/ChatList/ChatListRecentItem.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <QList> +#include <QIcon> + +#include <boost/shared_ptr.hpp> + +#include <Swiften/MUC/MUCBookmark.h> +#include <Swift/Controllers/UIInterfaces/ChatListWindow.h> + +#include <Swift/QtUI/ChatList/ChatListItem.h> + +namespace Swift { + class ChatListRecentItem : public ChatListItem { + public: + enum RecentItemRoles { + DetailTextRole = Qt::UserRole, + AvatarRole = Qt::UserRole + 1, + PresenceIconRole = Qt::UserRole + 2/*, + StatusShowTypeRole = Qt::UserRole + 3*/ + }; + ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent); + const ChatListWindow::Chat& getChat() const; + QVariant data(int role) const; + private: + QIcon getPresenceIcon() const; + ChatListWindow::Chat chat_; + }; +} diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp index b532cdb..e5c63f6 100644 --- a/Swift/QtUI/ChatList/QtChatListWindow.cpp +++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -10,9 +10,11 @@ #include <QContextMenuEvent> #include "Swift/QtUI/ChatList/ChatListMUCItem.h" +#include "Swift/QtUI/ChatList/ChatListRecentItem.h" #include "Swift/QtUI/QtAddBookmarkWindow.h" #include "Swift/QtUI/QtEditBookmarkWindow.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" #include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h" #include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h" #include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h" @@ -68,19 +70,21 @@ void QtChatListWindow::setupContextMenus() { } void QtChatListWindow::handleItemActivated(const QModelIndex& index) { - if (!bookmarksEnabled_) { - return; - } ChatListItem* item = model_->getItemForIndex(index); - ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(item); - if (mucItem) { - boost::shared_ptr<UIEvent> event(new JoinMUCUIEvent(mucItem->getBookmark().getRoom(), mucItem->getBookmark().getNick())); - eventStream_->send(event); + if (ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(item)) { + if (bookmarksEnabled_) { + onMUCBookmarkActivated(mucItem->getBookmark()); + } + } + else if (ChatListRecentItem* recentItem = dynamic_cast<ChatListRecentItem*>(item)) { + if (!recentItem->getChat().isMUC || bookmarksEnabled_) { + onRecentActivated(recentItem->getChat()); + } } } -void QtChatListWindow::clear() { - model_->clear(); +void QtChatListWindow::clearBookmarks() { + model_->clearBookmarks(); } void QtChatListWindow::addMUCBookmark(const MUCBookmark& bookmark) { @@ -91,6 +95,14 @@ void QtChatListWindow::removeMUCBookmark(const MUCBookmark& bookmark) { model_->removeMUCBookmark(bookmark); } +void QtChatListWindow::setRecents(const std::list<ChatListWindow::Chat>& recents) { + model_->setRecents(recents); +} + +void QtChatListWindow::setUnreadCount(int unread) { + emit onCountUpdated(unread); +} + void QtChatListWindow::handleRemoveBookmark() { ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_); if (!mucItem) return; @@ -111,9 +123,6 @@ void QtChatListWindow::handleEditBookmark() { void QtChatListWindow::contextMenuEvent(QContextMenuEvent* event) { - if (!bookmarksEnabled_) { - return; - } QModelIndex index = indexAt(event->pos()); ChatListItem* baseItem = index.isValid() ? static_cast<ChatListItem*>(index.internalPointer()) : NULL; contextMenuItem_ = baseItem; @@ -123,8 +132,20 @@ void QtChatListWindow::contextMenuEvent(QContextMenuEvent* event) { } ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(baseItem); if (mucItem) { + if (!bookmarksEnabled_) { + return; + } mucMenu_->exec(QCursor::pos()); } + else { + QMenu menu; + QAction* clearRecents = menu.addAction(tr("Clear recents")); + menu.addAction(clearRecents); + QAction* result = menu.exec(event->globalPos()); + if (result == clearRecents) { + onClearRecentsRequested(); + } + } } } diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h index 3a3e95f..8775c3e 100644 --- a/Swift/QtUI/ChatList/QtChatListWindow.h +++ b/Swift/QtUI/ChatList/QtChatListWindow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -23,7 +23,12 @@ namespace Swift { void addMUCBookmark(const MUCBookmark& bookmark); void removeMUCBookmark(const MUCBookmark& bookmark); void setBookmarksEnabled(bool enabled); - void clear(); + void setRecents(const std::list<ChatListWindow::Chat>& recents); + void setUnreadCount(int unread); + void clearBookmarks(); + + signals: + void onCountUpdated(int count); private slots: void handleItemActivated(const QModelIndex&); void handleAddBookmark(); diff --git a/Swift/QtUI/ChatSnippet.h b/Swift/QtUI/ChatSnippet.h index 3aa5fcc..0d864c1 100644 --- a/Swift/QtUI/ChatSnippet.h +++ b/Swift/QtUI/ChatSnippet.h @@ -17,16 +17,16 @@ namespace Swift { public: ChatSnippet(bool appendToPrevious); virtual ~ChatSnippet(); - + virtual const QString& getContent() const = 0; virtual QString getContinuationElementID() const { return ""; } - boost::shared_ptr<ChatSnippet> getContinuationFallbackSnippet() {return continuationFallback_;} + boost::shared_ptr<ChatSnippet> getContinuationFallbackSnippet() const {return continuationFallback_;} bool getAppendToPrevious() const { return appendToPrevious_; } - + static QString escape(const QString& original) { QString result(original); result.replace("%message%", "%message%"); @@ -37,11 +37,12 @@ namespace Swift { return result; } + static QString timeToEscapedString(const QDateTime& time); + protected: void setContinuationFallbackSnippet(boost::shared_ptr<ChatSnippet> continuationFallback) { continuationFallback_ = continuationFallback; } - static QString timeToEscapedString(const QDateTime& time); private: bool appendToPrevious_; boost::shared_ptr<ChatSnippet> continuationFallback_; diff --git a/Swift/QtUI/EventViewer/QtEventWindow.h b/Swift/QtUI/EventViewer/QtEventWindow.h index 03f009b..a20e5ab 100644 --- a/Swift/QtUI/EventViewer/QtEventWindow.h +++ b/Swift/QtUI/EventViewer/QtEventWindow.h @@ -6,7 +6,7 @@ #pragma once -#include "boost/shared_ptr.hpp" +#include <boost/shared_ptr.hpp> #include <QTreeView> diff --git a/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h index 920aaae..a9eb74d 100644 --- a/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h +++ b/Swift/QtUI/MUCSearch/MUCSearchRoomItem.h @@ -15,7 +15,7 @@ namespace Swift { MUCSearchRoomItem(const QString& node, MUCSearchServiceItem* parent); MUCSearchServiceItem* getParent(); QVariant data(int role); - QString getNode() {return node_;} + QString getNode() const {return node_;} private: MUCSearchServiceItem* parent_; QString node_; diff --git a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h index 411727d..2a28922 100644 --- a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h +++ b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h @@ -24,7 +24,7 @@ namespace Swift { default: return QVariant(); } } - QString getHost() {return jidString_;} + QString getHost() const {return jidString_;} private: QList<MUCSearchItem*> rooms_; QString jidString_; diff --git a/Swift/QtUI/QtAdHocCommandWindow.cpp b/Swift/QtUI/QtAdHocCommandWindow.cpp new file mode 100644 index 0000000..a3bb077 --- /dev/null +++ b/Swift/QtUI/QtAdHocCommandWindow.cpp @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/QtUI/QtAdHocCommandWindow.h> + +#include <boost/bind.hpp> +#include <QBoxLayout> +#include <Swift/QtUI/QtFormWidget.h> +#include <Swiften/Elements/Command.h> + +namespace Swift { +QtAdHocCommandWindow::QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) : command_(command) { + + formWidget_ = NULL; + + setAttribute(Qt::WA_DeleteOnClose); + command->onNextStageReceived.connect(boost::bind(&QtAdHocCommandWindow::handleNextStageReceived, this, _1)); + command->onError.connect(boost::bind(&QtAdHocCommandWindow::handleError, this, _1)); + command->start(); + + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, this); + layout->setContentsMargins(0,0,0,0); + layout->setSpacing(2); + label_ = new QLabel(this); + layout->addWidget(label_); + QWidget* formContainer = new QWidget(this); + layout->addWidget(formContainer); + formLayout_ = new QBoxLayout(QBoxLayout::TopToBottom, formContainer); + QWidget* buttonsWidget = new QWidget(this); + layout->addWidget(buttonsWidget); + + QBoxLayout* buttonsLayout = new QBoxLayout(QBoxLayout::LeftToRight, buttonsWidget); + cancelButton_ = new QPushButton(tr("Cancel"), buttonsWidget); + buttonsLayout->addWidget(cancelButton_); + connect(cancelButton_, SIGNAL(clicked()), this, SLOT(handleCancelClicked())); + backButton_ = new QPushButton(tr("Back"), buttonsWidget); + buttonsLayout->addWidget(backButton_); + connect(backButton_, SIGNAL(clicked()), this, SLOT(handlePrevClicked())); + nextButton_ = new QPushButton(tr("Next"), buttonsWidget); + buttonsLayout->addWidget(nextButton_); + connect(nextButton_, SIGNAL(clicked()), this, SLOT(handleNextClicked())); + completeButton_ = new QPushButton(tr("Complete"), buttonsWidget); + buttonsLayout->addWidget(completeButton_); + connect(completeButton_, SIGNAL(clicked()), this, SLOT(handleCompleteClicked())); + nextButton_->setEnabled(false); + backButton_->setEnabled(false); + completeButton_->setEnabled(false); + actions_[Command::Next] = nextButton_; + actions_[Command::Prev] = backButton_; + actions_[Command::Complete] = completeButton_; + actions_[Command::Cancel] = cancelButton_; + show(); +} + +QtAdHocCommandWindow::~QtAdHocCommandWindow() { + +} + +void QtAdHocCommandWindow::handleCancelClicked() { + command_->cancel(); +} + +void QtAdHocCommandWindow::handlePrevClicked() { + command_->goBack(); +} + +void QtAdHocCommandWindow::handleNextClicked() { + command_->goNext(formWidget_ ? formWidget_->getCompletedForm() : Form::ref()); +} + +void QtAdHocCommandWindow::handleCompleteClicked() { + command_->complete(formWidget_ ? formWidget_->getCompletedForm() : Form::ref()); +} + +void QtAdHocCommandWindow::handleNextStageReceived(Command::ref command) { + if (command->getForm()) { + setForm(command->getForm()); + } else { + setNoForm(); + } + QString notes; + foreach (Command::Note note, command->getNotes()) { + if (!notes.isEmpty()) { + notes += "\n"; + QString qNote(note.note.c_str()); + switch (note.type) { + case Command::Note::Error: notes += tr("Error: %1").arg(qNote); break; + case Command::Note::Warn: notes += tr("Warning: %1").arg(qNote); break; + case Command::Note::Info: notes += qNote; break; + } + } + } + label_->setText(notes); + setAvailableActions(command); +} + +void QtAdHocCommandWindow::handleError(ErrorPayload::ref /*error*/) { + nextButton_->setEnabled(false); + backButton_->setEnabled(false); + completeButton_->setEnabled(false); + label_->setText(tr("Error executing command")); +} + +void QtAdHocCommandWindow::setForm(Form::ref form) { + delete formWidget_; + formWidget_ = new QtFormWidget(form, this); + formLayout_->addWidget(formWidget_); +} + +void QtAdHocCommandWindow::setNoForm() { + delete formWidget_; +} + +typedef std::pair<Command::Action, QPushButton*> ActionButton; + +void QtAdHocCommandWindow::setAvailableActions(Command::ref /*commandResult*/) { + foreach (ActionButton pair, actions_) { + OutgoingAdHocCommandSession::ActionState state = command_->getActionState(pair.first); + if (state & OutgoingAdHocCommandSession::Present) { + pair.second->show(); + } + else { + pair.second->hide(); + } + if (state & OutgoingAdHocCommandSession::Enabled) { + pair.second->setEnabled(true); + } + else { + pair.second->setEnabled(false); + } + } +} + +} diff --git a/Swift/QtUI/QtAdHocCommandWindow.h b/Swift/QtUI/QtAdHocCommandWindow.h new file mode 100644 index 0000000..adeb3e6 --- /dev/null +++ b/Swift/QtUI/QtAdHocCommandWindow.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <QWidget> +#include <QPushButton> +#include <QLabel> + +#include <Swift/Controllers/UIInterfaces/AdHocCommandWindow.h> +#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h> + +class QBoxLayout; + +namespace Swift { + class QtFormWidget; + class QtAdHocCommandWindow : public QWidget, public AdHocCommandWindow { + Q_OBJECT + public: + QtAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command); + virtual ~QtAdHocCommandWindow(); + private: + void handleNextStageReceived(Command::ref command); + void handleError(ErrorPayload::ref error); + void setForm(Form::ref); + void setNoForm(); + void setAvailableActions(Command::ref commandResult); + private slots: + void handleCancelClicked(); + void handlePrevClicked(); + void handleNextClicked(); + void handleCompleteClicked(); + private: + boost::shared_ptr<OutgoingAdHocCommandSession> command_; + QtFormWidget* formWidget_; + QBoxLayout* formLayout_; + Form::ref form_; + QLabel* label_; + QPushButton* backButton_; + QPushButton* nextButton_; + QPushButton* completeButton_; + QPushButton* cancelButton_; + std::map<Command::Action, QPushButton*> actions_; + }; +} diff --git a/Swift/QtUI/QtAvatarWidget.cpp b/Swift/QtUI/QtAvatarWidget.cpp index 3e3aa69..1efb787 100644 --- a/Swift/QtUI/QtAvatarWidget.cpp +++ b/Swift/QtUI/QtAvatarWidget.cpp @@ -47,8 +47,8 @@ void QtAvatarWidget::setAvatar(const ByteArray& data, const std::string& type) { this->type = type; QImage image; - if (!data.isEmpty()) { - image.loadFromData(reinterpret_cast<const uchar*>(data.getData()), data.getSize()); + if (!data.empty()) { + image.loadFromData(reinterpret_cast<const uchar*>(vecptr(data)), data.size()); } if (image.isNull()) { @@ -81,10 +81,10 @@ void QtAvatarWidget::mousePressEvent(QMouseEvent* event) { QString fileName = QFileDialog::getOpenFileName(this, tr("Select picture"), "", tr("Image Files (*.png *.jpg *.gif)")); if (!fileName.isEmpty()) { ByteArray data; - data.readFromFile(Q2PSTRING(fileName)); + readByteArrayFromFile(data, Q2PSTRING(fileName)); QBuffer buffer; - buffer.setData(reinterpret_cast<const char*>(data.getData()), data.getSize()); + buffer.setData(reinterpret_cast<const char*>(vecptr(data)), data.size()); buffer.open(QIODevice::ReadOnly); QString type = QImageReader::imageFormat(&buffer).toLower(); if (!type.isEmpty()) { diff --git a/Swift/QtUI/QtBookmarkDetailWindow.ui b/Swift/QtUI/QtBookmarkDetailWindow.ui index a77ac76..4a37b2f 100644 --- a/Swift/QtUI/QtBookmarkDetailWindow.ui +++ b/Swift/QtUI/QtBookmarkDetailWindow.ui @@ -90,7 +90,7 @@ <item row="4" column="1"> <widget class="QCheckBox" name="autojoin_"> <property name="text"> - <string>Join automatically</string> + <string>Enter automatically</string> </property> <property name="checked"> <bool>true</bool> diff --git a/Swift/QtUI/QtChatTabs.cpp b/Swift/QtUI/QtChatTabs.cpp index 25c7ca2..249080b 100644 --- a/Swift/QtUI/QtChatTabs.cpp +++ b/Swift/QtUI/QtChatTabs.cpp @@ -7,6 +7,10 @@ #include "QtChatTabs.h" #include <algorithm> +#include <vector> + +#include <Swift/Controllers/ChatMessageSummarizer.h> +#include <Swift/QtUI/QtSwiftUtil.h> #include <QCloseEvent> #include <QDesktopWidget> @@ -236,16 +240,18 @@ void QtChatTabs::handleTabTitleUpdated(QWidget* widget) { default : tabTextColor = QColor(); } tabs_->tabBar()->setTabTextColor(index, tabTextColor); - int unread = 0; + + std::vector<std::pair<std::string, int> > unreads; for (int i = 0; i < tabs_->count(); i++) { QtTabbable* tab = qobject_cast<QtTabbable*>(tabs_->widget(i)); if (tab) { - unread += tab->getCount(); + unreads.push_back(std::pair<std::string, int>(Q2PSTRING(tab->windowTitle()), tab->getCount())); } } - QtTabbable* current = qobject_cast<QtTabbable*>(tabs_->currentWidget()); - setWindowTitle(unread > 0 ? QString("(%1) %2").arg(unread).arg(current->windowTitle()) : current->windowTitle()); + std::string current(Q2PSTRING(qobject_cast<QtTabbable*>(tabs_->currentWidget())->windowTitle())); + ChatMessageSummarizer summary; + setWindowTitle(summary.getSummary(current, unreads).c_str()); } void QtChatTabs::flash() { diff --git a/Swift/QtUI/QtChatTheme.cpp b/Swift/QtUI/QtChatTheme.cpp index afcf665..1d7a970 100644 --- a/Swift/QtUI/QtChatTheme.cpp +++ b/Swift/QtUI/QtChatTheme.cpp @@ -60,7 +60,7 @@ QtChatTheme::QtChatTheme(const QString& themePath) : qrc_(themePath.isEmpty()), } -QString QtChatTheme::getBase() { +QString QtChatTheme::getBase() const { return qrc_ ? "qrc" + themePath_ : "file://" + themePath_; } diff --git a/Swift/QtUI/QtChatTheme.h b/Swift/QtUI/QtChatTheme.h index 199c66d..c6b02a0 100644 --- a/Swift/QtUI/QtChatTheme.h +++ b/Swift/QtUI/QtChatTheme.h @@ -13,23 +13,23 @@ namespace Swift { class QtChatTheme { public: QtChatTheme(const QString& themePath); - QString getHeader() {return fileContents_[Header];}; - QString getFooter() {return fileContents_[Footer];}; - QString getContent() {return fileContents_[Content];}; - QString getStatus() {return fileContents_[Status];}; - QString getTopic() {return fileContents_[Topic];}; - QString getFileTransferRequest() {return fileContents_[FileTransferRequest];}; - QString getIncomingContent() {return fileContents_[IncomingContent];}; - QString getIncomingNextContent() {return fileContents_[IncomingNextContent];}; - QString getIncomingContext() {return fileContents_[IncomingContext];}; - QString getIncomingNextContext() {return fileContents_[IncomingNextContext];}; - QString getOutgoingContent() {return fileContents_[OutgoingContent];}; - QString getOutgoingNextContent() {return fileContents_[OutgoingNextContent];}; - QString getOutgoingContext() {return fileContents_[OutgoingContext];}; - QString getOutgoingNextContext() {return fileContents_[OutgoingNextContext];}; - QString getTemplate() {return fileContents_[Template];} - QString getMainCSS() {return fileContents_[MainCSS];} - QString getBase(); + QString getHeader() const {return fileContents_[Header];}; + QString getFooter() const {return fileContents_[Footer];}; + QString getContent() const {return fileContents_[Content];}; + QString getStatus() const {return fileContents_[Status];}; + QString getTopic() const {return fileContents_[Topic];}; + QString getFileTransferRequest() const {return fileContents_[FileTransferRequest];}; + QString getIncomingContent() const {return fileContents_[IncomingContent];}; + QString getIncomingNextContent() const {return fileContents_[IncomingNextContent];}; + QString getIncomingContext() const {return fileContents_[IncomingContext];}; + QString getIncomingNextContext() const {return fileContents_[IncomingNextContext];}; + QString getOutgoingContent() const {return fileContents_[OutgoingContent];}; + QString getOutgoingNextContent() const {return fileContents_[OutgoingNextContent];}; + QString getOutgoingContext() const {return fileContents_[OutgoingContext];}; + QString getOutgoingNextContext() const {return fileContents_[OutgoingNextContext];}; + QString getTemplate() const {return fileContents_[Template];} + QString getMainCSS() const {return fileContents_[MainCSS];} + QString getBase() const; private: enum files {Header = 0, Footer, Content, Status, Topic, FileTransferRequest, IncomingContent, IncomingNextContent, IncomingContext, IncomingNextContext, OutgoingContent, OutgoingNextContent, OutgoingContext, OutgoingNextContext, Template, MainCSS, TemplateDefault, EndMarker}; diff --git a/Swift/QtUI/QtChatView.cpp b/Swift/QtUI/QtChatView.cpp index 521b072..7bb5818 100644 --- a/Swift/QtUI/QtChatView.cpp +++ b/Swift/QtUI/QtChatView.cpp @@ -18,13 +18,16 @@ #include <QMessageBox> #include <QApplication> +#include <Swiften/Base/Log.h> + #include "QtWebView.h" #include "QtChatTheme.h" +#include "QtSwiftUtil.h" namespace Swift { -QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent) { +QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent), fontSizeSteps_(0) { theme_ = theme; QVBoxLayout* mainLayout = new QVBoxLayout(this); @@ -35,6 +38,8 @@ QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent) { connect(webView_, SIGNAL(loadFinished(bool)), SLOT(handleViewLoadFinished(bool))); connect(webView_, SIGNAL(gotFocus()), SIGNAL(gotFocus())); connect(webView_, SIGNAL(clearRequested()), SLOT(handleClearRequested())); + connect(webView_, SIGNAL(fontGrowRequested()), SLOT(increaseFontSize())); + connect(webView_, SIGNAL(fontShrinkRequested()), SLOT(decreaseFontSize())); #ifdef Q_WS_X11 /* To give a border on Linux, where it looks bad without */ QStackedWidget* stack = new QStackedWidget(this); @@ -46,8 +51,15 @@ QtChatView::QtChatView(QtChatTheme* theme, QWidget* parent) : QWidget(parent) { mainLayout->addWidget(webView_); #endif +#ifdef SWIFT_EXPERIMENTAL_FT + setAcceptDrops(true); +#endif + webPage_ = new QWebPage(this); webPage_->setLinkDelegationPolicy(QWebPage::DelegateAllLinks); +#ifdef SWIFT_EXPERIMENTAL_FT + webPage_->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); +#endif webView_->setPage(webPage_); connect(webPage_, SIGNAL(selectionChanged()), SLOT(copySelectionToClipboard())); @@ -77,13 +89,14 @@ void QtChatView::addMessage(boost::shared_ptr<ChatSnippet> snippet) { if (viewReady_) { addToDOM(snippet); } else { - queuedSnippets_.append(snippet); + /* If this asserts, the previous queuing code was necessary and should be reinstated */ + assert(false); } } QWebElement QtChatView::snippetToDOM(boost::shared_ptr<ChatSnippet> snippet) { QWebElement newElement = newInsertPoint_.clone(); - newElement.setInnerXml(snippet->getContent()); /* FIXME: Outer, surely? */ + newElement.setInnerXml(snippet->getContent()); Q_ASSERT(!newElement.isNull()); return newElement; } @@ -103,12 +116,31 @@ void QtChatView::addToDOM(boost::shared_ptr<ChatSnippet> snippet) { newInsertPoint_.prependOutside(newElement); } lastElement_ = newElement; - //qApp->processEvents(); + if (fontSizeSteps_ != 0) { + double size = 1.0 + 0.2 * fontSizeSteps_; + QString sizeString(QString().setNum(size, 'g', 3) + "em"); + const QWebElementCollection spans = lastElement_.findAll("span"); + foreach (QWebElement span, spans) { + span.setStyleProperty("font-size", sizeString); + } + } +} + +void QtChatView::addLastSeenLine() { + if (lineSeparator_.isNull()) { + lineSeparator_ = newInsertPoint_.clone(); + lineSeparator_.setInnerXml(QString("<hr/>")); + newInsertPoint_.prependOutside(lineSeparator_); + } + else { + QWebElement lineSeparatorC = lineSeparator_.clone(); + lineSeparatorC.removeFromDocument(); + } + newInsertPoint_.prependOutside(lineSeparator_); } void QtChatView::replaceLastMessage(const QString& newMessage) { assert(viewReady_); - /* FIXME: must be queued? */ rememberScrolledToBottom(); assert(!lastElement_.isNull()); QWebElement replace = lastElement_.findFirst("span.swift_message"); @@ -125,6 +157,29 @@ void QtChatView::replaceLastMessage(const QString& newMessage, const QString& no replace.setInnerXml(ChatSnippet::escape(note)); } +QString QtChatView::getLastSentMessage() { + return lastElement_.toPlainText(); +} + +void QtChatView::addToJSEnvironment(const QString& name, QObject* obj) { + webView_->page()->currentFrame()->addToJavaScriptWindowObject(name, obj); +} + +void QtChatView::replaceMessage(const QString& newMessage, const QString& id, const QDateTime& editTime) { + rememberScrolledToBottom(); + QWebElement message = document_.findFirst("#" + id); + if (!message.isNull()) { + QWebElement replaceContent = message.findFirst("span.swift_message"); + assert(!replaceContent.isNull()); + QString old = replaceContent.toOuterXml(); + replaceContent.setInnerXml(ChatSnippet::escape(newMessage)); + QWebElement replaceTime = message.findFirst("span.swift_time"); + assert(!replaceTime.isNull()); + old = replaceTime.toOuterXml(); + replaceTime.setInnerXml(ChatSnippet::escape(tr("%1 edited").arg(ChatSnippet::timeToEscapedString(editTime)))); + } +} + void QtChatView::copySelectionToClipboard() { if (!webPage_->selectedText().isEmpty()) { webPage_->triggerAction(QWebPage::Copy); @@ -160,17 +215,35 @@ void QtChatView::handleLinkClicked(const QUrl& url) { QDesktopServices::openUrl(url); } -void QtChatView::addQueuedSnippets() { - for (int i = 0; i < queuedSnippets_.count(); i++) { - addToDOM(queuedSnippets_[i]); - } - queuedSnippets_.clear(); -} - void QtChatView::handleViewLoadFinished(bool ok) { Q_ASSERT(ok); viewReady_ = true; - addQueuedSnippets(); +} + +void QtChatView::increaseFontSize(int numSteps) { + //qDebug() << "Increasing"; + fontSizeSteps_ += numSteps; + emit fontResized(fontSizeSteps_); +} + +void QtChatView::decreaseFontSize() { + fontSizeSteps_--; + if (fontSizeSteps_ < 0) { + fontSizeSteps_ = 0; + } + emit fontResized(fontSizeSteps_); +} + +void QtChatView::resizeFont(int fontSizeSteps) { + fontSizeSteps_ = fontSizeSteps; + double size = 1.0 + 0.2 * fontSizeSteps_; + QString sizeString(QString().setNum(size, 'g', 3) + "em"); + //qDebug() << "Setting to " << sizeString; + const QWebElementCollection spans = document_.findAll("span"); + foreach (QWebElement span, spans) { + span.setStyleProperty("font-size", sizeString); + } + webView_->setFontSizeIsMinimal(size == 1.0); } void QtChatView::resetView() { @@ -204,4 +277,69 @@ void QtChatView::resetView() { connect(webPage_->mainFrame(), SIGNAL(contentsSizeChanged(const QSize&)), this, SLOT(handleFrameSizeChanged()), Qt::UniqueConnection); } +QWebElement findDivElementWithID(QWebElement document, QString id) { + QWebElementCollection divs = document.findAll("div"); + foreach(QWebElement div, divs) { + if (div.attribute("id") == id) { + return div; + } + } + return QWebElement(); +} + +void QtChatView::setFileTransferProgress(QString id, const int percentageDone) { + QWebElement ftElement = findDivElementWithID(document_, id); + if (ftElement.isNull()) { + SWIFT_LOG(debug) << "Tried to access FT UI via invalid id!" << std::endl; + return; + } + QWebElement progressBar = ftElement.findFirst("div.progressbar"); + progressBar.setStyleProperty("width", QString::number(percentageDone) + "%"); + + QWebElement progressBarValue = ftElement.findFirst("div.progressbar-value"); + progressBarValue.setInnerXml(QString::number(percentageDone) + " %"); +} + +void QtChatView::setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& /* msg */) { + QWebElement ftElement = findDivElementWithID(document_, id); + if (ftElement.isNull()) { + SWIFT_LOG(debug) << "Tried to access FT UI via invalid id! id = " << Q2PSTRING(id) << std::endl; + return; + } + + QString newInnerHTML = ""; + if (state == ChatWindow::WaitingForAccept) { + newInnerHTML = "Waiting for other side to accept the transfer.<br/>" + "<input id=\"discard\" type=\"submit\" value=\"Cancel\" onclick=\"filetransfer.cancel(\'" + id + "\');\">"; + } + if (state == ChatWindow::Negotiating) { + // replace with text "Negotiaging" + Cancel button + newInnerHTML = "Negotiating...<br/>" + "<input id=\"discard\" type=\"submit\" value=\"Cancel\" onclick=\"filetransfer.cancel(\'" + id + "\');\">"; + } + else if (state == ChatWindow::Transferring) { + // progress bar + Cancel Button + newInnerHTML = "<div style=\"position: relative; width: 90%; height: 20px; border: 2px solid grey; -webkit-border-radius: 10px;\">" + "<div class=\"progressbar\" style=\"width: 0%; height: 100%; background: #AAA; -webkit-border-radius: 6px;\">" + "<div class=\"progressbar-value\" style=\"position: absolute; top: 0px; left: 0px; width: 100%; text-align: center; padding-top: 2px;\">" + "0%" + "</div>" + "</div>" + "</div>" + "<input id=\"discard\" type=\"submit\" value=\"Cancel\" onclick=\"filetransfer.cancel(\'" + id + "\');\">"; + } + else if (state == ChatWindow::Canceled) { + newInnerHTML = "Transfer has been canceled!"; + } + else if (state == ChatWindow::Finished) { + // text "Successful transfer" + newInnerHTML = "Transfer completed successfully."; + } + else if (state == ChatWindow::FTFailed) { + newInnerHTML = "Transfer failed."; + } + + ftElement.setInnerXml(newInnerHTML); +} + } diff --git a/Swift/QtUI/QtChatView.h b/Swift/QtUI/QtChatView.h index 58b33df..cf47029 100644 --- a/Swift/QtUI/QtChatView.h +++ b/Swift/QtUI/QtChatView.h @@ -16,6 +16,8 @@ #include "ChatSnippet.h" +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> + class QWebPage; class QUrl; @@ -26,15 +28,21 @@ namespace Swift { Q_OBJECT public: QtChatView(QtChatTheme* theme, QWidget* parent); - void addMessage(boost::shared_ptr<ChatSnippet> snippet); + void addLastSeenLine(); void replaceLastMessage(const QString& newMessage); void replaceLastMessage(const QString& newMessage, const QString& note); + void replaceMessage(const QString& newMessage, const QString& id, const QDateTime& time); void rememberScrolledToBottom(); void setAckXML(const QString& id, const QString& xml); + QString getLastSentMessage(); + void addToJSEnvironment(const QString&, QObject*); + void setFileTransferProgress(QString id, const int percentageDone); + void setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& msg); signals: void gotFocus(); + void fontResized(int); public slots: void copySelectionToClipboard(); @@ -42,6 +50,9 @@ namespace Swift { void handleLinkClicked(const QUrl&); void handleKeyPressEvent(QKeyEvent* event); void resetView(); + void increaseFontSize(int numSteps = 1); + void decreaseFontSize(); + void resizeFont(int fontSizeSteps); private slots: void handleViewLoadFinished(bool); @@ -51,7 +62,6 @@ namespace Swift { private: void headerEncode(); void messageEncode(); - void addQueuedSnippets(); void addToDOM(boost::shared_ptr<ChatSnippet> snippet); QWebElement snippetToDOM(boost::shared_ptr<ChatSnippet> snippet); @@ -59,10 +69,10 @@ namespace Swift { bool isAtBottom_; QtWebView* webView_; QWebPage* webPage_; - QList<boost::shared_ptr<ChatSnippet> > queuedSnippets_; - + int fontSizeSteps_; QtChatTheme* theme_; QWebElement newInsertPoint_; + QWebElement lineSeparator_; QWebElement lastElement_; QWebElement document_; }; diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 1a909fd..07ff47e 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,16 +7,28 @@ #include "QtChatWindow.h" #include "QtSwiftUtil.h" #include "Swift/Controllers/Roster/Roster.h" -#include "Roster/QtTreeWidget.h" +#include "Swift/Controllers/Roster/RosterItem.h" +#include "Swift/Controllers/Roster/ContactRosterItem.h" +#include "Roster/QtOccupantListWidget.h" #include "SwifTools/Linkify.h" #include "QtChatView.h" #include "MessageSnippet.h" #include "SystemMessageSnippet.h" #include "QtTextEdit.h" +#include "QtSettingsProvider.h" #include "QtScaledAvatarCache.h" #include "SwifTools/TabComplete.h" +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIEvents/SendFileUIEvent.h> +#include "QtFileTransferJSBridge.h" +#include <boost/cstdint.hpp> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> + +#include <QLabel> +#include <QInputDialog> #include <QApplication> #include <QBoxLayout> #include <QCloseEvent> @@ -28,32 +40,74 @@ #include <QTextEdit> #include <QTime> #include <QUrl> +#include <QPushButton> +#include <QFileDialog> +#include <QMenu> + +#include <QDebug> namespace Swift { -QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), previousMessageWasPresence_(false), eventStream_(eventStream) { +QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), previousMessageWasPresence_(false), previousMessageWasFileTransfer_(false), eventStream_(eventStream) { unreadCount_ = 0; inputEnabled_ = true; completer_ = NULL; theme_ = theme; + isCorrection_ = false; + correctionEnabled_ = Maybe; updateTitleWithUnreadCount(); + QtSettingsProvider settings; + +#ifdef SWIFT_EXPERIMENTAL_FT + setAcceptDrops(true); +#endif + + alertStyleSheet_ = "background: rgb(255, 255, 153); color: black"; QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this); layout->setContentsMargins(0,0,0,0); layout->setSpacing(2); - - - QSplitter *logRosterSplitter = new QSplitter(this); - logRosterSplitter->setAutoFillBackground(true); - layout->addWidget(logRosterSplitter); + alertWidget_ = new QWidget(this); + QHBoxLayout* alertLayout = new QHBoxLayout(alertWidget_); + layout->addWidget(alertWidget_); + alertLabel_ = new QLabel(this); + alertLayout->addWidget(alertLabel_); + alertButton_ = new QPushButton(this); + connect (alertButton_, SIGNAL(clicked()), this, SLOT(handleAlertButtonClicked())); + alertLayout->addWidget(alertButton_); + QPalette palette = alertWidget_->palette(); + palette.setColor(QPalette::Window, QColor(Qt::yellow)); + palette.setColor(QPalette::WindowText, QColor(Qt::black)); + alertWidget_->setStyleSheet(alertStyleSheet_); + alertLabel_->setStyleSheet(alertStyleSheet_); + alertWidget_->hide(); + + QBoxLayout* subjectLayout = new QBoxLayout(QBoxLayout::LeftToRight); + subject_ = new QLineEdit(this); + subjectLayout->addWidget(subject_); + setSubject(""); + subject_->setReadOnly(true); + + actionButton_ = new QPushButton(tr("Actions"), this); + connect(actionButton_, SIGNAL(clicked()), this, SLOT(handleActionButtonClicked())); + subjectLayout->addWidget(actionButton_); + + subject_->hide(); + actionButton_->hide(); + + layout->addLayout(subjectLayout); + + logRosterSplitter_ = new QSplitter(this); + logRosterSplitter_->setAutoFillBackground(true); + layout->addWidget(logRosterSplitter_); messageLog_ = new QtChatView(theme, this); - logRosterSplitter->addWidget(messageLog_); + logRosterSplitter_->addWidget(messageLog_); - treeWidget_ = new QtTreeWidget(eventStream_); - treeWidget_->setEditable(false); + treeWidget_ = new QtOccupantListWidget(eventStream_, this); treeWidget_->hide(); - logRosterSplitter->addWidget(treeWidget_); - logRosterSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + logRosterSplitter_->addWidget(treeWidget_); + logRosterSplitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + connect(logRosterSplitter_, SIGNAL(splitterMoved(int, int)), this, SLOT(handleSplitterMoved(int, int))); QWidget* midBar = new QWidget(this); layout->addWidget(midBar); @@ -69,10 +123,17 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt labelsWidget_->setSizeAdjustPolicy(QComboBox::AdjustToContents); midBarLayout->addWidget(labelsWidget_,0); + QHBoxLayout* inputBarLayout = new QHBoxLayout(); + inputBarLayout->setContentsMargins(0,0,0,0); + inputBarLayout->setSpacing(2); input_ = new QtTextEdit(this); input_->setAcceptRichText(false); - layout->addWidget(input_); - + inputBarLayout->addWidget(input_); + correctingLabel_ = new QLabel(tr("Correcting"), this); + inputBarLayout->addWidget(correctingLabel_); + correctingLabel_->hide(); + layout->addLayout(inputBarLayout); + inputClearing_ = false; contactIsTyping_ = false; @@ -80,16 +141,58 @@ QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventSt connect(input_, SIGNAL(returnPressed()), this, SLOT(returnPressed())); connect(input_, SIGNAL(textChanged()), this, SLOT(handleInputChanged())); setFocusProxy(input_); - logRosterSplitter->setFocusProxy(input_); + logRosterSplitter_->setFocusProxy(input_); midBar->setFocusProxy(input_); messageLog_->setFocusProxy(input_); connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)), this, SLOT(qAppFocusChanged(QWidget*, QWidget*))); connect(messageLog_, SIGNAL(gotFocus()), input_, SLOT(setFocus())); resize(400,300); + connect(messageLog_, SIGNAL(fontResized(int)), this, SIGNAL(fontResized(int))); + + treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QtChatWindow::handleOccupantSelectionChanged, this, _1)); + treeWidget_->onOccupantActionSelected.connect(boost::bind(boost::ref(onOccupantActionSelected), _1, _2)); + + fileTransferJS = new QtFileTransferJSBridge(); + messageLog_->addToJSEnvironment("filetransfer", fileTransferJS); + connect(fileTransferJS, SIGNAL(setDescription(QString)), this, SLOT(handleFileTransferSetDescription(QString))); + connect(fileTransferJS, SIGNAL(sendRequest(QString)), this, SLOT(handleFileTransferStart(QString))); + connect(fileTransferJS, SIGNAL(acceptRequest(QString, QString)), this, SLOT(handleFileTransferAccept(QString, QString))); + connect(fileTransferJS, SIGNAL(cancel(QString)), this, SLOT(handleFileTransferCancel(QString))); } QtChatWindow::~QtChatWindow() { + delete fileTransferJS; + if (mucConfigurationWindow) { + delete mucConfigurationWindow.data(); + } +} + +void QtChatWindow::handleOccupantSelectionChanged(RosterItem* item) { + onOccupantSelectionChanged(dynamic_cast<ContactRosterItem*>(item)); +} + +void QtChatWindow::handleFontResized(int fontSizeSteps) { + messageLog_->resizeFont(fontSizeSteps); +} + +void QtChatWindow::handleAlertButtonClicked() { + onAlertButtonClicked(); +} + +void QtChatWindow::setAlert(const std::string& alertText, const std::string& buttonText) { + alertLabel_->setText(alertText.c_str()); + if (buttonText.empty()) { + alertButton_->hide(); + } else { + alertButton_->setText(buttonText.c_str()); + alertButton_->show(); + } + alertWidget_->show(); +} + +void QtChatWindow::cancelAlert() { + alertWidget_->hide(); } void QtChatWindow::setTabComplete(TabComplete* completer) { @@ -118,11 +221,55 @@ void QtChatWindow::handleKeyPressEvent(QKeyEvent* event) { emit requestActiveTab(); } else if (key == Qt::Key_Tab) { tabComplete(); + } else if ((key == Qt::Key_Up) && input_->toPlainText().isEmpty() && !(lastSentMessage_.isEmpty())) { + beginCorrection(); + } else if (key == Qt::Key_Down && isCorrection_ && input_->textCursor().atBlockEnd()) { + cancelCorrection(); + } else if (key == Qt::Key_Down || key == Qt::Key_Up) { + /* Drop */ } else { messageLog_->handleKeyPressEvent(event); } } +void QtChatWindow::beginCorrection() { + if (correctionEnabled_ == ChatWindow::Maybe) { + setAlert(Q2PSTRING(tr("This chat may not support message correction. If you send a correction anyway, it may appear as a duplicate message"))); + } else if (correctionEnabled_ == ChatWindow::No) { + setAlert(Q2PSTRING(tr("This chat does not support message correction. If you send a correction anyway, it will appear as a duplicate message"))); + } + QTextCursor cursor = input_->textCursor(); + cursor.select(QTextCursor::Document); + cursor.beginEditBlock(); + cursor.insertText(QString(lastSentMessage_)); + cursor.endEditBlock(); + isCorrection_ = true; + correctingLabel_->show(); + input_->setStyleSheet(alertStyleSheet_); +} + +void QtChatWindow::cancelCorrection() { + cancelAlert(); + QTextCursor cursor = input_->textCursor(); + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); + isCorrection_ = false; + correctingLabel_->hide(); + input_->setStyleSheet(qApp->styleSheet()); +} + +QByteArray QtChatWindow::getSplitterState() { + return logRosterSplitter_->saveState(); +} + +void QtChatWindow::handleChangeSplitterState(QByteArray state) { + logRosterSplitter_->restoreState(state); +} + +void QtChatWindow::handleSplitterMoved(int, int) { + emit splitterMoved(); +} + void QtChatWindow::tabComplete() { if (!completer_) { return; @@ -150,7 +297,7 @@ void QtChatWindow::tabComplete() { } void QtChatWindow::setRosterModel(Roster* roster) { - treeWidget_->setRosterModel(roster); + treeWidget_->setRosterModel(roster); } void QtChatWindow::setAvailableSecurityLabels(const std::vector<SecurityLabelsCatalog::Item>& labels) { @@ -185,6 +332,10 @@ void QtChatWindow::setSecurityLabelsEnabled(bool enabled) { } } +void QtChatWindow::setCorrectionEnabled(Tristate enabled) { + correctionEnabled_ = enabled; +} + SecurityLabelsCatalog::Item QtChatWindow::getSelectedSecurityLabel() { assert(labelsWidget_->isEnabled()); return availableLabels_[labelsWidget_->currentIndex()]; @@ -197,22 +348,28 @@ void QtChatWindow::closeEvent(QCloseEvent* event) { } void QtChatWindow::convertToMUC() { + setAcceptDrops(false); treeWidget_->show(); + subject_->show(); + actionButton_->show(); } -void QtChatWindow::qAppFocusChanged(QWidget *old, QWidget *now) { - Q_UNUSED(old); - Q_UNUSED(now); +void QtChatWindow::qAppFocusChanged(QWidget* /*old*/, QWidget* /*now*/) { if (isWidgetSelected()) { + lastLineTracker_.setHasFocus(true); input_->setFocus(); onAllMessagesRead(); } - + else { + lastLineTracker_.setHasFocus(false); + } } void QtChatWindow::setInputEnabled(bool enabled) { inputEnabled_ = enabled; -// input_->setEnabled(enabled); + if (!enabled && mucConfigurationWindow) { + delete mucConfigurationWindow.data(); + } } void QtChatWindow::showEvent(QShowEvent* event) { @@ -236,7 +393,7 @@ void QtChatWindow::setContactChatState(ChatState::ChatStateType state) { QtTabbable::AlertType QtChatWindow::getWidgetAlertState() { if (contactIsTyping_) { return ImpendingActivity; - } + } if (unreadCount_ > 0) { return WaitingActivity; } @@ -265,7 +422,6 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri if (isWidgetSelected()) { onAllMessagesRead(); } - QString scaledAvatarPath = QtScaledAvatarCache(32).getScaledAvatarPath(avatarPath.c_str()); QString htmlString; @@ -280,7 +436,13 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri QString styleSpanEnd = style == "" ? "" : "</span>"; htmlString += styleSpanStart + messageHTML + styleSpanEnd; - bool appendToPrevious = !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName))); + bool appendToPrevious = !previousMessageWasFileTransfer_ && !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName))); + if (lastLineTracker_.getShouldMoveLastLine()) { + /* should this be queued? */ + messageLog_->addLastSeenLine(); + /* if the line is added we should break the snippet */ + appendToPrevious = false; + } QString qAvatarPath = scaledAvatarPath.isEmpty() ? "qrc:/icons/avatar.png" : QUrl::fromLocalFile(scaledAvatarPath).toEncoded(); std::string id = id_.generateID(); messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(htmlString, Qt::escape(P2QSTRING(senderName)), B2QDATE(time), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id)))); @@ -289,6 +451,7 @@ std::string QtChatWindow::addMessage(const std::string &message, const std::stri previousSenderName_ = P2QSTRING(senderName); previousMessageWasSystem_ = false; previousMessageWasPresence_ = false; + previousMessageWasFileTransfer_ = false; return id; } @@ -314,6 +477,94 @@ std::string QtChatWindow::addAction(const std::string &message, const std::strin return addMessage(" *" + message + "*", senderName, senderIsSelf, label, avatarPath, "font-style:italic ", time); } +std::string formatSize(const boost::uintmax_t bytes) { + static const char *siPrefix[] = {"k", "M", "G", "T", "P", "E", "Z", "Y", NULL}; + int power = 0; + double engBytes = bytes; + while (engBytes >= 1000) { + ++power; + engBytes = engBytes / 1000.0; + } + return str( boost::format("%.1lf %sB") % engBytes % (power > 0 ? siPrefix[power-1] : "") ); +} + +std::string QtChatWindow::addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes) { + qDebug() << "addFileTransfer"; + std::string ft_id = id_.generateID(); + + std::string htmlString; + if (senderIsSelf) { + // outgoing + htmlString = "Send file: " + filename + " ( " + formatSize(sizeInBytes) + ") </br>" + + "<div id='" + ft_id + "'>" + + "<input id='discard' type='submit' value='Cancel' onclick='filetransfer.cancel(\"" + ft_id + "\");' />" + + "<input id='description' type='submit' value='Set Description' onclick='filetransfer.setDescription(\"" + ft_id + "\");' />" + + "<input id='send' type='submit' value='Send' onclick='filetransfer.sendRequest(\"" + ft_id + "\");' />" + + "</div>"; + } else { + // incoming + htmlString = "Receiving file: " + filename + " ( " + formatSize(sizeInBytes) + ") </br>" + + "<div id='" + ft_id + "'>" + + "<input id='discard' type='submit' value='Cancel' onclick='filetransfer.cancel(\"" + ft_id + "\");' />" + + "<input id='accept' type='submit' value='Accept' onclick='filetransfer.acceptRequest(\"" + ft_id + "\", \"" + filename + "\");' />" + + "</div>"; + } + + //addMessage(message, senderName, senderIsSelf, boost::shared_ptr<SecurityLabel>(), "", boost::posix_time::second_clock::local_time()); + + bool appendToPrevious = !previousMessageWasFileTransfer_ && !previousMessageWasSystem_ && !previousMessageWasPresence_ && ((senderIsSelf && previousMessageWasSelf_) || (!senderIsSelf && !previousMessageWasSelf_ && previousSenderName_ == P2QSTRING(senderName))); + if (lastLineTracker_.getShouldMoveLastLine()) { + /* should this be queued? */ + messageLog_->addLastSeenLine(); + /* if the line is added we should break the snippet */ + appendToPrevious = false; + } + QString qAvatarPath = "qrc:/icons/avatar.png"; + std::string id = id_.generateID(); + messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new MessageSnippet(QString::fromStdString(htmlString), Qt::escape(P2QSTRING(senderName)), B2QDATE(boost::posix_time::second_clock::local_time()), qAvatarPath, senderIsSelf, appendToPrevious, theme_, P2QSTRING(id)))); + + + return ft_id; +} + +void QtChatWindow::setFileTransferProgress(std::string id, const int percentageDone) { + messageLog_->setFileTransferProgress(QString::fromStdString(id), percentageDone); +} + +void QtChatWindow::setFileTransferStatus(std::string id, const FileTransferState state, const std::string& msg) { + messageLog_->setFileTransferStatus(QString::fromStdString(id), state, QString::fromStdString(msg)); +} + +void QtChatWindow::handleFileTransferCancel(QString id) { + qDebug() << "QtChatWindow::handleFileTransferCancel(" << id << ")"; + onFileTransferCancel(Q2PSTRING(id)); +} + +void QtChatWindow::handleFileTransferSetDescription(QString id) { + bool ok = false; + QString text = QInputDialog::getText(this, tr("File transfer description"), + tr("Description:"), QLineEdit::Normal, "", &ok); + if (ok) { + descriptions[id] = text; + } +} + +void QtChatWindow::handleFileTransferStart(QString id) { + qDebug() << "QtChatWindow::handleFileTransferStart(" << id << ")"; + + QString text = descriptions.find(id) == descriptions.end() ? QString() : descriptions[id]; + onFileTransferStart(Q2PSTRING(id), Q2PSTRING(text)); +} + +void QtChatWindow::handleFileTransferAccept(QString id, QString filename) { + qDebug() << "QtChatWindow::handleFileTransferAccept(" << id << ", " << filename << ")"; + + QString path = QFileDialog::getSaveFileName(this, tr("Save File"), filename); + if (!path.isEmpty()) { + onFileTransferAccept(Q2PSTRING(id), Q2PSTRING(path)); + } +} + void QtChatWindow::addErrorMessage(const std::string& errorMessage) { if (isWidgetSelected()) { onAllMessagesRead(); @@ -321,11 +572,12 @@ void QtChatWindow::addErrorMessage(const std::string& errorMessage) { QString errorMessageHTML(Qt::escape(P2QSTRING(errorMessage))); errorMessageHTML.replace("\n","<br/>"); - messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet(QString("<span class=\"error\">" + tr("Couldn't send message: %1") + "</span>").arg(errorMessageHTML), QDateTime::currentDateTime(), false, theme_))); + messageLog_->addMessage(boost::shared_ptr<ChatSnippet>(new SystemMessageSnippet("<span class=\"error\">" + errorMessageHTML + "</span>", QDateTime::currentDateTime(), false, theme_))); previousMessageWasSelf_ = false; previousMessageWasSystem_ = true; previousMessageWasPresence_ = false; + previousMessageWasFileTransfer_ = false; } void QtChatWindow::addSystemMessage(const std::string& message) { @@ -341,6 +593,16 @@ void QtChatWindow::addSystemMessage(const std::string& message) { previousMessageWasSelf_ = false; previousMessageWasSystem_ = true; previousMessageWasPresence_ = false; + previousMessageWasFileTransfer_ = false; +} + +void QtChatWindow::replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time) { + if (!id.empty()) { + QString messageHTML(Qt::escape(P2QSTRING(message))); + messageHTML = P2QSTRING(Linkify::linkify(Q2PSTRING(messageHTML))); + messageHTML.replace("\n","<br/>"); + messageLog_->replaceMessage(messageHTML, P2QSTRING(id), B2QDATE(time)); + } } void QtChatWindow::addPresenceMessage(const std::string& message) { @@ -364,9 +626,11 @@ void QtChatWindow::returnPressed() { return; } messageLog_->scrollToBottom(); - onSendMessageRequest(Q2PSTRING(input_->toPlainText())); + lastSentMessage_ = QString(input_->toPlainText()); + onSendMessageRequest(Q2PSTRING(input_->toPlainText()), isCorrection_); inputClearing_ = true; input_->clear(); + cancelCorrection(); inputClearing_ = false; } @@ -382,7 +646,9 @@ void QtChatWindow::handleInputChanged() { } void QtChatWindow::show() { - QWidget::show(); + if (parentWidget() == NULL) { + QWidget::show(); + } emit windowOpening(); } @@ -399,11 +665,64 @@ void QtChatWindow::resizeEvent(QResizeEvent*) { } void QtChatWindow::moveEvent(QMoveEvent*) { - emit geometryChanged(); + emit geometryChanged(); +} + +void QtChatWindow::dragEnterEvent(QDragEnterEvent *event) { + if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) { + // TODO: check whether contact actually supports file transfer + event->acceptProposedAction(); + } +} + +void QtChatWindow::dropEvent(QDropEvent *event) { + if (event->mimeData()->urls().size() == 1) { + onSendFileRequest(Q2PSTRING(event->mimeData()->urls().at(0).toLocalFile())); + } else { + addSystemMessage("Sending of multiple files at once isn't supported at this time."); + } } void QtChatWindow::replaceLastMessage(const std::string& message) { messageLog_->replaceLastMessage(P2QSTRING(Linkify::linkify(message))); } +void QtChatWindow::setAvailableOccupantActions(const std::vector<OccupantAction>& actions) { + treeWidget_->setAvailableOccupantActions(actions); +} + +void QtChatWindow::setSubject(const std::string& subject) { + //subject_->setVisible(!subject.empty()); + subject_->setText(P2QSTRING(subject)); +} + +void QtChatWindow::handleActionButtonClicked() { + QMenu contextMenu; + QAction* changeSubject = contextMenu.addAction(tr("Change subject")); + QAction* configure = contextMenu.addAction(tr("Configure room")); + QAction* destroy = contextMenu.addAction(tr("Destroy room")); + QAction* result = contextMenu.exec(QCursor::pos()); + if (result == changeSubject) { + bool ok; + QString subject = QInputDialog::getText(this, tr("Change room subject"), tr("New subject:"), QLineEdit::Normal, subject_->text(), &ok); + if (ok) { + onChangeSubjectRequest(Q2PSTRING(subject)); + } + } + else if (result == configure) { + onConfigureRequest(Form::ref()); + } + else if (result == destroy) { + onDestroyRequest(); + } +} + +void QtChatWindow::showRoomConfigurationForm(Form::ref form) { + if (mucConfigurationWindow) { + delete mucConfigurationWindow.data(); + } + mucConfigurationWindow = new QtMUCConfigurationWindow(form); + mucConfigurationWindow->onFormComplete.connect(boost::bind(boost::ref(onConfigureRequest), _1)); +} + } diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index 910019b..b011427 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -1,30 +1,38 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFT_QtChatWindow_H -#define SWIFT_QtChatWindow_H +#pragma once -#include "Swift/Controllers/UIInterfaces/ChatWindow.h" +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/QtUI/QtMUCConfigurationWindow.h> -#include "QtTabbable.h" +#include <QtTabbable.h> -#include "Swiften/Base/IDGenerator.h" +#include <SwifTools/LastLineTracker.h> + +#include <Swiften/Base/IDGenerator.h> + +#include <map> +#include <QPointer> class QTextEdit; class QLineEdit; class QComboBox; +class QLabel; +class QSplitter; +class QPushButton; namespace Swift { class QtChatView; - class QtTreeWidget; - class QtTreeWidgetFactory; + class QtOccupantListWidget; class QtChatTheme; class TreeWidget; class QtTextEdit; class UIEventStream; + class QtFileTransferJSBridge; class QtChatWindow : public QtTabbable, public ChatWindow { Q_OBJECT public: @@ -35,6 +43,12 @@ namespace Swift { void addSystemMessage(const std::string& message); void addPresenceMessage(const std::string& message); void addErrorMessage(const std::string& errorMessage); + void replaceMessage(const std::string& message, const std::string& id, const boost::posix_time::ptime& time); + // File transfer related stuff + std::string addFileTransfer(const std::string& senderName, bool senderIsSelf, const std::string& filename, const boost::uintmax_t sizeInBytes); + void setFileTransferProgress(std::string id, const int percentageDone); + void setFileTransferStatus(std::string id, const FileTransferState state, const std::string& msg); + void show(); void activate(); void setUnreadMessageCount(int count); @@ -54,9 +68,22 @@ namespace Swift { void replaceLastMessage(const std::string& message); void setAckState(const std::string& id, AckState state); void flash(); + QByteArray getSplitterState(); + virtual void setAvailableOccupantActions(const std::vector<OccupantAction>& actions); + void setSubject(const std::string& subject); + void showRoomConfigurationForm(Form::ref); + + public slots: + void handleChangeSplitterState(QByteArray state); + void handleFontResized(int fontSizeSteps); + void setAlert(const std::string& alertText, const std::string& buttonText = ""); + void cancelAlert(); + void setCorrectionEnabled(Tristate enabled); signals: void geometryChanged(); + void splitterMoved(); + void fontResized(int); protected slots: void qAppFocusChanged(QWidget* old, QWidget* now); @@ -64,6 +91,9 @@ namespace Swift { void resizeEvent(QResizeEvent* event); void moveEvent(QMoveEvent* event); + void dragEnterEvent(QDragEnterEvent *event); + void dropEvent(QDropEvent *event); + protected: void showEvent(QShowEvent* event); @@ -71,31 +101,57 @@ namespace Swift { void returnPressed(); void handleInputChanged(); void handleKeyPressEvent(QKeyEvent* event); + void handleSplitterMoved(int pos, int index); + void handleAlertButtonClicked(); + void handleActionButtonClicked(); + + + void handleFileTransferCancel(QString id); + void handleFileTransferSetDescription(QString id); + void handleFileTransferStart(QString id); + void handleFileTransferAccept(QString id, QString filename); private: void updateTitleWithUnreadCount(); void tabComplete(); + void beginCorrection(); + void cancelCorrection(); std::string addMessage(const std::string &message, const std::string &senderName, bool senderIsSelf, boost::shared_ptr<SecurityLabel> label, const std::string& avatarPath, const QString& style, const boost::posix_time::ptime& time); + void handleOccupantSelectionChanged(RosterItem* item); int unreadCount_; bool contactIsTyping_; + LastLineTracker lastLineTracker_; QString contact_; + QString lastSentMessage_; QtChatView* messageLog_; QtChatTheme* theme_; QtTextEdit* input_; QComboBox* labelsWidget_; - QtTreeWidget* treeWidget_; + QtOccupantListWidget* treeWidget_; + QLabel* correctingLabel_; + QLabel* alertLabel_; + QWidget* alertWidget_; + QPushButton* alertButton_; TabComplete* completer_; + QLineEdit* subject_; + QPushButton* actionButton_; std::vector<SecurityLabelsCatalog::Item> availableLabels_; + bool isCorrection_; bool previousMessageWasSelf_; bool previousMessageWasSystem_; bool previousMessageWasPresence_; + bool previousMessageWasFileTransfer_; QString previousSenderName_; bool inputClearing_; UIEventStream* eventStream_; bool inputEnabled_; IDGenerator id_; + QSplitter *logRosterSplitter_; + Tristate correctionEnabled_; + QString alertStyleSheet_; + std::map<QString, QString> descriptions; + QtFileTransferJSBridge* fileTransferJS; + QPointer<QtMUCConfigurationWindow> mucConfigurationWindow; }; } - -#endif diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp index d146474..4943c0e 100644 --- a/Swift/QtUI/QtChatWindowFactory.cpp +++ b/Swift/QtUI/QtChatWindowFactory.cpp @@ -16,6 +16,10 @@ namespace Swift { + +static const QString SPLITTER_STATE = "mucSplitterState"; +static const QString CHAT_TABS_GEOMETRY = "chatTabsGeometry"; + QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs, const QString& themePath) : themePath_(themePath) { settings_ = settings; tabs_ = tabs; @@ -23,7 +27,7 @@ QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider if (splitter) { splitter->addWidget(tabs_); } else if (tabs_) { - QVariant chatTabsGeometryVariant = settings_->getQSettings()->value("chatTabsGeometry"); + QVariant chatTabsGeometryVariant = settings_->getQSettings()->value(CHAT_TABS_GEOMETRY); if (chatTabsGeometryVariant.isValid()) { tabs_->restoreGeometry(chatTabsGeometryVariant.toByteArray()); } @@ -43,11 +47,20 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre theme_ = new QtChatTheme(""); /* Use the inbuilt theme */ } } + QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), theme_, eventStream); + connect(chatWindow, SIGNAL(splitterMoved()), this, SLOT(handleSplitterMoved())); + connect(this, SIGNAL(changeSplitterState(QByteArray)), chatWindow, SLOT(handleChangeSplitterState(QByteArray))); + + QVariant splitterState = settings_->getQSettings()->value(SPLITTER_STATE); + if(splitterState.isValid()) { + chatWindow->handleChangeSplitterState(splitterState.toByteArray()); + } + if (tabs_) { tabs_->addTab(chatWindow); } else { - QVariant chatGeometryVariant = settings_->getQSettings()->value("chatTabsGeometry"); + QVariant chatGeometryVariant = settings_->getQSettings()->value(CHAT_TABS_GEOMETRY); if (chatGeometryVariant.isValid()) { chatWindow->restoreGeometry(chatGeometryVariant.toByteArray()); } @@ -57,7 +70,13 @@ ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStre } void QtChatWindowFactory::handleWindowGeometryChanged() { - settings_->getQSettings()->setValue("chatTabsGeometry", qobject_cast<QWidget*>(sender())->saveGeometry()); + settings_->getQSettings()->setValue(CHAT_TABS_GEOMETRY, qobject_cast<QWidget*>(sender())->saveGeometry()); +} + +void QtChatWindowFactory::handleSplitterMoved() { + QByteArray splitterState = qobject_cast<QtChatWindow*>(sender())->getSplitterState(); + settings_->getQSettings()->setValue(SPLITTER_STATE, QVariant(splitterState)); + emit changeSplitterState(splitterState); } } diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h index 0d47854..f3e8956 100644 --- a/Swift/QtUI/QtChatWindowFactory.h +++ b/Swift/QtUI/QtChatWindowFactory.h @@ -22,8 +22,11 @@ namespace Swift { QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs, const QString& themePath); ~QtChatWindowFactory(); ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream); + signals: + void changeSplitterState(QByteArray); private slots: void handleWindowGeometryChanged(); + void handleSplitterMoved(); private: QString themePath_; QtSettingsProvider* settings_; diff --git a/Swift/QtUI/QtContactEditWindow.cpp b/Swift/QtUI/QtContactEditWindow.cpp index 4be2939..9b24b23 100644 --- a/Swift/QtUI/QtContactEditWindow.cpp +++ b/Swift/QtUI/QtContactEditWindow.cpp @@ -42,6 +42,7 @@ QtContactEditWindow::QtContactEditWindow() : contactEditWidget_(NULL) { connect(removeButton, SIGNAL(clicked()), this, SLOT(handleRemoveContact())); buttonLayout->addWidget(removeButton); QPushButton* okButton = new QPushButton(tr("OK"), this); + okButton->setDefault( true ); connect(okButton, SIGNAL(clicked()), this, SLOT(handleUpdateContact())); buttonLayout->addStretch(); buttonLayout->addWidget(okButton); diff --git a/Swift/QtUI/QtDBUSURIHandler.cpp b/Swift/QtUI/QtDBUSURIHandler.cpp new file mode 100644 index 0000000..9b69ca6 --- /dev/null +++ b/Swift/QtUI/QtDBUSURIHandler.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "QtDBUSURIHandler.h" + +#include <QDBusAbstractAdaptor> +#include <QDBusConnection> + +#include "QtSwiftUtil.h" + +using namespace Swift; + +namespace { + class DBUSAdaptor: public QDBusAbstractAdaptor { + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "im.swift.Swift.URIHandler"); + public: + DBUSAdaptor(QtDBUSURIHandler* uriHandler) : QDBusAbstractAdaptor(uriHandler), uriHandler(uriHandler) { + } + + public slots: + void openURI(const QString& uri) { + uriHandler->onURI(Q2PSTRING(uri)); + } + + private: + QtDBUSURIHandler* uriHandler; + }; +} + +QtDBUSURIHandler::QtDBUSURIHandler() { + new DBUSAdaptor(this); + QDBusConnection connection = QDBusConnection::sessionBus(); + connection.registerService("im.swift.Swift.URIHandler"); + connection.registerObject("/", this); +} + +#include "QtDBUSURIHandler.moc" diff --git a/Swift/QtUI/QtDBUSURIHandler.h b/Swift/QtUI/QtDBUSURIHandler.h new file mode 100644 index 0000000..be1872e --- /dev/null +++ b/Swift/QtUI/QtDBUSURIHandler.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <QObject> +#include <SwifTools/URIHandler/URIHandler.h> + +namespace Swift { + class QtDBUSURIHandler : public QObject, public URIHandler { + public: + QtDBUSURIHandler(); + }; +} diff --git a/Swift/QtUI/QtFileTransferJSBridge.cpp b/Swift/QtUI/QtFileTransferJSBridge.cpp new file mode 100644 index 0000000..76c1509 --- /dev/null +++ b/Swift/QtUI/QtFileTransferJSBridge.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "QtFileTransferJSBridge.h" + +namespace Swift { + +QtFileTransferJSBridge::QtFileTransferJSBridge() { + +} + +QtFileTransferJSBridge::~QtFileTransferJSBridge() { + +} + +}
\ No newline at end of file diff --git a/Swift/QtUI/QtFileTransferJSBridge.h b/Swift/QtUI/QtFileTransferJSBridge.h new file mode 100644 index 0000000..bd884e5 --- /dev/null +++ b/Swift/QtUI/QtFileTransferJSBridge.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <QObject> + +#include <map> + +namespace Swift { + +class FileTransferController; + +class QtFileTransferJSBridge : public QObject { + Q_OBJECT +public: + QtFileTransferJSBridge(); + virtual ~QtFileTransferJSBridge(); +signals: + void discard(QString id); + void sendRequest(QString id); + void setDescription(QString id); + void acceptRequest(QString id, QString filename); + void cancel(QString id); +}; + +} diff --git a/Swift/QtUI/QtFileTransferListItemModel.cpp b/Swift/QtUI/QtFileTransferListItemModel.cpp new file mode 100644 index 0000000..63dd45a --- /dev/null +++ b/Swift/QtUI/QtFileTransferListItemModel.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "QtFileTransferListItemModel.h" + +#include <boost/bind.hpp> +#include <boost/cstdint.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swift/Controllers/FileTransfer/FileTransferController.h> +#include <Swift/Controllers/FileTransfer/FileTransferOverview.h> + +namespace Swift { + +extern std::string formatSize(const boost::uintmax_t bytes); + +QtFileTransferListItemModel::QtFileTransferListItemModel(QObject *parent) : QAbstractItemModel(parent), fileTransferOverview(0) { +} + +void QtFileTransferListItemModel::setFileTransferOverview(FileTransferOverview *overview) { + fileTransferOverview = overview; + fileTransferOverview->onNewFileTransferController.connect(boost::bind(&QtFileTransferListItemModel::handleNewFileTransferController, this, _1)); +} + +void QtFileTransferListItemModel::handleNewFileTransferController(FileTransferController* newController) { + emit layoutAboutToBeChanged(); + emit layoutChanged(); + dataChanged(createIndex(0,0), createIndex(fileTransferOverview->getFileTransfers().size(),4)); + newController->onStateChage.connect(boost::bind(&QtFileTransferListItemModel::handleStateChange, this, fileTransferOverview->getFileTransfers().size() - 1)); + newController->onProgressChange.connect(boost::bind(&QtFileTransferListItemModel::handleProgressChange, this, fileTransferOverview->getFileTransfers().size() - 1)); +} + +void QtFileTransferListItemModel::handleStateChange(int index) { + emit dataChanged(createIndex(index, 2), createIndex(index, 2)); +} + +void QtFileTransferListItemModel::handleProgressChange(int index) { + emit dataChanged(createIndex(index, 3), createIndex(index, 3)); +} + +QVariant QtFileTransferListItemModel::headerData(int section, Qt::Orientation /* orientation */, int role) const { + if (role != Qt::DisplayRole) return QVariant(); + if (section == Direction) return QVariant("Direction"); + if (section == OtherParty) return QVariant("Other Party"); + if (section == State) return QVariant("State"); + if (section == Progress) return QVariant("Progress"); + if (section == OverallSize) return QVariant("Size"); + return QVariant(); +} + +int QtFileTransferListItemModel::columnCount(const QModelIndex& /* parent */) const { + return NoOfColumns; +} + +QVariant QtFileTransferListItemModel::data(const QModelIndex &index, int role) const { + if (role != Qt::DisplayRole || !index.isValid() || + !fileTransferOverview || static_cast<size_t>(index.row()) >= fileTransferOverview->getFileTransfers().size()) { + return QVariant(); + } + FileTransferController* controller = fileTransferOverview->getFileTransfers().at(index.row()); + if (index.column() == Direction) { + return controller->isIncoming() ? QVariant("Incoming") : QVariant("Outgoing"); + } + if (index.column() == OtherParty) { + return QVariant(QString::fromStdString(controller->getOtherParty().toString())); + } + if (index.column() == State) { + FileTransfer::State state = controller->getState(); + switch(state.state) { + case FileTransfer::State::WaitingForStart: + return QVariant("Waiting for start"); + case FileTransfer::State::WaitingForAccept: + return QVariant("Waiting for other side to accept"); + case FileTransfer::State::Negotiating: + return QVariant("Negotiating"); + case FileTransfer::State::Transferring: + return QVariant("Transferring"); + case FileTransfer::State::Finished: + return QVariant("Finished"); + case FileTransfer::State::Failed: + return QVariant("Failed"); + case FileTransfer::State::Canceled: + return QVariant("Canceled"); + } + } + + if (index.column() == Progress) { + return QVariant(QString::number(controller->getProgress())); + } + if (index.column() == OverallSize) { + return QVariant(QString::fromStdString(formatSize((controller->getSize())))); + } + return QVariant(); +} + +QModelIndex QtFileTransferListItemModel::parent(const QModelIndex& /* child */) const { + return createIndex(0,0); +} + +int QtFileTransferListItemModel::rowCount(const QModelIndex& /* parent */) const { + return fileTransferOverview ? fileTransferOverview->getFileTransfers().size() : 0; +} + +QModelIndex QtFileTransferListItemModel::index(int row, int column, const QModelIndex& /* parent */) const { + return createIndex(row, column, 0); +} + +} diff --git a/Swift/QtUI/QtFileTransferListItemModel.h b/Swift/QtUI/QtFileTransferListItemModel.h new file mode 100644 index 0000000..1d892a5 --- /dev/null +++ b/Swift/QtUI/QtFileTransferListItemModel.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <QAbstractItemModel> + +namespace Swift { + +class FileTransferController; +class FileTransferOverview; + +class QtFileTransferListItemModel : public QAbstractItemModel { + Q_OBJECT +public: + explicit QtFileTransferListItemModel(QObject *parent = 0); + + void setFileTransferOverview(FileTransferOverview*); + + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent) const; + QModelIndex index(int row, int column, const QModelIndex &parent) const; + +private: + enum Columns { + Direction = 0, + OtherParty, + State, + Progress, + OverallSize, + NoOfColumns, + }; + +private: + void handleNewFileTransferController(FileTransferController*); + void handleStateChange(int index); + void handleProgressChange(int index); + +signals: + +public slots: + +private: + FileTransferOverview *fileTransferOverview; + +}; + +} diff --git a/Swift/QtUI/QtFileTransferListWidget.cpp b/Swift/QtUI/QtFileTransferListWidget.cpp new file mode 100644 index 0000000..01c632f --- /dev/null +++ b/Swift/QtUI/QtFileTransferListWidget.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "QtFileTransferListWidget.h" + +#include <Swift/QtUI/QtFileTransferListItemModel.h> + +#include <QVBoxLayout> +#include <QHBoxLayout> +#include <QWidget> +#include <QPushButton> + +namespace Swift { + +QtFileTransferListWidget::QtFileTransferListWidget() : fileTransferOverview(0) { + QVBoxLayout* layout = new QVBoxLayout(this); + layout->setSpacing(0); + layout->setContentsMargins(0,0,0,0); + + treeView = new QTreeView(this); + treeView->setRootIsDecorated(false); + treeView->setItemsExpandable(false); + layout->addWidget(treeView); + + itemModel = new QtFileTransferListItemModel(); + treeView->setModel(itemModel); + + QWidget* bottom = new QWidget(this); + layout->addWidget(bottom); + bottom->setAutoFillBackground(true); + + QHBoxLayout* buttonLayout = new QHBoxLayout(bottom); + buttonLayout->setContentsMargins(10,0,20,0); + buttonLayout->setSpacing(0); + + QPushButton* clearFinished = new QPushButton(tr("Clear Finished Transfers"), bottom); + clearFinished->setEnabled(false); + //connect(clearButton, SIGNAL(clicked()), textEdit, SLOT(clear())); + buttonLayout->addWidget(clearFinished); + + setWindowTitle(tr("File Transfer List")); + emit titleUpdated(); +} + +QtFileTransferListWidget::~QtFileTransferListWidget() { + delete itemModel; +} + +void QtFileTransferListWidget::showEvent(QShowEvent* event) { + emit windowOpening(); + emit titleUpdated(); /* This just needs to be somewhere after construction */ + QWidget::showEvent(event); +} + +void QtFileTransferListWidget::show() { + QWidget::show(); + emit windowOpening(); +} + +void QtFileTransferListWidget::activate() { + emit wantsToActivate(); +} + +void QtFileTransferListWidget::setFileTransferOverview(FileTransferOverview *overview) { + fileTransferOverview = overview; + itemModel->setFileTransferOverview(overview); +} + +void QtFileTransferListWidget::closeEvent(QCloseEvent* event) { + emit windowClosing(); + event->accept(); +} + +} diff --git a/Swift/QtUI/QtFileTransferListWidget.h b/Swift/QtUI/QtFileTransferListWidget.h new file mode 100644 index 0000000..c828d4e --- /dev/null +++ b/Swift/QtUI/QtFileTransferListWidget.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include "Swift/Controllers/UIInterfaces/FileTransferListWidget.h" + +#include "QtTabbable.h" + +#include <QCloseEvent> +#include <QShowEvent> +#include <QTreeView> + +namespace Swift { + +class FileTransferOverview; +class QtFileTransferListItemModel; + +class QtFileTransferListWidget : public QtTabbable, public FileTransferListWidget { + Q_OBJECT + +public: + QtFileTransferListWidget(); + virtual ~QtFileTransferListWidget(); + + void show(); + void activate(); + + void setFileTransferOverview(FileTransferOverview *); + +private: + virtual void closeEvent(QCloseEvent* event); + virtual void showEvent(QShowEvent* event); + +private: + QTreeView* treeView; + + QtFileTransferListItemModel* itemModel; + FileTransferOverview* fileTransferOverview; +}; + +} diff --git a/Swift/QtUI/QtFormWidget.cpp b/Swift/QtUI/QtFormWidget.cpp new file mode 100644 index 0000000..2df8d7f --- /dev/null +++ b/Swift/QtUI/QtFormWidget.cpp @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/QtUI/QtFormWidget.h> + +#include <QGridLayout> +#include <QLabel> +#include <QListWidget> +#include <QLineEdit> +#include <QTextEdit> +#include <QCheckBox> +#include <QScrollArea> +#include <qdebug.h> + +#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swiften/Base/foreach.h> + +namespace Swift { + +QtFormWidget::QtFormWidget(Form::ref form, QWidget* parent) : QWidget(parent), form_(form) { + QGridLayout* thisLayout = new QGridLayout(this); + int row = 0; + if (!form->getTitle().empty()) { + QLabel* instructions = new QLabel(("<b>" + form->getTitle() + "</b>").c_str(), this); + thisLayout->addWidget(instructions, row++, 0, 1, 2); + } + if (!form->getInstructions().empty()) { + QLabel* instructions = new QLabel(form->getInstructions().c_str(), this); + thisLayout->addWidget(instructions, row++, 0, 1, 2); + } + QScrollArea* scrollArea = new QScrollArea(this); + thisLayout->addWidget(scrollArea); + QWidget* scroll = new QWidget(this); + QGridLayout* layout = new QGridLayout(scroll); + foreach (boost::shared_ptr<FormField> field, form->getFields()) { + QWidget* widget = createWidget(field); + if (widget) { + layout->addWidget(new QLabel(field->getLabel().c_str(), this), row, 0); + layout->addWidget(widget, row++, 1); + } + } + scrollArea->setWidget(scroll); + scrollArea->setWidgetResizable(true); +} + +QtFormWidget::~QtFormWidget() { + +} + +QListWidget* QtFormWidget::createList(FormField::ref field) { + QListWidget* listWidget = new QListWidget(this); + listWidget->setSortingEnabled(false); + listWidget->setSelectionMode(boost::dynamic_pointer_cast<ListMultiFormField>(field) ? QAbstractItemView::MultiSelection : QAbstractItemView::SingleSelection); + boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field); + boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field); + std::vector<bool> selected; + foreach (FormField::Option option, field->getOptions()) { + listWidget->addItem(option.label.c_str()); + if (listSingleField) { + selected.push_back(option.value == listSingleField->getValue()); + } + else if (listMultiField) { + std::string text = option.value; + selected.push_back(std::find(listMultiField->getValue().begin(), listMultiField->getValue().end(), text) != listMultiField->getValue().end()); + } + + } + for (int i = 0; i < listWidget->count(); i++) { + QListWidgetItem* item = listWidget->item(i); + item->setSelected(selected[i]); + } + return listWidget; +} + +QWidget* QtFormWidget::createWidget(FormField::ref field) { + QWidget* widget = NULL; + boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field); + if (booleanField) { + QCheckBox* checkWidget = new QCheckBox(this); + checkWidget->setCheckState(booleanField->getValue() ? Qt::Checked : Qt::Unchecked); + widget = checkWidget; + } + boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field); + if (fixedField) { + QString value = fixedField->getValue().c_str(); + widget = new QLabel(value, this); + } + boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field); + if (listSingleField) { + widget = createList(field); + } + boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field); + if (textMultiField) { + QString value = textMultiField->getValue().c_str(); + widget = new QTextEdit(value, this); + } + boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field); + if (textPrivateField) { + QString value = textPrivateField->getValue().c_str(); + QLineEdit* lineWidget = new QLineEdit(value, this); + lineWidget->setEchoMode(QLineEdit::Password); + widget = lineWidget; + } + boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field); + if (textSingleField) { + QString value = textSingleField->getValue().c_str(); + widget = new QLineEdit(value, this); + } + boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field); + if (jidSingleField) { + QString value = jidSingleField->getValue().toString().c_str(); + widget = new QLineEdit(value, this); + } + boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field); + if (jidMultiField) { + QString text; + bool prev = false; + foreach (JID line, jidMultiField->getValue()) { + if (prev) { + text += "\n"; + } + prev = true; + text += line.toString().c_str(); + } + widget = new QTextEdit(text, this); + } + boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field); + if (listMultiField) { + widget = createList(field); + } + boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field); + if (hiddenField) { + } + fields_[field->getName()] = widget; + return widget; +} + +Form::ref QtFormWidget::getCompletedForm() { + Form::ref result(new Form(Form::SubmitType)); + foreach (boost::shared_ptr<FormField> field, form_->getFields()) { + boost::shared_ptr<FormField> resultField; + boost::shared_ptr<BooleanFormField> booleanField = boost::dynamic_pointer_cast<BooleanFormField>(field); + if (booleanField) { + resultField = FormField::ref(BooleanFormField::create(qobject_cast<QCheckBox*>(fields_[field->getName()])->checkState() == Qt::Checked)); + } + boost::shared_ptr<FixedFormField> fixedField = boost::dynamic_pointer_cast<FixedFormField>(field); + if (fixedField) { + resultField = FormField::ref(FixedFormField::create(fixedField->getValue())); + } + boost::shared_ptr<ListSingleFormField> listSingleField = boost::dynamic_pointer_cast<ListSingleFormField>(field); + if (listSingleField) { + QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]); + if (listWidget->selectedItems().size() > 0) { + int i = listWidget->row(listWidget->selectedItems()[0]); + resultField = FormField::ref(ListSingleFormField::create(field->getOptions()[i].value)); + } + else { + resultField = FormField::ref(ListSingleFormField::create()); + } + } + boost::shared_ptr<TextMultiFormField> textMultiField = boost::dynamic_pointer_cast<TextMultiFormField>(field); + if (textMultiField) { + QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]); + QString string = widget->toPlainText(); + if (string.isEmpty()) { + resultField = FormField::ref(TextMultiFormField::create()); + } + else { + resultField = FormField::ref(TextMultiFormField::create(Q2PSTRING(string))); + } + } + boost::shared_ptr<TextPrivateFormField> textPrivateField = boost::dynamic_pointer_cast<TextPrivateFormField>(field); + if (textPrivateField) { + QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]); + QString string = widget->text(); + if (string.isEmpty()) { + resultField = FormField::ref(TextPrivateFormField::create()); + } + else { + resultField = FormField::ref(TextPrivateFormField::create(Q2PSTRING(string))); + } + } + boost::shared_ptr<TextSingleFormField> textSingleField = boost::dynamic_pointer_cast<TextSingleFormField>(field); + if (textSingleField) { + QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]); + QString string = widget->text(); + if (string.isEmpty()) { + resultField = FormField::ref(TextSingleFormField::create()); + } + else { + resultField = FormField::ref(TextSingleFormField::create(Q2PSTRING(string))); + } + } + boost::shared_ptr<JIDSingleFormField> jidSingleField = boost::dynamic_pointer_cast<JIDSingleFormField>(field); + if (jidSingleField) { + QLineEdit* widget = qobject_cast<QLineEdit*>(fields_[field->getName()]); + QString string = widget->text(); + JID jid(Q2PSTRING(string)); + if (string.isEmpty()) { + resultField = FormField::ref(JIDSingleFormField::create()); + } + else { + resultField = FormField::ref(JIDSingleFormField::create(jid)); + } + } + boost::shared_ptr<JIDMultiFormField> jidMultiField = boost::dynamic_pointer_cast<JIDMultiFormField>(field); + if (jidMultiField) { + QTextEdit* widget = qobject_cast<QTextEdit*>(fields_[field->getName()]); + QString string = widget->toPlainText(); + if (string.isEmpty()) { + resultField = FormField::ref(JIDMultiFormField::create()); + } + else { + QStringList lines = string.split("\n"); + std::vector<JID> value; + foreach (QString line, lines) { + value.push_back(JID(Q2PSTRING(line))); + } + resultField = FormField::ref(JIDMultiFormField::create(value)); + } + } + boost::shared_ptr<ListMultiFormField> listMultiField = boost::dynamic_pointer_cast<ListMultiFormField>(field); + if (listMultiField) { + QListWidget* listWidget = qobject_cast<QListWidget*>(fields_[field->getName()]); + std::vector<std::string> values; + foreach (QListWidgetItem* item, listWidget->selectedItems()) { + values.push_back(field->getOptions()[listWidget->row(item)].value); + } + resultField = FormField::ref(ListMultiFormField::create(values)); + } + boost::shared_ptr<HiddenFormField> hiddenField = boost::dynamic_pointer_cast<HiddenFormField>(field); + if (hiddenField) { + resultField = FormField::ref(HiddenFormField::create(hiddenField->getValue())); + } + resultField->setName(field->getName()); + result->addField(resultField); + } + return result; +} + +} diff --git a/Swift/QtUI/QtFormWidget.h b/Swift/QtUI/QtFormWidget.h new file mode 100644 index 0000000..2fb7b98 --- /dev/null +++ b/Swift/QtUI/QtFormWidget.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <QWidget> + +#include <map> +#include <Swiften/Elements/Form.h> + +class QListWidget; + +namespace Swift { + +class QtFormWidget : public QWidget { + Q_OBJECT + public: + QtFormWidget(Form::ref form, QWidget* parent = NULL); + virtual ~QtFormWidget(); + Form::ref getCompletedForm(); + private: + QWidget* createWidget(FormField::ref field); + QListWidget* createList(FormField::ref field); + std::map<std::string, QWidget*> fields_; + Form::ref form_; +}; + +} diff --git a/Swift/QtUI/QtJoinMUCWindow.cpp b/Swift/QtUI/QtJoinMUCWindow.cpp index 7980a17..a44cdaf 100644 --- a/Swift/QtUI/QtJoinMUCWindow.cpp +++ b/Swift/QtUI/QtJoinMUCWindow.cpp @@ -6,10 +6,13 @@ #include "QtJoinMUCWindow.h" #include "QtSwiftUtil.h" +#include <boost/smart_ptr/make_shared.hpp> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> namespace Swift { -QtJoinMUCWindow::QtJoinMUCWindow() { +QtJoinMUCWindow::QtJoinMUCWindow(UIEventStream* uiEventStream) : uiEventStream(uiEventStream) { ui.setupUi(this); #if QT_VERSION >= 0x040700 ui.room->setPlaceholderText(tr("someroom@rooms.example.com")); @@ -35,7 +38,7 @@ void QtJoinMUCWindow::handleJoin() { lastSetNick = Q2PSTRING(ui.nickName->text()); JID room(Q2PSTRING(ui.room->text())); - onJoinMUC(room, lastSetNick, ui.joinAutomatically->isChecked()); + uiEventStream->send(boost::make_shared<JoinMUCUIEvent>(room, lastSetNick, ui.joinAutomatically->isChecked())); hide(); } diff --git a/Swift/QtUI/QtJoinMUCWindow.h b/Swift/QtUI/QtJoinMUCWindow.h index 6e8e846..90b4f3f 100644 --- a/Swift/QtUI/QtJoinMUCWindow.h +++ b/Swift/QtUI/QtJoinMUCWindow.h @@ -11,10 +11,11 @@ #include <Swift/QtUI/ui_QtJoinMUCWindow.h> namespace Swift { + class UIEventStream; class QtJoinMUCWindow : public QWidget, public JoinMUCWindow { Q_OBJECT public: - QtJoinMUCWindow(); + QtJoinMUCWindow(UIEventStream* uiEventStream); virtual void setNick(const std::string& nick); virtual void setMUC(const std::string& nick); @@ -28,5 +29,6 @@ namespace Swift { private: Ui::QtJoinMUCWindow ui; std::string lastSetNick; + UIEventStream* uiEventStream; }; } diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp index fc92792..0db6071 100644 --- a/Swift/QtUI/QtLoginWindow.cpp +++ b/Swift/QtUI/QtLoginWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -7,6 +7,7 @@ #include "QtLoginWindow.h" #include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> #include <algorithm> #include <cassert> @@ -28,6 +29,7 @@ #include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/Controllers/UIEvents/RequestXMLConsoleUIEvent.h" +#include "Swift/Controllers/UIEvents/RequestFileTransferListUIEvent.h" #include "Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h" #include "Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h" #include "Swiften/Base/Platform.h" @@ -39,7 +41,7 @@ namespace Swift{ -QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() { +QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow(), forgetful_(false) { uiEventStream_ = uiEventStream; setWindowTitle("Swift"); @@ -56,9 +58,9 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() { stack_ = new QStackedWidget(centralWidget); topLayout->addWidget(stack_); topLayout->setMargin(0); - QWidget *wrapperWidget = new QWidget(this); - wrapperWidget->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); - QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, wrapperWidget); + loginWidgetWrapper_ = new QWidget(this); + loginWidgetWrapper_->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, loginWidgetWrapper_); layout->addStretch(2); QLabel* logo = new QLabel(this); @@ -139,7 +141,7 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() { layout->addWidget(loginAutomatically_); connect(loginButton_, SIGNAL(clicked()), SLOT(loginClicked())); - stack_->addWidget(wrapperWidget); + stack_->addWidget(loginWidgetWrapper_); #ifdef SWIFTEN_PLATFORM_MACOSX menuBar_ = new QMenuBar(NULL); #else @@ -162,9 +164,15 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() { connect(aboutAction, SIGNAL(triggered()), SLOT(handleAbout())); swiftMenu_->addAction(aboutAction); - QAction* xmlConsoleAction = new QAction(tr("&Show Debug Console"), this); - connect(xmlConsoleAction, SIGNAL(triggered()), SLOT(handleShowXMLConsole())); - generalMenu_->addAction(xmlConsoleAction); + xmlConsoleAction_ = new QAction(tr("&Show Debug Console"), this); + connect(xmlConsoleAction_, SIGNAL(triggered()), SLOT(handleShowXMLConsole())); + generalMenu_->addAction(xmlConsoleAction_); + +#ifdef SWIFT_EXPERIMENTAL_FT + fileTransferOverviewAction_ = new QAction(tr("Show &File Transfer Overview"), this); + connect(fileTransferOverviewAction_, SIGNAL(triggered()), SLOT(handleShowFileTransferOverview())); + generalMenu_->addAction(fileTransferOverviewAction_); +#endif toggleSoundsAction_ = new QAction(tr("&Play Sounds"), this); toggleSoundsAction_->setCheckable(true); @@ -197,6 +205,17 @@ QtLoginWindow::QtLoginWindow(UIEventStream* uiEventStream) : QMainWindow() { this->show(); } +void QtLoginWindow::setRememberingAllowed(bool allowed) { + forgetful_ = true; + remember_->setEnabled(allowed); + loginAutomatically_->setEnabled(allowed); + xmlConsoleAction_->setEnabled(allowed); + if (!allowed) { + remember_->setChecked(false); + loginAutomatically_->setChecked(false); + } +} + bool QtLoginWindow::eventFilter(QObject *obj, QEvent *event) { if (obj == username_->view() && event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); @@ -284,11 +303,9 @@ void QtLoginWindow::handleUsernameTextChanged() { } void QtLoginWindow::loggedOut() { - if (stack_->count() > 1) { - QWidget* current = stack_->currentWidget(); - stack_->setCurrentIndex(0); - stack_->removeWidget(current); - } + stack_->removeWidget(stack_->currentWidget()); + stack_->addWidget(loginWidgetWrapper_); + stack_->setCurrentWidget(loginWidgetWrapper_); setInitialMenus(); setIsLoggingIn(false); } @@ -306,6 +323,10 @@ void QtLoginWindow::setIsLoggingIn(bool loggingIn) { void QtLoginWindow::loginClicked() { if (username_->isEnabled()) { onLoginRequest(Q2PSTRING(username_->currentText()), Q2PSTRING(password_->text()), Q2PSTRING(certificateFile_), remember_->isChecked(), loginAutomatically_->isChecked()); + if (forgetful_) { /* Mustn't remember logins */ + username_->clearEditText(); + password_->setText(""); + } } else { onCancelLoginRequest(); } @@ -343,6 +364,10 @@ void QtLoginWindow::handleShowXMLConsole() { uiEventStream_->send(boost::shared_ptr<RequestXMLConsoleUIEvent>(new RequestXMLConsoleUIEvent())); } +void QtLoginWindow::handleShowFileTransferOverview() { + uiEventStream_->send(boost::make_shared<RequestFileTransferListUIEvent>()); +} + void QtLoginWindow::handleToggleSounds(bool enabled) { uiEventStream_->send(boost::shared_ptr<ToggleSoundsUIEvent>(new ToggleSoundsUIEvent(enabled))); } @@ -370,6 +395,7 @@ void QtLoginWindow::setInitialMenus() { void QtLoginWindow::morphInto(MainWindow *mainWindow) { QtMainWindow *qtMainWindow = dynamic_cast<QtMainWindow*>(mainWindow); assert(qtMainWindow); + stack_->removeWidget(loginWidgetWrapper_); stack_->addWidget(qtMainWindow); stack_->setCurrentWidget(qtMainWindow); setEnabled(true); diff --git a/Swift/QtUI/QtLoginWindow.h b/Swift/QtUI/QtLoginWindow.h index 3f3b5f8..414bb20 100644 --- a/Swift/QtUI/QtLoginWindow.h +++ b/Swift/QtUI/QtLoginWindow.h @@ -1,11 +1,10 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFT_QtLoginWindow_H -#define SWIFT_QtLoginWindow_H +#pragma once #include <QMainWindow> #include <QPointer> @@ -37,6 +36,7 @@ namespace Swift { virtual void removeAvailableAccount(const std::string& jid); virtual void setLoginAutomatically(bool loginAutomatically); virtual void setIsLoggingIn(bool loggingIn); + virtual void setRememberingAllowed(bool allowed); void selectUser(const std::string& user); bool askUserToTrustCertificatePermanently(const std::string& message, Certificate::ref certificate); void hide(); @@ -51,6 +51,7 @@ namespace Swift { void handleCertficateChecked(bool); void handleQuit(); void handleShowXMLConsole(); + void handleShowFileTransferOverview(); void handleToggleSounds(bool enabled); void handleToggleNotifications(bool enabled); void handleAbout(); @@ -65,6 +66,7 @@ namespace Swift { private: void setInitialMenus(); + QWidget* loginWidgetWrapper_; QStringList usernames_; QStringList passwords_; QStringList certificateFiles_; @@ -85,7 +87,8 @@ namespace Swift { QAction* toggleNotificationsAction_; UIEventStream* uiEventStream_; QPointer<QtAboutWidget> aboutDialog_; + bool forgetful_; + QAction* xmlConsoleAction_; + QAction* fileTransferOverviewAction_; }; } - -#endif diff --git a/Swift/QtUI/QtMUCConfigurationWindow.cpp b/Swift/QtUI/QtMUCConfigurationWindow.cpp new file mode 100644 index 0000000..a8dec2a --- /dev/null +++ b/Swift/QtUI/QtMUCConfigurationWindow.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/QtUI/QtMUCConfigurationWindow.h> + +#include <boost/bind.hpp> +#include <QBoxLayout> +#include <Swift/QtUI/QtFormWidget.h> + +namespace Swift { +QtMUCConfigurationWindow::QtMUCConfigurationWindow(Form::ref form) { + + setAttribute(Qt::WA_DeleteOnClose); + + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom, this); + layout->setContentsMargins(0,0,0,0); + layout->setSpacing(2); + //QLabel* label = new QLabel(this); + //label->setText(tr("Room configuration")); + //layout->addWidget(label); + + formWidget_ = NULL; + formWidget_ = new QtFormWidget(form, this); + layout->addWidget(formWidget_); + + QWidget* buttonsWidget = new QWidget(this); + layout->addWidget(buttonsWidget); + + QBoxLayout* buttonsLayout = new QBoxLayout(QBoxLayout::LeftToRight, buttonsWidget); + cancelButton_ = new QPushButton(tr("Cancel"), buttonsWidget); + buttonsLayout->addWidget(cancelButton_); + connect(cancelButton_, SIGNAL(clicked()), this, SLOT(handleCancelClicked())); + okButton_ = new QPushButton(tr("OK"), buttonsWidget); + buttonsLayout->addWidget(okButton_); + connect(okButton_, SIGNAL(clicked()), this, SLOT(handleOKClicked())); + show(); +} + +QtMUCConfigurationWindow::~QtMUCConfigurationWindow() { + +} + +void QtMUCConfigurationWindow::handleCancelClicked() { + close(); +} + +void QtMUCConfigurationWindow::handleOKClicked() { + onFormComplete(formWidget_->getCompletedForm()); + close(); +} + + +} diff --git a/Swift/QtUI/QtMUCConfigurationWindow.h b/Swift/QtUI/QtMUCConfigurationWindow.h new file mode 100644 index 0000000..2be126b --- /dev/null +++ b/Swift/QtUI/QtMUCConfigurationWindow.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <QWidget> +#include <QPushButton> +#include <QLabel> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Form.h> + +class QBoxLayout; + +namespace Swift { + class QtFormWidget; + class QtMUCConfigurationWindow : public QWidget { + Q_OBJECT + public: + QtMUCConfigurationWindow(Form::ref form); + virtual ~QtMUCConfigurationWindow(); + boost::signal<void (Form::ref)> onFormComplete; + private slots: + void handleCancelClicked(); + void handleOKClicked(); + private: + QtFormWidget* formWidget_; + QPushButton* okButton_; + QPushButton* cancelButton_; + }; +} diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index 6391961..9d35435 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -21,20 +21,25 @@ #include <QAction> #include <QTabWidget> -#include "QtSwiftUtil.h" -#include "QtTabWidget.h" -#include "Roster/QtTreeWidget.h" -#include "Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h" -#include "Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h" -#include "Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h" -#include "Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h" -#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" -#include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h" +#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtTabWidget.h> +#include <Swift/QtUI/QtSettingsProvider.h> +#include <Roster/QtRosterWidget.h> +#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestProfileEditorUIEvent.h> +#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h> namespace Swift { +#define CURRENT_ROSTER_TAB "current_roster_tab" + QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventStream) : QWidget(), MainWindow(false) { uiEventStream_ = uiEventStream; + settings_ = settings; setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); mainLayout->setContentsMargins(0,0,0,0); @@ -57,8 +62,7 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS contactTabLayout->setSpacing(0); contactTabLayout->setContentsMargins(0, 0, 0, 0); - treeWidget_ = new QtTreeWidget(uiEventStream_); - treeWidget_->setEditable(true); + treeWidget_ = new QtRosterWidget(uiEventStream_, this); contactTabLayout->addWidget(treeWidget_); tabs_->addTab(contactsTabWidget_, tr("&Contacts")); @@ -67,9 +71,14 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS connect(eventWindow_, SIGNAL(onNewEventCountUpdated(int)), this, SLOT(handleEventCountUpdated(int))); chatListWindow_ = new QtChatListWindow(uiEventStream_); + connect(chatListWindow_, SIGNAL(onCountUpdated(int)), this, SLOT(handleChatCountUpdated(int))); - tabs_->addTab(eventWindow_, tr("&Notices")); tabs_->addTab(chatListWindow_, tr("C&hats")); + tabs_->addTab(eventWindow_, tr("&Notices")); + + tabs_->setCurrentIndex(settings_->getIntSetting(CURRENT_ROSTER_TAB, 0)); + + connect(tabs_, SIGNAL(currentChanged(int)), this, SLOT(handleTabChanged(int))); this->setLayout(mainLayout); @@ -99,12 +108,20 @@ QtMainWindow::QtMainWindow(QtSettingsProvider* settings, UIEventStream* uiEventS chatUserAction_ = new QAction(tr("Start &Chat"), this); connect(chatUserAction_, SIGNAL(triggered(bool)), this, SLOT(handleChatUserActionTriggered(bool))); actionsMenu->addAction(chatUserAction_); + serverAdHocMenu_ = new QMenu(tr("Run Server Command"), this); + actionsMenu->addMenu(serverAdHocMenu_); actionsMenu->addSeparator(); QAction* signOutAction = new QAction(tr("&Sign Out"), this); connect(signOutAction, SIGNAL(triggered()), SLOT(handleSignOutAction())); actionsMenu->addAction(signOutAction); - connect(treeWidget_, SIGNAL(onSomethingSelectedChanged(bool)), editUserAction_, SLOT(setEnabled(bool))); + treeWidget_->onSomethingSelectedChanged.connect(boost::bind(&QAction::setEnabled, editUserAction_, _1)); + + setAvailableAdHocCommands(std::vector<DiscoItems::Item>()); + QAction* adHocAction = new QAction(tr("Collecting commands..."), this); + adHocAction->setEnabled(false); + serverAdHocMenu_->addAction(adHocAction); + serverAdHocCommandActions_.append(adHocAction); lastOfflineState_ = false; uiEventStream_->onUIEvent.connect(boost::bind(&QtMainWindow::handleUIEvent, this, _1)); @@ -114,6 +131,10 @@ QtMainWindow::~QtMainWindow() { uiEventStream_->onUIEvent.disconnect(boost::bind(&QtMainWindow::handleUIEvent, this, _1)); } +void QtMainWindow::handleTabChanged(int index) { + settings_->storeInt(CURRENT_ROSTER_TAB, index); +} + QtEventWindow* QtMainWindow::getEventWindow() { return eventWindow_; } @@ -132,7 +153,7 @@ void QtMainWindow::handleEditProfileRequest() { void QtMainWindow::handleEventCountUpdated(int count) { QColor eventTabColor = (count == 0) ? QColor() : QColor(255, 0, 0); // invalid resets to default - int eventIndex = 1; + int eventIndex = 2; tabs_->tabBar()->setTabTextColor(eventIndex, eventTabColor); QString text = tr("&Notices"); if (count > 0) { @@ -141,6 +162,17 @@ void QtMainWindow::handleEventCountUpdated(int count) { tabs_->setTabText(eventIndex, text); } +void QtMainWindow::handleChatCountUpdated(int count) { + QColor chatTabColor = (count == 0) ? QColor() : QColor(255, 0, 0); // invalid resets to default + int chatIndex = 1; + tabs_->tabBar()->setTabTextColor(chatIndex, chatTabColor); + QString text = tr("&Chats"); + if (count > 0) { + text += QString(" (%1)").arg(count); + } + tabs_->setTabText(chatIndex, text); +} + void QtMainWindow::handleAddUserActionTriggered(bool /*checked*/) { boost::shared_ptr<UIEvent> event(new RequestAddUserDialogUIEvent()); uiEventStream_->send(event); @@ -206,6 +238,33 @@ void QtMainWindow::setConnecting() { meView_->setConnecting(); } +void QtMainWindow::handleAdHocActionTriggered(bool /*checked*/) { + QAction* action = qobject_cast<QAction*>(sender()); + assert(action); + DiscoItems::Item command = serverAdHocCommands_[serverAdHocCommandActions_.indexOf(action)]; + uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestAdHocUIEvent(command))); +} + +void QtMainWindow::setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) { + serverAdHocCommands_ = commands; + foreach (QAction* action, serverAdHocCommandActions_) { + delete action; + } + serverAdHocMenu_->clear(); + serverAdHocCommandActions_.clear(); + foreach (DiscoItems::Item command, commands) { + QAction* action = new QAction(P2QSTRING(command.getName()), this); + connect(action, SIGNAL(triggered(bool)), this, SLOT(handleAdHocActionTriggered(bool))); + serverAdHocMenu_->addAction(action); + serverAdHocCommandActions_.append(action); + } + if (serverAdHocCommandActions_.isEmpty()) { + QAction* action = new QAction(tr("No Available Commands"), this); + action->setEnabled(false); + serverAdHocMenu_->addAction(action); + serverAdHocCommandActions_.append(action); + } +} } diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index 3462bb0..321fa2d 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -8,6 +8,7 @@ #include <QWidget> #include <QMenu> +#include <QList> #include "Swift/Controllers/UIInterfaces/MainWindow.h" #include "Swift/QtUI/QtRosterHeader.h" #include "Swift/QtUI/EventViewer/QtEventWindow.h" @@ -20,12 +21,11 @@ class QLineEdit; class QPushButton; class QToolBar; class QAction; - +class QMenu; class QTabWidget; namespace Swift { - class QtTreeWidget; - class QtTreeWidgetFactory; + class QtRosterWidget; class TreeWidget; class UIEventStream; class QtTabWidget; @@ -35,7 +35,7 @@ namespace Swift { Q_OBJECT public: QtMainWindow(QtSettingsProvider*, UIEventStream* eventStream); - ~QtMainWindow(); + virtual ~QtMainWindow(); std::vector<QMenu*> getMenus() {return menus_;} void setMyNick(const std::string& name); void setMyJID(const JID& jid); @@ -46,6 +46,7 @@ namespace Swift { QtEventWindow* getEventWindow(); QtChatListWindow* getChatListWindow(); void setRosterModel(Roster* roster); + void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands); private slots: void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage); void handleUIEvent(boost::shared_ptr<UIEvent> event); @@ -55,17 +56,22 @@ namespace Swift { void handleEditProfileAction(); void handleAddUserActionTriggered(bool checked); void handleChatUserActionTriggered(bool checked); + void handleAdHocActionTriggered(bool checked); void handleEventCountUpdated(int count); + void handleChatCountUpdated(int count); void handleEditProfileRequest(); + void handleTabChanged(int index); private: + QtSettingsProvider* settings_; std::vector<QMenu*> menus_; - QtTreeWidget* treeWidget_; + QtRosterWidget* treeWidget_; QtRosterHeader* meView_; QAction* addUserAction_; QAction* editUserAction_; QAction* chatUserAction_; QAction* showOfflineAction_; + QMenu* serverAdHocMenu_; QtTabWidget* tabs_; QWidget* contactsTabWidget_; QWidget* eventsTabWidget_; @@ -73,5 +79,7 @@ namespace Swift { QtChatListWindow* chatListWindow_; UIEventStream* uiEventStream_; bool lastOfflineState_; + std::vector<DiscoItems::Item> serverAdHocCommands_; + QList<QAction*> serverAdHocCommandActions_; }; } diff --git a/Swift/QtUI/QtSubscriptionRequestWindow.cpp b/Swift/QtUI/QtSubscriptionRequestWindow.cpp index 7828103..d22cbd0 100644 --- a/Swift/QtUI/QtSubscriptionRequestWindow.cpp +++ b/Swift/QtUI/QtSubscriptionRequestWindow.cpp @@ -28,10 +28,12 @@ QtSubscriptionRequestWindow::QtSubscriptionRequestWindow(boost::shared_ptr<Subsc layout->addWidget(okButton); } else { QPushButton* yesButton = new QPushButton(tr("Yes"), this); + yesButton->setDefault(true); connect(yesButton, SIGNAL(clicked()), this, SLOT(handleYes())); QPushButton* noButton = new QPushButton(tr("No"), this); connect(noButton, SIGNAL(clicked()), this, SLOT(handleNo())); QPushButton* deferButton = new QPushButton(tr("Defer"), this); + deferButton->setShortcut(QKeySequence(Qt::Key_Escape)); connect(deferButton, SIGNAL(clicked()), this, SLOT(handleDefer())); QHBoxLayout* buttonLayout = new QHBoxLayout(); diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index 7830150..57f4175 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -18,13 +18,11 @@ #include "QtUIFactory.h" #include "QtChatWindowFactory.h" #include <Swiften/Base/Log.h> -#include <Swift/Controllers/CertificateFileStorageFactory.h> +#include <Swift/Controllers/Storages/CertificateFileStorageFactory.h> +#include "Swift/Controllers/Storages/FileStoragesFactory.h" #include "SwifTools/Application/PlatformApplicationPathProvider.h" -#include "Swiften/Avatars/AvatarFileStorage.h" -#include "Swiften/Disco/CapsFileStorage.h" #include <string> #include "Swiften/Base/Platform.h" -#include "Swift/Controllers/FileStoragesFactory.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Client/Client.h" #include "Swift/Controllers/MainController.h" @@ -32,20 +30,30 @@ #include "Swift/Controllers/BuildVersion.h" #include "SwifTools/AutoUpdater/AutoUpdater.h" #include "SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h" + #if defined(SWIFTEN_PLATFORM_WINDOWS) #include "WindowsNotifier.h" -#endif -#if defined(HAVE_GROWL) +#elif defined(HAVE_GROWL) #include "SwifTools/Notifier/GrowlNotifier.h" #elif defined(SWIFTEN_PLATFORM_LINUX) #include "FreeDesktopNotifier.h" #else #include "SwifTools/Notifier/NullNotifier.h" #endif + #if defined(SWIFTEN_PLATFORM_MACOSX) #include "SwifTools/Dock/MacOSXDock.h" -#endif +#else #include "SwifTools/Dock/NullDock.h" +#endif + +#if defined(SWIFTEN_PLATFORM_MACOSX) +#include "QtURIHandler.h" +#elif defined(SWIFTEN_PLATFORM_WIN32) +#include <SwifTools/URIHandler/NullURIHandler.h> +#else +#include "QtDBUSURIHandler.h" +#endif namespace Swift{ @@ -66,12 +74,13 @@ po::options_description QtSwift::getOptionsDescription() { ("latency-debug", "Use latency debugging (unsupported)") ("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)") ("start-minimized", "Don't show the login/roster window at startup") + ("eagle-mode", "Settings more suitable for military/secure deployments") ; return result; } -QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(NULL) { +QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(NULL), idleDetector_(&idleQuerier_, networkFactories_.getTimerFactory(), 1000) { if (options.count("netbook-mode")) { splitter_ = new QSplitter(); } else { @@ -96,6 +105,7 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa tabs_ = options.count("no-tabs") && !(splitter_ > 0) ? NULL : new QtChatTabs(); bool startMinimized = options.count("start-minimized") > 0; + bool eagleMode = options.count("eagle-mode") > 0; settings_ = new QtSettingsProvider(); applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME); storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir()); @@ -124,6 +134,14 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa dock_ = new NullDock(); #endif +#if defined(SWIFTEN_PLATFORM_MACOSX) + uriHandler_ = new QtURIHandler(); +#elif defined(SWIFTEN_PLATFORM_WIN32) + uriHandler_ = new NullURIHandler(); +#else + uriHandler_ = new QtDBUSURIHandler(); +#endif + if (splitter_) { splitter_->show(); } @@ -146,7 +164,10 @@ QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMa certificateStorageFactory_, dock_, notifier_, - options.count("latency-debug") > 0); + uriHandler_, + &idleDetector_, + options.count("latency-debug") > 0, + eagleMode); mainControllers_.push_back(mainController); } @@ -173,6 +194,7 @@ QtSwift::~QtSwift() { } delete tabs_; delete splitter_; + delete uriHandler_; delete dock_; delete soundPlayer_; delete chatWindowFactory_; diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h index 978fa14..7f33475 100644 --- a/Swift/QtUI/QtSwift.h +++ b/Swift/QtUI/QtSwift.h @@ -21,6 +21,8 @@ #if defined(SWIFTEN_PLATFORM_WINDOWS) #include "WindowsNotifier.h" #endif +#include "SwifTools/Idle/PlatformIdleQuerier.h" +#include "SwifTools/Idle/ActualIdleDetector.h" namespace po = boost::program_options; @@ -44,6 +46,7 @@ namespace Swift { class QtMUCSearchWindowFactory; class QtUserSearchWindowFactory; class EventLoop; + class URIHandler; class QtSwift : public QObject { Q_OBJECT @@ -63,12 +66,15 @@ namespace Swift { QSplitter* splitter_; QtSoundPlayer* soundPlayer_; Dock* dock_; + URIHandler* uriHandler_; QtChatTabs* tabs_; ApplicationPathProvider* applicationPathProvider_; StoragesFactory* storagesFactory_; CertificateStorageFactory* certificateStorageFactory_; AutoUpdater* autoUpdater_; Notifier* notifier_; + PlatformIdleQuerier idleQuerier_; + ActualIdleDetector idleDetector_; #if defined(SWIFTEN_PLATFORM_MACOSX) CocoaApplication cocoaApplication_; #endif diff --git a/Swift/QtUI/QtTextEdit.cpp b/Swift/QtUI/QtTextEdit.cpp index 3668220..3a62325 100644 --- a/Swift/QtUI/QtTextEdit.cpp +++ b/Swift/QtUI/QtTextEdit.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "QtTextEdit.h" +#include <Swift/QtUI/QtTextEdit.h> #include <QFontMetrics> #include <QKeyEvent> @@ -22,19 +22,25 @@ void QtTextEdit::keyPressEvent(QKeyEvent* event) { if ((key == Qt::Key_Enter || key == Qt::Key_Return) && (modifiers == Qt::NoModifier || modifiers == Qt::KeypadModifier)) { emit returnPressed(); - } else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier) + } + else if (((key == Qt::Key_PageUp || key == Qt::Key_PageDown) && modifiers == Qt::ShiftModifier) || (key == Qt::Key_C && modifiers == Qt::ControlModifier && textCursor().selectedText().isEmpty()) || (key == Qt::Key_W && modifiers == Qt::ControlModifier) || (key == Qt::Key_PageUp && modifiers == Qt::ControlModifier) || (key == Qt::Key_PageDown && modifiers == Qt::ControlModifier) -// || (key == Qt::Key_Left && modifiers == (Qt::ControlModifier | Qt::ShiftModifier)) -// || (key == Qt::Key_Right && modifiers == (Qt::ControlModifier | Qt::ShiftModifier)) || (key == Qt::Key_Tab && modifiers == Qt::ControlModifier) || (key == Qt::Key_A && modifiers == Qt::AltModifier) || (key == Qt::Key_Tab) ) { emit unhandledKeyPressEvent(event); - } else { + } + else if ((key == Qt::Key_Up) + || (key == Qt::Key_Down) + ){ + emit unhandledKeyPressEvent(event); + QTextEdit::keyPressEvent(event); + } + else { QTextEdit::keyPressEvent(event); } } diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp index 35fbfcd..9de700c 100644 --- a/Swift/QtUI/QtUIFactory.cpp +++ b/Swift/QtUI/QtUIFactory.cpp @@ -23,10 +23,15 @@ #include "UserSearch/QtUserSearchWindow.h" #include "QtProfileWindow.h" #include "QtContactEditWindow.h" +#include "QtAdHocCommandWindow.h" +#include "QtFileTransferListWidget.h" + +#define CHATWINDOW_FONT_SIZE "chatWindowFontSize" namespace Swift { QtUIFactory::QtUIFactory(QtSettingsProvider* settings, QtChatTabs* tabs, QSplitter* netbookSplitter, QtSystemTray* systemTray, QtChatWindowFactory* chatWindowFactory, bool startMinimized) : settings(settings), tabs(tabs), netbookSplitter(netbookSplitter), systemTray(systemTray), chatWindowFactory(chatWindowFactory), lastMainWindow(NULL), loginWindow(NULL), startMinimized(startMinimized) { + chatFontSize = settings->getIntSetting(CHATWINDOW_FONT_SIZE, 0); } XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() { @@ -39,6 +44,15 @@ XMLConsoleWidget* QtUIFactory::createXMLConsoleWidget() { return widget; } +FileTransferListWidget* QtUIFactory::createFileTransferListWidget() { + QtFileTransferListWidget* widget = new QtFileTransferListWidget(); + tabs->addTab(widget); + if (!tabs->isVisible()) { + tabs->show(); + } + widget->show(); + return widget; +} MainWindow* QtUIFactory::createMainWindow(UIEventStream* eventStream) { lastMainWindow = new QtMainWindow(settings, eventStream); @@ -80,15 +94,36 @@ MUCSearchWindow* QtUIFactory::createMUCSearchWindow() { } ChatWindow* QtUIFactory::createChatWindow(const JID& contact, UIEventStream* eventStream) { - return chatWindowFactory->createChatWindow(contact, eventStream); + QtChatWindow* window = dynamic_cast<QtChatWindow*>(chatWindowFactory->createChatWindow(contact, eventStream)); + chatWindows.push_back(window); + std::vector<QPointer<QtChatWindow> > deletions; + foreach (QPointer<QtChatWindow> existingWindow, chatWindows) { + if (existingWindow.isNull()) { + deletions.push_back(existingWindow); + } else { + connect(window, SIGNAL(fontResized(int)), existingWindow, SLOT(handleFontResized(int))); + connect(existingWindow, SIGNAL(fontResized(int)), window, SLOT(handleFontResized(int))); + } + } + foreach (QPointer<QtChatWindow> deletedWindow, deletions) { + chatWindows.erase(std::remove(chatWindows.begin(), chatWindows.end(), deletedWindow), chatWindows.end()); + } + connect(window, SIGNAL(fontResized(int)), this, SLOT(handleChatWindowFontResized(int))); + window->handleFontResized(chatFontSize); + return window; +} + +void QtUIFactory::handleChatWindowFontResized(int size) { + chatFontSize = size; + settings->storeInt(CHATWINDOW_FONT_SIZE, size); } UserSearchWindow* QtUIFactory::createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups) { return new QtUserSearchWindow(eventStream, type, groups); }; -JoinMUCWindow* QtUIFactory::createJoinMUCWindow() { - return new QtJoinMUCWindow(); +JoinMUCWindow* QtUIFactory::createJoinMUCWindow(UIEventStream* uiEventStream) { + return new QtJoinMUCWindow(uiEventStream); } ProfileWindow* QtUIFactory::createProfileWindow() { @@ -99,5 +134,8 @@ ContactEditWindow* QtUIFactory::createContactEditWindow() { return new QtContactEditWindow(); } +void QtUIFactory::createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command) { + new QtAdHocCommandWindow(command); +} } diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h index ddaaf6e..8fc5395 100644 --- a/Swift/QtUI/QtUIFactory.h +++ b/Swift/QtUI/QtUIFactory.h @@ -7,6 +7,7 @@ #pragma once #include <QObject> +#include <QPointer> #include <Swift/Controllers/UIInterfaces/UIFactory.h> @@ -20,6 +21,7 @@ namespace Swift { class QtMainWindow; class QtChatTheme; class QtChatWindowFactory; + class QtChatWindow; class QtUIFactory : public QObject, public UIFactory { Q_OBJECT @@ -34,12 +36,15 @@ namespace Swift { virtual MUCSearchWindow* createMUCSearchWindow(); virtual ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream); virtual UserSearchWindow* createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream, const std::set<std::string>& groups); - virtual JoinMUCWindow* createJoinMUCWindow(); + virtual JoinMUCWindow* createJoinMUCWindow(UIEventStream* uiEventStream); virtual ProfileWindow* createProfileWindow(); virtual ContactEditWindow* createContactEditWindow(); + virtual FileTransferListWidget* createFileTransferListWidget(); + virtual void createAdHocCommandWindow(boost::shared_ptr<OutgoingAdHocCommandSession> command); private slots: void handleLoginWindowGeometryChanged(); + void handleChatWindowFontResized(int); private: QtSettingsProvider* settings; @@ -49,6 +54,8 @@ namespace Swift { QtChatWindowFactory* chatWindowFactory; QtMainWindow* lastMainWindow; QtLoginWindow* loginWindow; + std::vector<QPointer<QtChatWindow> > chatWindows; bool startMinimized; + int chatFontSize; }; } diff --git a/Swift/QtUI/QtURIHandler.cpp b/Swift/QtUI/QtURIHandler.cpp new file mode 100644 index 0000000..43f3ed1 --- /dev/null +++ b/Swift/QtUI/QtURIHandler.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "QtURIHandler.h" + +#include <QCoreApplication> +#include <QFileOpenEvent> +#include <QUrl> + +#include "QtSwiftUtil.h" +#ifdef Q_WS_MAC +#include <SwifTools/URIHandler/MacOSXURIHandlerHelpers.h> +#endif + +using namespace Swift; + +QtURIHandler::QtURIHandler() { + qApp->installEventFilter(this); +#ifdef Q_WS_MAC + registerAppAsDefaultXMPPURIHandler(); +#endif +} + +bool QtURIHandler::eventFilter(QObject*, QEvent* event) { + if (event->type() == QEvent::FileOpen) { + QFileOpenEvent* fileOpenEvent = static_cast<QFileOpenEvent*>(event); + if (fileOpenEvent->url().scheme() == "xmpp") { + onURI(Q2PSTRING(fileOpenEvent->url().toString())); + return true; + } + } + return false; +} diff --git a/Swift/QtUI/QtURIHandler.h b/Swift/QtUI/QtURIHandler.h new file mode 100644 index 0000000..a02114a --- /dev/null +++ b/Swift/QtUI/QtURIHandler.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <QObject> +#include <SwifTools/URIHandler/URIHandler.h> + +class QUrl; + +namespace Swift { + class QtURIHandler : public QObject, public URIHandler { + public: + QtURIHandler(); + + private: + bool eventFilter(QObject* obj, QEvent* event); + }; +} diff --git a/Swift/QtUI/QtWebView.cpp b/Swift/QtUI/QtWebView.cpp index 9d12010..d849ce7 100644 --- a/Swift/QtUI/QtWebView.cpp +++ b/Swift/QtUI/QtWebView.cpp @@ -39,9 +39,15 @@ void QtWebView::dragEnterEvent(QDragEnterEvent*) { } +void QtWebView::setFontSizeIsMinimal(bool minimum) { + fontSizeIsMinimal = minimum; +} + void QtWebView::contextMenuEvent(QContextMenuEvent* ev) { // Filter out the relevant actions from the standard actions + QMenu* menu = page()->createStandardContextMenu(); + /* QList<QAction*> actions(menu->actions()); for (int i = 0; i < actions.size(); ++i) { QAction* action = actions.at(i); @@ -55,10 +61,15 @@ void QtWebView::contextMenuEvent(QContextMenuEvent* ev) { if (removeAction) { menu->removeAction(action); } - } + }*/ // Add our own custom actions menu->addAction(tr("Clear"), this, SIGNAL(clearRequested())); + menu->addAction(tr("Increase font size"), this, SIGNAL(fontGrowRequested())); + QAction* shrink = new QAction(tr("Decrease font size"), this); + shrink->setEnabled(!fontSizeIsMinimal); + connect(shrink, SIGNAL(triggered()), this, SIGNAL(fontShrinkRequested())); + menu->addAction(shrink); menu->exec(ev->globalPos()); delete menu; diff --git a/Swift/QtUI/QtWebView.h b/Swift/QtUI/QtWebView.h index fbd31e3..202037f 100644 --- a/Swift/QtUI/QtWebView.h +++ b/Swift/QtUI/QtWebView.h @@ -18,15 +18,19 @@ namespace Swift { void keyPressEvent(QKeyEvent* event); void dragEnterEvent(QDragEnterEvent *event); void contextMenuEvent(QContextMenuEvent* ev); + void setFontSizeIsMinimal(bool minimum); signals: void gotFocus(); void clearRequested(); + void fontGrowRequested(); + void fontShrinkRequested(); protected: void focusInEvent(QFocusEvent* event); private: std::vector<QWebPage::WebAction> filteredActions; + bool fontSizeIsMinimal; }; } diff --git a/Swift/QtUI/QtXMLConsoleWidget.cpp b/Swift/QtUI/QtXMLConsoleWidget.cpp index c1b1d0d..e674df8 100644 --- a/Swift/QtUI/QtXMLConsoleWidget.cpp +++ b/Swift/QtUI/QtXMLConsoleWidget.cpp @@ -51,6 +51,9 @@ QtXMLConsoleWidget::QtXMLConsoleWidget() { emit titleUpdated(); } +QtXMLConsoleWidget::~QtXMLConsoleWidget() { +} + void QtXMLConsoleWidget::showEvent(QShowEvent* event) { emit windowOpening(); emit titleUpdated(); /* This just needs to be somewhere after construction */ @@ -71,12 +74,12 @@ void QtXMLConsoleWidget::closeEvent(QCloseEvent* event) { event->accept(); } -void QtXMLConsoleWidget::handleDataRead(const std::string& data) { - appendTextIfEnabled(std::string(tr("<!-- IN -->").toUtf8()) + "\n" + data + "\n", QColor(33,98,33)); +void QtXMLConsoleWidget::handleDataRead(const SafeByteArray& data) { + appendTextIfEnabled(std::string(tr("<!-- IN -->").toUtf8()) + "\n" + safeByteArrayToString(data) + "\n", QColor(33,98,33)); } -void QtXMLConsoleWidget::handleDataWritten(const std::string& data) { - appendTextIfEnabled(std::string(tr("<!-- OUT -->").toUtf8()) + "\n" + data + "\n", QColor(155,1,0)); +void QtXMLConsoleWidget::handleDataWritten(const SafeByteArray& data) { + appendTextIfEnabled(std::string(tr("<!-- OUT -->").toUtf8()) + "\n" + safeByteArrayToString(data) + "\n", QColor(155,1,0)); } void QtXMLConsoleWidget::appendTextIfEnabled(const std::string& data, const QColor& color) { diff --git a/Swift/QtUI/QtXMLConsoleWidget.h b/Swift/QtUI/QtXMLConsoleWidget.h index a345495..912ad90 100644 --- a/Swift/QtUI/QtXMLConsoleWidget.h +++ b/Swift/QtUI/QtXMLConsoleWidget.h @@ -19,12 +19,13 @@ namespace Swift { public: QtXMLConsoleWidget(); + ~QtXMLConsoleWidget(); void show(); void activate(); - virtual void handleDataRead(const std::string& data); - virtual void handleDataWritten(const std::string& data); + virtual void handleDataRead(const SafeByteArray& data); + virtual void handleDataWritten(const SafeByteArray& data); private: virtual void closeEvent(QCloseEvent* event); diff --git a/Swift/QtUI/Roster/DelegateCommons.cpp b/Swift/QtUI/Roster/DelegateCommons.cpp index 164b80f..290794d 100644 --- a/Swift/QtUI/Roster/DelegateCommons.cpp +++ b/Swift/QtUI/Roster/DelegateCommons.cpp @@ -6,18 +6,102 @@ #include "DelegateCommons.h" +#include <QtScaledAvatarCache.h> +#include <QFileInfo> + namespace Swift { -void DelegateCommons::drawElidedText(QPainter* painter, const QRect& region, const QString& text) { +void DelegateCommons::drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags) { QString adjustedText(painter->fontMetrics().elidedText(text, Qt::ElideRight, region.width(), Qt::TextShowMnemonic)); - painter->drawText(region, Qt::AlignTop, adjustedText); + painter->drawText(region, flags, adjustedText); } +void DelegateCommons::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, int unreadCount) const { + painter->save(); + QRect fullRegion(option.rect); + if ( option.state & QStyle::State_Selected ) { + painter->fillRect(fullRegion, option.palette.highlight()); + painter->setPen(option.palette.highlightedText().color()); + } else { + painter->setPen(QPen(nameColor)); + } + + QRect presenceIconRegion(QPoint(farLeftMargin, fullRegion.top()), QSize(presenceIconWidth, fullRegion.height() - verticalMargin)); + + int calculatedAvatarSize = presenceIconRegion.height(); + //This overlaps the presenceIcon, so must be painted first + QRect avatarRegion(QPoint(presenceIconRegion.right() - presenceIconWidth / 2, presenceIconRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize)); + + QPixmap avatarPixmap; + if (!avatarPath.isEmpty()) { + QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath); + if (QFileInfo(scaledAvatarPath).exists()) { + avatarPixmap.load(scaledAvatarPath); + } + } + if (avatarPixmap.isNull()) { + avatarPixmap = QPixmap(":/icons/avatar.png").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation); + } + + painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap); + + //Paint the presence icon over the top of the avatar + presenceIcon.paint(painter, presenceIconRegion, Qt::AlignBottom | Qt::AlignHCenter); + + QFontMetrics nameMetrics(nameFont); + painter->setFont(nameFont); + int extraFontWidth = nameMetrics.width("H"); + int leftOffset = avatarRegion.right() + horizontalMargin * 2 + extraFontWidth / 2; + QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0/*-leftOffset*/, 0)); + + int nameHeight = nameMetrics.height() + verticalMargin; + QRect nameRegion(textRegion.adjusted(0, verticalMargin, 0, 0)); + + DelegateCommons::drawElidedText(painter, nameRegion, name); + + + painter->setFont(detailFont); + painter->setPen(QPen(QColor(160,160,160))); + + QRect statusTextRegion(textRegion.adjusted(0, nameHeight, 0, 0)); + DelegateCommons::drawElidedText(painter, statusTextRegion, statusText); + + if (unreadCount > 0) { + QRect unreadRect(fullRegion.right() - unreadCountSize - horizontalMargin, fullRegion.top() + (fullRegion.height() - unreadCountSize) / 2, unreadCountSize, unreadCountSize); + QPen pen(QColor("black")); + pen.setWidth(1); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->setPen(pen); + painter->setBrush(QBrush(QColor("red"), Qt::SolidPattern)); + //painter->setBackgroundMode(Qt::OpaqueMode); + painter->drawEllipse(unreadRect); + painter->setBackgroundMode(Qt::TransparentMode); + painter->setPen(QColor("white")); + drawElidedText(painter, unreadRect, QString("%1").arg(unreadCount), Qt::AlignCenter); + } + + painter->restore(); +} + +QSize DelegateCommons::contactSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const { + int heightByAvatar = avatarSize + verticalMargin * 2; + QFontMetrics nameMetrics(nameFont); + QFontMetrics statusMetrics(detailFont); + int sizeByText = 2 * verticalMargin + nameMetrics.height() + statusMetrics.height(); + //Doesn't work, yay! FIXME: why? + //QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2); + //qDebug() << "Returning size" << size; + return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar); +} const int DelegateCommons::horizontalMargin = 2; const int DelegateCommons::verticalMargin = 2; const int DelegateCommons::farLeftMargin = 2; +const int DelegateCommons::avatarSize = 20; +const int DelegateCommons::presenceIconHeight = 16; +const int DelegateCommons::presenceIconWidth = 16; +const int DelegateCommons::unreadCountSize = 16; diff --git a/Swift/QtUI/Roster/DelegateCommons.h b/Swift/QtUI/Roster/DelegateCommons.h index 9213ef5..e5e4ff9 100644 --- a/Swift/QtUI/Roster/DelegateCommons.h +++ b/Swift/QtUI/Roster/DelegateCommons.h @@ -11,6 +11,8 @@ #include <QPainter> #include <QRect> #include <QString> +#include <QIcon> +#include <QStyleOptionViewItem> namespace Swift { class DelegateCommons { @@ -21,7 +23,10 @@ namespace Swift { detailFont.setPointSize(nameFont.pointSize() - detailFontSizeDrop); } - static void drawElidedText(QPainter* painter, const QRect& region, const QString& text); + static void drawElidedText(QPainter* painter, const QRect& region, const QString& text, int flags = Qt::AlignTop); + + QSize contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QColor& nameColor, const QString& avatarPath, const QIcon& presenceIcon, const QString& name, const QString& statusText, int unreadCount) const; int detailFontSizeDrop; QFont nameFont; @@ -29,5 +34,9 @@ namespace Swift { static const int horizontalMargin; static const int verticalMargin; static const int farLeftMargin; + static const int avatarSize; + static const int presenceIconHeight; + static const int presenceIconWidth; + static const int unreadCountSize; }; } diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.cpp b/Swift/QtUI/Roster/QtOccupantListWidget.cpp new file mode 100644 index 0000000..cbda0f1 --- /dev/null +++ b/Swift/QtUI/Roster/QtOccupantListWidget.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#include "Roster/QtOccupantListWidget.h" + +#include <QContextMenuEvent> +#include <QMenu> +#include <QAction> +#include <QInputDialog> + +#include "Swift/Controllers/Roster/ContactRosterItem.h" +#include "Swift/Controllers/Roster/GroupRosterItem.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h" +#include "QtSwiftUtil.h" + +namespace Swift { + +QtOccupantListWidget::QtOccupantListWidget(UIEventStream* eventStream, QWidget* parent) : QtTreeWidget(eventStream, parent) { + +} + +QtOccupantListWidget::~QtOccupantListWidget() { + +} + +void QtOccupantListWidget::setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions) { + availableOccupantActions_ = actions; +} + +void QtOccupantListWidget::contextMenuEvent(QContextMenuEvent* event) { + QModelIndex index = indexAt(event->pos()); + if (!index.isValid()) { + return; + } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact) { + QMenu contextMenu; + std::map<QAction*, ChatWindow::OccupantAction> actions; + foreach (ChatWindow::OccupantAction availableAction, availableOccupantActions_) { + QString text = "Error: missing string"; + switch (availableAction) { + case ChatWindow::Kick: text = tr("Kick user"); break; + } + QAction* action = contextMenu.addAction(text); + actions[action] = availableAction; + } + QAction* result = contextMenu.exec(event->globalPos()); + if (result) { + onOccupantActionSelected(actions[result], contact); + } + } +} + +} + diff --git a/Swift/QtUI/Roster/QtOccupantListWidget.h b/Swift/QtUI/Roster/QtOccupantListWidget.h new file mode 100644 index 0000000..ef29c00 --- /dev/null +++ b/Swift/QtUI/Roster/QtOccupantListWidget.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swift/QtUI/Roster/QtTreeWidget.h" + +#include "Swiften/Base/boost_bsignals.h" +#include "Swift/Controllers/UIInterfaces/ChatWindow.h" + +namespace Swift { + +class QtOccupantListWidget : public QtTreeWidget { + Q_OBJECT + public: + QtOccupantListWidget(UIEventStream* eventStream, QWidget* parent = 0); + virtual ~QtOccupantListWidget(); + void setAvailableOccupantActions(const std::vector<ChatWindow::OccupantAction>& actions); + boost::signal<void (ChatWindow::OccupantAction, ContactRosterItem*)> onOccupantActionSelected; + protected: + void contextMenuEvent(QContextMenuEvent* event); + private: + std::vector<ChatWindow::OccupantAction> availableOccupantActions_; +}; + +} + diff --git a/Swift/QtUI/Roster/QtRosterWidget.cpp b/Swift/QtUI/Roster/QtRosterWidget.cpp new file mode 100644 index 0000000..4c96695 --- /dev/null +++ b/Swift/QtUI/Roster/QtRosterWidget.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Roster/QtRosterWidget.h" + +#include <QContextMenuEvent> +#include <QMenu> +#include <QInputDialog> +#include <QFileDialog> + +#include "Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h" +#include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h" +#include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h" +#include "Swift/Controllers/UIEvents/SendFileUIEvent.h" +#include "QtContactEditWindow.h" +#include "Swift/Controllers/Roster/ContactRosterItem.h" +#include "Swift/Controllers/Roster/GroupRosterItem.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h" +#include "QtSwiftUtil.h" + +namespace Swift { + +QtRosterWidget::QtRosterWidget(UIEventStream* eventStream, QWidget* parent) : QtTreeWidget(eventStream, parent) { + +} + +QtRosterWidget::~QtRosterWidget() { + +} + +void QtRosterWidget::handleEditUserActionTriggered(bool /*checked*/) { + QModelIndexList selectedIndexList = getSelectedIndexes(); + if (selectedIndexList.empty()) { + return; + } + QModelIndex index = selectedIndexList[0]; + if (!index.isValid()) { + return; + } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID())); + } +} + +void QtRosterWidget::contextMenuEvent(QContextMenuEvent* event) { + QModelIndex index = indexAt(event->pos()); + if (!index.isValid()) { + return; + } + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + QMenu contextMenu; + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + QAction* editContact = contextMenu.addAction(tr("Edit")); + QAction* removeContact = contextMenu.addAction(tr("Remove")); +#ifdef SWIFT_EXPERIMENTAL_FT + QAction* sendFile = NULL; + if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { + sendFile = contextMenu.addAction(tr("Send File")); + } +#endif + QAction* result = contextMenu.exec(event->globalPos()); + if (result == editContact) { + eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID())); + } + else if (result == removeContact) { + if (QtContactEditWindow::confirmContactDeletion(contact->getJID())) { + eventStream_->send(boost::make_shared<RemoveRosterItemUIEvent>(contact->getJID())); + } + } +#ifdef SWIFT_EXPERIMENTAL_FT + else if (sendFile && result == sendFile) { + QString fileName = QFileDialog::getOpenFileName(this, tr("Send File"), "", tr("All Files (*);;")); + if (!fileName.isEmpty()) { + eventStream_->send(boost::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(fileName))); + } + } +#endif + } + else if (GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item)) { + QAction* renameGroupAction = contextMenu.addAction(tr("Rename")); + QAction* result = contextMenu.exec(event->globalPos()); + if (result == renameGroupAction) { + renameGroup(group); + } + } +} + +void QtRosterWidget::renameGroup(GroupRosterItem* group) { + bool ok; + QString newName = QInputDialog::getText(NULL, tr("Rename group"), tr("Enter a new name for group '%1':").arg(P2QSTRING(group->getDisplayName())), QLineEdit::Normal, P2QSTRING(group->getDisplayName()), &ok); + if (ok) { + eventStream_->send(boost::make_shared<RenameGroupUIEvent>(group->getDisplayName(), Q2PSTRING(newName))); + } +} + +} diff --git a/Swift/QtUI/Roster/QtRosterWidget.h b/Swift/QtUI/Roster/QtRosterWidget.h new file mode 100644 index 0000000..f870237 --- /dev/null +++ b/Swift/QtUI/Roster/QtRosterWidget.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swift/QtUI/Roster/QtTreeWidget.h" + +namespace Swift { +class QtRosterWidget : public QtTreeWidget { + Q_OBJECT + public: + QtRosterWidget(UIEventStream* eventStream, QWidget* parent = 0); + virtual ~QtRosterWidget(); + public slots: + void handleEditUserActionTriggered(bool checked); + protected: + void contextMenuEvent(QContextMenuEvent* event); + private: + void renameGroup(GroupRosterItem* group); +}; + +} diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp index 1296872..690515d 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.cpp +++ b/Swift/QtUI/Roster/QtTreeWidget.cpp @@ -6,25 +6,21 @@ #include "Roster/QtTreeWidget.h" -#include <QMenu> -#include <QContextMenuEvent> -#include <QInputDialog> #include <boost/smart_ptr/make_shared.hpp> +#include <QUrl> + #include "Swiften/Base/Platform.h" #include "Swift/Controllers/Roster/ContactRosterItem.h" #include "Swift/Controllers/Roster/GroupRosterItem.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" -#include "Swift/Controllers/UIEvents/RequestContactEditorUIEvent.h" -#include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h" -#include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h" +#include "Swift/Controllers/UIEvents/SendFileUIEvent.h" #include "QtSwiftUtil.h" -#include "QtContactEditWindow.h" namespace Swift { -QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, QWidget* parent) : QTreeView(parent), editable_(false) { +QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, QWidget* parent) : QTreeView(parent) { eventStream_ = eventStream; model_ = new RosterModel(this); setModel(model_); @@ -38,6 +34,9 @@ QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, QWidget* parent) : QTreeV expandAll(); setAnimated(true); setIndentation(0); +#ifdef SWIFT_EXPERIMENTAL_FT + setAcceptDrops(true); +#endif setRootIsDecorated(true); connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&))); connect(model_, SIGNAL(itemExpanded(const QModelIndex&, bool)), this, SLOT(handleModelItemExpanded(const QModelIndex&, bool))); @@ -89,21 +88,20 @@ QModelIndexList QtTreeWidget::getSelectedIndexes() const { } void QtTreeWidget::currentChanged(const QModelIndex& current, const QModelIndex& previous) { - bool valid = false; + RosterItem* item = NULL; QModelIndexList selectedIndexList = getSelectedIndexes(); - if (!editable_ || selectedIndexList.empty() || !selectedIndexList[0].isValid()) { + if (selectedIndexList.empty() || !selectedIndexList[0].isValid()) { /* I didn't quite understand why using current didn't seem to work here.*/ } else if (current.isValid()) { - RosterItem* item = static_cast<RosterItem*>(current.internalPointer()); - if (dynamic_cast<ContactRosterItem*>(item)) { - valid = true; - } + item = static_cast<RosterItem*>(current.internalPointer()); + item = dynamic_cast<ContactRosterItem*>(item); } - onSomethingSelectedChanged(valid); + onSomethingSelectedChanged(item); QTreeView::currentChanged(current, previous); } + void QtTreeWidget::handleItemActivated(const QModelIndex& index) { RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); @@ -112,62 +110,39 @@ void QtTreeWidget::handleItemActivated(const QModelIndex& index) { } } -void QtTreeWidget::handleEditUserActionTriggered(bool /*checked*/) { - if (!editable_) { - return; - } - QModelIndexList selectedIndexList = getSelectedIndexes(); - if (selectedIndexList.empty()) { - return; - } - QModelIndex index = selectedIndexList[0]; - if (!index.isValid()) { - return; - } - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { - eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID())); +void QtTreeWidget::dragEnterEvent(QDragEnterEvent *event) { + if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) { + event->acceptProposedAction(); } } -void QtTreeWidget::contextMenuEvent(QContextMenuEvent* event) { - if (!editable_) { - return; - } +void QtTreeWidget::dropEvent(QDropEvent *event) { QModelIndex index = indexAt(event->pos()); - if (!index.isValid()) { - return; - } - RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); - QMenu contextMenu; - if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { - QAction* editContact = contextMenu.addAction(tr("Edit")); - QAction* removeContact = contextMenu.addAction(tr("Remove")); - QAction* result = contextMenu.exec(event->globalPos()); - if (result == editContact) { - eventStream_->send(boost::make_shared<RequestContactEditorUIEvent>(contact->getJID())); - } - else if (result == removeContact) { - if (QtContactEditWindow::confirmContactDeletion(contact->getJID())) { - eventStream_->send(boost::make_shared<RemoveRosterItemUIEvent>(contact->getJID())); + if (index.isValid()) { + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { + QString filename = event->mimeData()->urls().at(0).toLocalFile(); + if (!filename.isEmpty()) { + eventStream_->send(boost::make_shared<SendFileUIEvent>(contact->getJID(), Q2PSTRING(filename))); + } } } } - else if (GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item)) { - QAction* renameGroupAction = contextMenu.addAction(tr("Rename")); - QAction* result = contextMenu.exec(event->globalPos()); - if (result == renameGroupAction) { - renameGroup(group); - } - } } -void QtTreeWidget::renameGroup(GroupRosterItem* group) { - bool ok; - QString newName = QInputDialog::getText(NULL, tr("Rename group"), tr("Enter a new name for group '%1':").arg(P2QSTRING(group->getDisplayName())), QLineEdit::Normal, P2QSTRING(group->getDisplayName()), &ok); - if (ok) { - eventStream_->send(boost::make_shared<RenameGroupUIEvent>(group->getDisplayName(), Q2PSTRING(newName))); +void QtTreeWidget::dragMoveEvent(QDragMoveEvent* event) { + QModelIndex index = indexAt(event->pos()); + if (index.isValid()) { + RosterItem* item = static_cast<RosterItem*>(index.internalPointer()); + if (ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item)) { + if (contact->supportsFeature(ContactRosterItem::FileTransferFeature)) { + event->accept(); + return; + } + } } + event->ignore(); } void QtTreeWidget::handleExpanded(const QModelIndex& index) { diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h index 4ecba83..271fbd5 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.h +++ b/Swift/QtUI/Roster/QtTreeWidget.h @@ -8,6 +8,9 @@ #include <QTreeView> #include <QModelIndex> +#include <QDragEnterEvent> +#include <QDropEvent> +#include <QDragMoveEvent> #include "Swift/QtUI/Roster/RosterModel.h" #include "Swift/QtUI/Roster/RosterDelegate.h" @@ -23,13 +26,7 @@ class QtTreeWidget : public QTreeView{ QtTreeWidgetItem* getRoot(); void setRosterModel(Roster* roster); Roster* getRoster() {return roster_;} - void setEditable(bool b) { editable_ = b; } - - signals: - void onSomethingSelectedChanged(bool); - - public slots: - void handleEditUserActionTriggered(bool checked); + boost::signal<void (RosterItem*)> onSomethingSelectedChanged; private slots: void handleItemActivated(const QModelIndex&); @@ -38,22 +35,24 @@ class QtTreeWidget : public QTreeView{ void handleCollapsed(const QModelIndex&); void handleClicked(const QModelIndex&); protected: - void contextMenuEvent(QContextMenuEvent* event); - protected slots: - virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); + void dragEnterEvent(QDragEnterEvent* event); + void dropEvent(QDropEvent* event); + void dragMoveEvent(QDragMoveEvent* event); + protected: + QModelIndexList getSelectedIndexes() const; private: - void renameGroup(GroupRosterItem* group); void drawBranches(QPainter*, const QRect&, const QModelIndex&) const; - QModelIndexList getSelectedIndexes() const; - + protected slots: + virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); + protected: + UIEventStream* eventStream_; + private: RosterModel* model_; Roster* roster_; RosterDelegate* delegate_; QtTreeWidgetItem* treeRoot_; - UIEventStream* eventStream_; - bool editable_; }; } diff --git a/Swift/QtUI/Roster/QtTreeWidgetItem.cpp b/Swift/QtUI/Roster/QtTreeWidgetItem.cpp deleted file mode 100644 index fcd8691..0000000 --- a/Swift/QtUI/Roster/QtTreeWidgetItem.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swift/QtUI/Roster/QtTreeWidgetItem.h" -#include "Swift/QtUI/Roster/QtTreeWidget.h" - -#include <qdebug.h> -#include <QtAlgorithms> -#include <algorithm> - -namespace Swift { - -QtTreeWidgetItem::QtTreeWidgetItem(QtTreeWidgetItem* parentItem) : QObject(), textColor_(0,0,0), backgroundColor_(255,255,255) { - parent_ = parentItem; - shown_ = true; - expanded_ = true; -} - - -void QtTreeWidgetItem::setText(const std::string& text) { - displayName_ = P2QSTRING(text); - displayNameLower_ = displayName_.toLower(); - emit changed(this); -} - -void QtTreeWidgetItem::setStatusText(const std::string& text) { - statusText_ = P2QSTRING(text); - emit changed(this); -} - -void QtTreeWidgetItem::setAvatarPath(const std::string& path) { - avatar_ = QIcon(P2QSTRING(path)); - emit changed(this); -} - -void QtTreeWidgetItem::setStatusShow(StatusShow::Type show) { - statusShowType_ = show; - int color = 0; - switch (show) { - case StatusShow::Online: color = 0x000000; mergedShowType_ = StatusShow::Online; break; - case StatusShow::Away: color = 0x336699; mergedShowType_ = StatusShow::Away; break; - case StatusShow::XA: color = 0x336699; mergedShowType_ = StatusShow::Away; break; - case StatusShow::FFC: color = 0x000000; mergedShowType_ = StatusShow::Online; break; - case StatusShow::DND: color = 0x990000; mergedShowType_ = show; break; - case StatusShow::None: color = 0x7F7F7F; mergedShowType_ = show; break; - } - setTextColor(color); - emit changed(this); -} - -void QtTreeWidgetItem::setTextColor(unsigned long color) { - textColor_ = QColor( - ((color & 0xFF0000)>>16), - ((color & 0xFF00)>>8), - (color & 0xFF)); -} - -void QtTreeWidgetItem::setBackgroundColor(unsigned long color) { - backgroundColor_ = QColor( - ((color & 0xFF0000)>>16), - ((color & 0xFF00)>>8), - (color & 0xFF)); -} - -void QtTreeWidgetItem::setExpanded(bool expanded) { - expanded_ = expanded; - emit changed(this); -} - -void QtTreeWidgetItem::hide() { - shown_ = false; - emit changed(this); -} - -void QtTreeWidgetItem::show() { - shown_ = true; - emit changed(this); -} - -bool QtTreeWidgetItem::isShown() { - return isContact() ? shown_ : shownChildren_.size() > 0; -} - -QWidget* QtTreeWidgetItem::getCollapsedRosterWidget() { - QWidget* widget = new QWidget(); - return widget; -} - -QWidget* QtTreeWidgetItem::getExpandedRosterWidget() { - QWidget* widget = new QWidget(); - return widget; -} - -QtTreeWidgetItem::~QtTreeWidgetItem() { - //It's possible (due to the way the roster deletes items in unknown order when it is deleted) - // That the children will be deleted before the groups, or that the groups are deleted - // before the children. If the children are deleted first, they will let the parent know that - // They've been deleted. If the parent is deleted first, it must tell the children not to - // tell it when they're deleted. Everything will be deleted in the end, because all the - // widgets are owned by the Roster in Swiften. - if (parent_) { - parent_->removeChild(this); - } - - for (int i = 0; i < children_.size(); i++) { - children_[i]->parentItemHasBeenDeleted(); - } -} - -void QtTreeWidgetItem::parentItemHasBeenDeleted() { - parent_ = NULL; -} - -QtTreeWidgetItem* QtTreeWidgetItem::getParentItem() { - return parent_; -} - -void QtTreeWidgetItem::addChild(QtTreeWidgetItem* child) { - children_.append(child); - connect(child, SIGNAL(changed(QtTreeWidgetItem*)), this, SLOT(handleChanged(QtTreeWidgetItem*))); - handleChanged(child); -} - -void QtTreeWidgetItem::removeChild(QtTreeWidgetItem* child) { - children_.removeAll(child); - handleChanged(this); -} - -void bubbleSort(QList<QtTreeWidgetItem*>& list) { - bool done = false; - for (int i = 0; i < list.size() - 1 && !done; i++) { - done = true; - for (int j = i + 1; j < list.size(); j++) { - if (*(list[j]) < *(list[j - 1])) { - done = false; - QtTreeWidgetItem* lower = list[j]; - list[j] = list[j - 1]; - list[j - 1] = lower; - } - } - } -} - -void QtTreeWidgetItem::handleChanged(QtTreeWidgetItem* child) { - /*We don't use the much faster qStableSort because it causes changed(child) and all sorts of nasty recursion*/ - //qStableSort(children_.begin(), children_.end(), itemLessThan); - //bubbleSort(children_); - std::stable_sort(children_.begin(), children_.end(), itemLessThan); - shownChildren_.clear(); - for (int i = 0; i < children_.size(); i++) { - if (children_[i]->isShown()) { - shownChildren_.append(children_[i]); - } - } - emit changed(child); -} - -int QtTreeWidgetItem::rowCount() { - //qDebug() << "Returning size of " << children_.size() << " for item " << displayName_; - return shownChildren_.size(); -} - -int QtTreeWidgetItem::rowOf(QtTreeWidgetItem* item) { - return shownChildren_.indexOf(item); -} - -int QtTreeWidgetItem::row() { - return parent_ ? parent_->rowOf(this) : 0; -} - -QtTreeWidgetItem* QtTreeWidgetItem::getItem(int row) { - //qDebug() << "Returning row " << row << " from item " << displayName_; - Q_ASSERT(row >= 0); - Q_ASSERT(row < rowCount()); - return shownChildren_[row]; -} - - -QVariant QtTreeWidgetItem::data(int role) { - if (!isContact()) { - setTextColor(0xFFFFFF); - setBackgroundColor(0x969696); - } - switch (role) { - case Qt::DisplayRole: return displayName_; - case Qt::TextColorRole: return textColor_; - case Qt::BackgroundColorRole: return backgroundColor_; - case Qt::ToolTipRole: return isContact() ? toolTipString() : QVariant(); - case StatusTextRole: return statusText_; - case AvatarRole: return avatar_; - case PresenceIconRole: return getPresenceIcon(); - default: return QVariant(); - } -} - -QString QtTreeWidgetItem::toolTipString() { - return displayName_ + "\n " + statusText_; -} - -QIcon QtTreeWidgetItem::getPresenceIcon() { - QString iconString; - switch (statusShowType_) { - case StatusShow::Online: iconString = "online";break; - case StatusShow::Away: iconString = "away";break; - case StatusShow::XA: iconString = "away";break; - case StatusShow::FFC: iconString = "online";break; - case StatusShow::DND: iconString = "dnd";break; - case StatusShow::None: iconString = "offline";break; - } - return QIcon(":/icons/" + iconString + ".png"); -} - -bool QtTreeWidgetItem::isContact() const { - return children_.size() == 0; -} - -bool QtTreeWidgetItem::isExpanded() { - return expanded_; -} - -bool QtTreeWidgetItem::operator<(const QtTreeWidgetItem& item) const { - if (isContact()) { - if (!item.isContact()) { - return false; - } - return getStatusShowMerged() == item.getStatusShowMerged() ? getLowerName() < item.getLowerName() : getStatusShowMerged() < item.getStatusShowMerged(); - } else { - if (item.isContact()) { - return true; - } - return getLowerName() < item.getLowerName(); - } -} - -bool itemLessThan(QtTreeWidgetItem* left, QtTreeWidgetItem* right) { - return *left < *right; -} - -} diff --git a/Swift/QtUI/Roster/QtTreeWidgetItem.h b/Swift/QtUI/Roster/QtTreeWidgetItem.h deleted file mode 100644 index 6855989..0000000 --- a/Swift/QtUI/Roster/QtTreeWidgetItem.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <QColor> -#include <QVariant> -#include <string> - -#include "Swiften/Roster/TreeWidgetFactory.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetItem.h" -#include "Swift/QtUI/QtSwiftUtil.h" - -namespace Swift { - enum RosterRoles { - StatusTextRole = Qt::UserRole, - AvatarRole = Qt::UserRole + 1, - PresenceIconRole = Qt::UserRole + 2, - StatusShowTypeRole = Qt::UserRole + 3 - }; - -class QtTreeWidget; -class QtTreeWidgetItem : public QObject, public TreeWidgetItem { - Q_OBJECT - public: - ~QtTreeWidgetItem(); - void addChild(QtTreeWidgetItem* child); - void removeChild(QtTreeWidgetItem* child); - QtTreeWidgetItem* getParentItem(); - int rowCount(); - int rowOf(QtTreeWidgetItem* item); - int row(); - QtTreeWidgetItem* getItem(int row); - QVariant data(int role); - QIcon getPresenceIcon(); - QtTreeWidgetItem(QtTreeWidgetItem* parentItem); - void setText(const std::string& text); - void setAvatarPath(const std::string& path); - void setStatusText(const std::string& text); - void setStatusShow(StatusShow::Type show); - void setTextColor(unsigned long color); - void setBackgroundColor(unsigned long color); - void setExpanded(bool b); - void parentItemHasBeenDeleted(); - void hide(); - void show(); - bool isShown(); - bool isContact() const; - bool isExpanded(); - const QString& getName() const {return displayName_;}; - const QString& getLowerName() const {return displayNameLower_;}; - StatusShow::Type getStatusShow() const {return statusShowType_;}; - StatusShow::Type getStatusShowMerged() const {return mergedShowType_;}; - - QWidget* getCollapsedRosterWidget(); - QWidget* getExpandedRosterWidget(); - bool operator<(const QtTreeWidgetItem& item) const; - - signals: - void changed(QtTreeWidgetItem*); - private slots: - void handleChanged(QtTreeWidgetItem* item); - private: - QString toolTipString(); - QList<QtTreeWidgetItem*> children_; - QList<QtTreeWidgetItem*> shownChildren_; - QtTreeWidgetItem* parent_; - QString displayName_; - QString displayNameLower_; - QString statusText_; - QColor textColor_; - QColor backgroundColor_; - QVariant avatar_; - bool shown_; - bool expanded_; - StatusShow::Type statusShowType_; - StatusShow::Type mergedShowType_; -}; - -bool itemLessThan(QtTreeWidgetItem* left, QtTreeWidgetItem* right); - -} diff --git a/Swift/QtUI/Roster/RosterDelegate.cpp b/Swift/QtUI/Roster/RosterDelegate.cpp index aaa6236..e40907a 100644 --- a/Swift/QtUI/Roster/RosterDelegate.cpp +++ b/Swift/QtUI/Roster/RosterDelegate.cpp @@ -12,7 +12,6 @@ #include <QBrush> #include <QFontMetrics> #include <QPainterPath> -#include <QFileInfo> #include <QPolygon> #include <qdebug.h> #include <QBitmap> @@ -22,7 +21,6 @@ #include "QtTreeWidget.h" #include "RosterModel.h" -#include "QtScaledAvatarCache.h" namespace Swift { @@ -43,15 +41,8 @@ QSize RosterDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelI return contactSizeHint(option, index); } -QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const { - int heightByAvatar = avatarSize_ + common_.verticalMargin * 2; - QFontMetrics nameMetrics(common_.nameFont); - QFontMetrics statusMetrics(common_.detailFont); - int sizeByText = 2 * common_.verticalMargin + nameMetrics.height() + statusMetrics.height(); - //Doesn't work, yay! FIXME: why? - //QSize size = (option.state & QStyle::State_Selected) ? QSize(150, 80) : QSize(150, avatarSize_ + margin_ * 2); - //qDebug() << "Returning size" << size; - return QSize(150, sizeByText > heightByAvatar ? sizeByText : heightByAvatar); +QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const { + return common_.contactSizeHint(option, index); } void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { @@ -70,70 +61,18 @@ void RosterDelegate::paintGroup(QPainter* painter, const QStyleOptionViewItem& o } void RosterDelegate::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - //qDebug() << "painting" << index.data(Qt::DisplayRole).toString(); - painter->save(); - //QStyledItemDelegate::paint(painter, option, index); - //initStyleOption(option, index); - QRect fullRegion(option.rect); - if ( option.state & QStyle::State_Selected ) { - painter->fillRect(fullRegion, option.palette.highlight()); - painter->setPen(option.palette.highlightedText().color()); - } else { - QColor nameColor = index.data(Qt::TextColorRole).value<QColor>(); - painter->setPen(QPen(nameColor)); - } - - QRect presenceIconRegion(QPoint(common_.farLeftMargin, fullRegion.top()), QSize(presenceIconWidth_, fullRegion.height() - common_.verticalMargin)); - - int calculatedAvatarSize = presenceIconRegion.height(); - //This overlaps the presenceIcon, so must be painted first - QRect avatarRegion(QPoint(presenceIconRegion.right() - presenceIconWidth_ / 2, presenceIconRegion.top()), QSize(calculatedAvatarSize, calculatedAvatarSize)); - - QPixmap avatarPixmap; + QColor nameColor = index.data(Qt::TextColorRole).value<QColor>(); + QString avatarPath; if (index.data(AvatarRole).isValid() && !index.data(AvatarRole).value<QString>().isNull()) { - QString avatarPath = index.data(AvatarRole).value<QString>(); - QString scaledAvatarPath = QtScaledAvatarCache(avatarRegion.height()).getScaledAvatarPath(avatarPath); - if (QFileInfo(scaledAvatarPath).exists()) { - avatarPixmap.load(scaledAvatarPath); - } + avatarPath = index.data(AvatarRole).value<QString>(); } - if (avatarPixmap.isNull()) { - avatarPixmap = QPixmap(":/icons/avatar.png").scaled(avatarRegion.height(), avatarRegion.width(), Qt::KeepAspectRatio, Qt::SmoothTransformation); - } - - painter->drawPixmap(avatarRegion.topLeft() + QPoint(((avatarRegion.width() - avatarPixmap.width()) / 2), (avatarRegion.height() - avatarPixmap.height()) / 2), avatarPixmap); - - //Paint the presence icon over the top of the avatar QIcon presenceIcon = index.data(PresenceIconRole).isValid() && !index.data(PresenceIconRole).value<QIcon>().isNull() - ? index.data(PresenceIconRole).value<QIcon>() - : QIcon(":/icons/offline.png"); - presenceIcon.paint(painter, presenceIconRegion, Qt::AlignBottom | Qt::AlignHCenter); - - QFontMetrics nameMetrics(common_.nameFont); - painter->setFont(common_.nameFont); - int extraFontWidth = nameMetrics.width("H"); - int leftOffset = avatarRegion.right() + common_.horizontalMargin * 2 + extraFontWidth / 2; - QRect textRegion(fullRegion.adjusted(leftOffset, 0, 0/*-leftOffset*/, 0)); - - int nameHeight = nameMetrics.height() + common_.verticalMargin; - QRect nameRegion(textRegion.adjusted(0, common_.verticalMargin, 0, 0)); - - DelegateCommons::drawElidedText(painter, nameRegion, index.data(Qt::DisplayRole).toString()); - - - painter->setFont(common_.detailFont); - painter->setPen(QPen(QColor(160,160,160))); - - QRect statusTextRegion(textRegion.adjusted(0, nameHeight, 0, 0)); - DelegateCommons::drawElidedText(painter, statusTextRegion, index.data(StatusTextRole).toString()); - - painter->restore(); + ? index.data(PresenceIconRole).value<QIcon>() + : QIcon(":/icons/offline.png"); + QString name = index.data(Qt::DisplayRole).toString(); + QString statusText = index.data(StatusTextRole).toString(); + common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, 0); } - -const int RosterDelegate::avatarSize_ = 20; -const int RosterDelegate::presenceIconHeight_ = 16; -const int RosterDelegate::presenceIconWidth_ = 16; - } diff --git a/Swift/QtUI/Roster/RosterDelegate.h b/Swift/QtUI/Roster/RosterDelegate.h index e6a16f2..253c11a 100644 --- a/Swift/QtUI/Roster/RosterDelegate.h +++ b/Swift/QtUI/Roster/RosterDelegate.h @@ -28,9 +28,5 @@ namespace Swift { DelegateCommons common_; GroupItemDelegate* groupDelegate_; QtTreeWidget* tree_; - static const int avatarSize_; - static const int presenceIconHeight_; - static const int presenceIconWidth_; - }; } diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 494731c..82e4490 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -25,16 +25,12 @@ myenv.MergeFlags(env["SWIFT_CONTROLLERS_FLAGS"]) myenv.MergeFlags(env["SWIFTOOLS_FLAGS"]) if myenv["HAVE_XSS"] : myenv.MergeFlags(env["XSS_FLAGS"]) +if env["PLATFORM"] == "posix" : + myenv.Append(LIBS = ["X11"]) if myenv["HAVE_SPARKLE"] : myenv.MergeFlags(env["SPARKLE_FLAGS"]) myenv.MergeFlags(env["SWIFTEN_FLAGS"]) -myenv.MergeFlags(env["LIBIDN_FLAGS"]) -myenv.MergeFlags(env["BOOST_FLAGS"]) -myenv.MergeFlags(env.get("SQLITE_FLAGS", {})) -myenv.MergeFlags(env["ZLIB_FLAGS"]) -myenv.MergeFlags(env["OPENSSL_FLAGS"]) -myenv.MergeFlags(env.get("LIBXML_FLAGS", "")) -myenv.MergeFlags(env.get("EXPAT_FLAGS", "")) +myenv.MergeFlags(env["SWIFTEN_DEP_FLAGS"]) if myenv.get("HAVE_GROWL", False) : myenv.MergeFlags(myenv["GROWL_FLAGS"]) myenv.Append(CPPDEFINES = ["HAVE_GROWL"]) @@ -59,7 +55,7 @@ if env["PLATFORM"] == "win32" : myenv.Append(LINKFLAGS = ["/SUBSYSTEM:WINDOWS"]) myenv.Append(LIBS = "qtmain") -myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("../resources/themes/Default")))) +myenv.WriteVal("DefaultTheme.qrc", myenv.Value(generateDefaultTheme(myenv.Dir("#/Swift/resources/themes/Default")))) sources = [ "main.cpp", @@ -77,6 +73,7 @@ sources = [ "QtStatusWidget.cpp", "QtScaledAvatarCache.cpp", "QtSwift.cpp", + "QtURIHandler.cpp", "QtChatView.cpp", "QtChatTheme.cpp", "QtChatTabs.cpp", @@ -87,6 +84,9 @@ sources = [ "QtTabWidget.cpp", "QtTextEdit.cpp", "QtXMLConsoleWidget.cpp", + "QtFileTransferListWidget.cpp", + "QtFileTransferListItemModel.cpp", + "QtAdHocCommandWindow.cpp", "QtUtilities.cpp", "QtBookmarkDetailWindow.cpp", "QtAddBookmarkWindow.cpp", @@ -97,6 +97,7 @@ sources = [ "MessageSnippet.cpp", "SystemMessageSnippet.cpp", "QtElidingLabel.cpp", + "QtFormWidget.cpp", "QtLineEdit.cpp", "QtJoinMUCWindow.cpp", "Roster/RosterModel.cpp", @@ -105,6 +106,8 @@ sources = [ "Roster/RosterDelegate.cpp", "Roster/GroupItemDelegate.cpp", "Roster/DelegateCommons.cpp", + "Roster/QtRosterWidget.cpp", + "Roster/QtOccupantListWidget.cpp", "EventViewer/EventModel.cpp", "EventViewer/EventDelegate.cpp", "EventViewer/TwoLineDelegate.cpp", @@ -114,6 +117,7 @@ sources = [ "ChatList/ChatListModel.cpp", "ChatList/ChatListDelegate.cpp", "ChatList/ChatListMUCItem.cpp", + "ChatList/ChatListRecentItem.cpp", "MUCSearch/QtMUCSearchWindow.cpp", "MUCSearch/MUCSearchModel.cpp", "MUCSearch/MUCSearchRoomItem.cpp", @@ -131,25 +135,38 @@ sources = [ "QtWebView.cpp", "qrc_DefaultTheme.cc", "qrc_Swift.cc", + "QtFileTransferJSBridge.cpp", + "QtMUCConfigurationWindow.cpp", ] myenv["SWIFT_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") if env["PLATFORM"] == "win32" : - myenv.RES("../resources/Windows/Swift.rc") + res = myenv.RES("#/Swift/resources/Windows/Swift.rc") + # For some reason, SCons isn't picking up the dependency correctly + # Adding it explicitly until i figure out why + myenv.Depends(res, "../Controllers/BuildVersion.h") sources += [ "WindowsNotifier.cpp", - "../resources/Windows/Swift.res" + "#/Swift/resources/Windows/Swift.res" ] if env["PLATFORM"] == "posix" : - sources += ["FreeDesktopNotifier.cpp"] + sources += [ + "FreeDesktopNotifier.cpp", + "QtDBUSURIHandler.cpp", + ] if env["PLATFORM"] == "darwin" or env["PLATFORM"] == "win32" : swiftProgram = myenv.Program("Swift", sources) else : swiftProgram = myenv.Program("swift", sources) +if env["PLATFORM"] != "darwin" and env["PLATFORM"] != "win32" : + openURIProgram = myenv.Program("swift-open-uri", "swift-open-uri.cpp") +else : + openURIProgram = [] + myenv.Uic4("MUCSearch/QtMUCSearchWindow.ui") myenv.Uic4("UserSearch/QtUserSearchWizard.ui") myenv.Uic4("UserSearch/QtUserSearchFirstPage.ui") @@ -162,7 +179,7 @@ myenv.Qrc("Swift.qrc") # Resources commonResources = { - "": ["../resources/sounds"] + "": ["#/Swift/resources/sounds"] } ################################################################################ @@ -171,16 +188,16 @@ commonResources = { # Collect available languages translation_languages = [] -for file in os.listdir(Dir("../Translations").abspath) : +for file in os.listdir(Dir("#/Swift/Translations").abspath) : if file.startswith("swift_") and file.endswith(".ts") : translation_languages.append(file[6:-3]) # Generate translation modules -translation_sources = [env.File("../Translations/swift.ts").abspath] +translation_sources = [env.File("#/Swift/Translations/swift.ts").abspath] translation_modules = [] for lang in translation_languages : - translation_resource = "../resources/translations/swift_" + lang + ".qm" - translation_source = "../Translations/swift_" + lang + ".ts" + translation_resource = "#/Swift/resources/translations/swift_" + lang + ".qm" + translation_source = "#/Swift/Translations/swift_" + lang + ".ts" translation_sources.append(env.File(translation_source).abspath) translation_modules.append(env.File(translation_resource).abspath) myenv.Qm(translation_resource, translation_source) @@ -214,20 +231,20 @@ if env["PLATFORM"] == "darwin" : frameworks.append(env["SPARKLE_FRAMEWORK"]) if env["HAVE_GROWL"] : frameworks.append(env["GROWL_FRAMEWORK"]) - commonResources[""] = commonResources.get("", []) + ["../resources/MacOSX/Swift.icns"] - app = myenv.AppBundle("Swift", version = myenv["SWIFT_VERSION"], resources = commonResources, frameworks = frameworks) + commonResources[""] = commonResources.get("", []) + ["#/Swift/resources/MacOSX/Swift.icns"] + app = myenv.AppBundle("Swift", version = myenv["SWIFT_VERSION"], resources = commonResources, frameworks = frameworks, handlesXMPPURIs = True) if env["DIST"] : myenv.Command(["Swift-${SWIFT_VERSION}.dmg"], [app], ["Swift/Packaging/MacOSX/package.sh " + app.path + " Swift/Packaging/MacOSX/Swift.dmg.gz $TARGET $QTDIR"]) if env.get("SWIFT_INSTALLDIR", "") : - env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram) - env.InstallAs(os.path.join(env["SWIFT_INSTALLDIR"], "share", "pixmaps", "swift.xpm"), "../resources/logo/logo-icon-32.xpm") + env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "bin"), swiftProgram + openURIProgram) + env.InstallAs(os.path.join(env["SWIFT_INSTALLDIR"], "share", "pixmaps", "swift.xpm"), "#/Swift/resources/logo/logo-icon-32.xpm") icons_path = os.path.join(env["SWIFT_INSTALLDIR"], "share", "icons", "hicolor") - env.InstallAs(os.path.join(icons_path, "32x32", "apps", "swift.xpm"), "../resources/logo/logo-icon-32.xpm") - env.InstallAs(os.path.join(icons_path, "scalable", "apps", "swift.svg"), "../resources/logo/logo-icon.svg") + env.InstallAs(os.path.join(icons_path, "32x32", "apps", "swift.xpm"), "#/Swift/resources/logo/logo-icon-32.xpm") + env.InstallAs(os.path.join(icons_path, "scalable", "apps", "swift.svg"), "#/Swift/resources/logo/logo-icon.svg") for i in ["16", "22", "24", "64", "128"] : - env.InstallAs(os.path.join(icons_path, i + "x" + i, "apps", "swift.png"), "../resources/logo/logo-icon-" + i + ".png") - env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "applications"), "../resources/swift.desktop") + env.InstallAs(os.path.join(icons_path, i + "x" + i, "apps", "swift.png"), "#/Swift/resources/logo/logo-icon-" + i + ".png") + env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "applications"), "#/Swift/resources/swift.desktop") for dir, resource in commonResources.items() : env.Install(os.path.join(env["SWIFT_INSTALLDIR"], "share", "swift", dir), resource) @@ -236,7 +253,7 @@ if env["PLATFORM"] == "win32" : commonResources[""] = commonResources.get("", []) + [ os.path.join(env["OPENSSL_DIR"], "bin", "ssleay32.dll"), os.path.join(env["OPENSSL_DIR"], "bin", "libeay32.dll"), - "../resources/images", + "#/Swift/resources/images", ] myenv.WindowsBundle("Swift", resources = commonResources, diff --git a/Swift/QtUI/main.cpp b/Swift/QtUI/main.cpp index 0146769..2eef379 100644 --- a/Swift/QtUI/main.cpp +++ b/Swift/QtUI/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char* argv[]) { boost::program_options::variables_map vm; try { boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); - } catch (boost::program_options::unknown_option option) { + } catch (const boost::program_options::unknown_option& option) { #if BOOST_VERSION >= 104200 std::cout << "Ignoring unknown option " << option.get_option_name() << " but continuing." << std::endl; #else diff --git a/Swift/QtUI/swift-open-uri.cpp b/Swift/QtUI/swift-open-uri.cpp new file mode 100644 index 0000000..2d5ef19 --- /dev/null +++ b/Swift/QtUI/swift-open-uri.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <QCoreApplication> +#include <QDBusConnection> +#include <QDBusMessage> +#include <iostream> + +int main(int argc, char* argv[]) { + QCoreApplication app(argc, argv); + + QDBusConnection bus = QDBusConnection::sessionBus(); + if (!bus.isConnected()) { + return -1; + } + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " uri" << std::endl; + return -1; + } + + QDBusMessage msg = QDBusMessage::createMethodCall("im.swift.Swift.URIHandler", "/", "im.swift.Swift.URIHandler", "openURI"); + msg << argv[1]; + + bus.call(msg); + + return 0; +} diff --git a/Swift/Translations/swift_nl.ts b/Swift/Translations/swift_nl.ts index 0683260..7e8bfbd 100644 --- a/Swift/Translations/swift_nl.ts +++ b/Swift/Translations/swift_nl.ts @@ -416,6 +416,22 @@ <source>There was an error publishing your profile data</source> <translation>Er is een fout opgetreden bij het publiceren van uw profiel</translation> </message> + <message> + <source>%1% (%2%)</source> + <translation>%1% (%2%)</translation> + </message> + <message> + <source>%1% and %2% others (%3%)</source> + <translation>%1% en %2% anderen (%3%)</translation> + </message> + <message> + <source>%1%, %2% (%3%)</source> + <translation>%1%, %2% (%3%)</translation> + </message> + <message> + <source>User address invalid. User address should be of the form 'alice@wonderland.lit'</source> + <translation>Gebruikersadres ongeldig. Gebruikersadres moet van de vorm 'alice@wonderland.lit' zijn</translation> + </message> </context> <context> <name>CloseButton</name> @@ -835,6 +851,10 @@ <source>Bookmarked Rooms</source> <translation>Bladwijzers</translation> </message> + <message> + <source>Recent Chats</source> + <translation>Recente conversaties</translation> + </message> </context> <context> <name>Swift::QtAboutWidget</name> @@ -866,6 +886,37 @@ </message> </context> <context> + <name>Swift::QtAdHocCommandWindow</name> + <message> + <source>Cancel</source> + <translation>Annuleren</translation> + </message> + <message> + <source>Back</source> + <translation>Terug</translation> + </message> + <message> + <source>Next</source> + <translation>Volgende</translation> + </message> + <message> + <source>Complete</source> + <translation>Voltooien</translation> + </message> + <message> + <source>Error: %1</source> + <translation>Fout: %1</translation> + </message> + <message> + <source>Warning: %1</source> + <translation>Waarschuwing: %1</translation> + </message> + <message> + <source>Error executing command</source> + <translation>Fout bij het uitvoeren van de opdracht</translation> + </message> +</context> +<context> <name>Swift::QtAvatarWidget</name> <message> <source>No picture</source> @@ -1161,6 +1212,18 @@ afbeelding</translation> <source>Enter &Room</source> <translation>&Kamer betreden</translation> </message> + <message> + <source>Run Server Command</source> + <translation>Voer opdracht op server uit</translation> + </message> + <message> + <source>Collecting commands...</source> + <translation>Opdrachten aan het verzamelen...</translation> + </message> + <message> + <source>No Available Commands</source> + <translation>Geen beschikbare opdrachten</translation> + </message> </context> <context> <name>Swift::QtNameWidget</name> diff --git a/Swift/resources/logo/dmg.png b/Swift/resources/logo/dmg.png Binary files differnew file mode 100644 index 0000000..64df425 --- /dev/null +++ b/Swift/resources/logo/dmg.png diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp new file mode 100644 index 0000000..ecc6cd0 --- /dev/null +++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/AdHoc/OutgoingAdHocCommandSession.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Base/Algorithm.h> + +namespace Swift { +OutgoingAdHocCommandSession::OutgoingAdHocCommandSession(const JID& to, const std::string& commandNode, IQRouter* iqRouter) : to_(to), commandNode_(commandNode), iqRouter_(iqRouter), isMultiStage_(false) { + +} + +void OutgoingAdHocCommandSession::handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error) { + if (error) { + onError(error); + } else { + const std::vector<Command::Action>& actions = payload->getAvailableActions(); + actionStates_.clear(); + if (payload->getStatus() == Command::Executing ) { + actionStates_[Command::Cancel] = EnabledAndPresent; + actionStates_[Command::Complete] = Present; + if (std::find(actions.begin(), actions.end(), Command::Complete) != actions.end()) { + actionStates_[Command::Complete] = EnabledAndPresent; + } + + if (getIsMultiStage()) { + actionStates_[Command::Next] = Present; + actionStates_[Command::Prev] = Present; + } + + if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end()) { + actionStates_[Command::Next] = EnabledAndPresent; + } + if (std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) { + actionStates_[Command::Prev] = EnabledAndPresent; + } + } + + sessionID_ = payload->getSessionID(); + if (std::find(actions.begin(), actions.end(), Command::Next) != actions.end() + || std::find(actions.begin(), actions.end(), Command::Prev) != actions.end()) { + isMultiStage_ = true; + } + onNextStageReceived(payload); + } +} + +bool OutgoingAdHocCommandSession::getIsMultiStage() const { + return isMultiStage_; +} + +void OutgoingAdHocCommandSession::start() { + boost::shared_ptr<GenericRequest<Command> > commandRequest = boost::make_shared< GenericRequest<Command> >(IQ::Set, to_, boost::make_shared<Command>(commandNode_), iqRouter_); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); +} + +void OutgoingAdHocCommandSession::cancel() { + if (!sessionID_.empty()) { + submitForm(Form::ref(), Command::Cancel); + } +} + +void OutgoingAdHocCommandSession::goBack() { + submitForm(Form::ref(), Command::Prev); +} + +void OutgoingAdHocCommandSession::complete(Form::ref form) { + submitForm(form, Command::Complete); +} + +void OutgoingAdHocCommandSession::goNext(Form::ref form) { + submitForm(form, Command::Next); +} + +void OutgoingAdHocCommandSession::submitForm(Form::ref form, Command::Action action) { + boost::shared_ptr<Command> command(boost::make_shared<Command>(commandNode_, sessionID_, action)); + command->setForm(form); + boost::shared_ptr<GenericRequest<Command> > commandRequest = boost::make_shared< GenericRequest<Command> >(IQ::Set, to_, command, iqRouter_); + commandRequest->onResponse.connect(boost::bind(&OutgoingAdHocCommandSession::handleResponse, this, _1, _2)); + commandRequest->send(); +} + +OutgoingAdHocCommandSession::ActionState OutgoingAdHocCommandSession::getActionState(Command::Action action) const { + return get(actionStates_, action, Absent); +} + +} diff --git a/Swiften/AdHoc/OutgoingAdHocCommandSession.h b/Swiften/AdHoc/OutgoingAdHocCommandSession.h new file mode 100644 index 0000000..a64eb4e --- /dev/null +++ b/Swiften/AdHoc/OutgoingAdHocCommandSession.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2010-2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <string> +#include <map> + +#include <Swiften/JID/JID.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Command.h> +#include <Swiften/Elements/ErrorPayload.h> + +namespace Swift { + class IQRouter; + class MainWindow; + class UIEventStream; + + class OutgoingAdHocCommandSession { + public: + + /** + * Availability of action. + */ + enum ActionState { + Absent /** Action isn't applicable to this command. */ = 0, + Present /** Action is applicable to this command */= 1, + Enabled /** Action is applicable and currently available */ = 2, + EnabledAndPresent = 3}; + + OutgoingAdHocCommandSession(const JID& to, const std::string& commandNode, IQRouter* iqRouter); + /** + * Send initial request to the target. + */ + void start(); + /** + * Cancel command session with the target. + */ + void cancel(); + /** + * Return to the previous stage. + */ + void goBack(); + /** + * Send the form to complete the command. + * \param form Form for submission - if missing the command will be submitted with no form. + */ + void complete(Form::ref form); + /** + * Send the form to advance to the next stage of the command. + * \param form Form for submission - if missing the command will be submitted with no form. + */ + void goNext(Form::ref form); + + /** + * Is the form multi-stage? + */ + bool getIsMultiStage() const; + + /** + * Emitted when the form for the next stage is available. + */ + boost::signal<void (Command::ref)> onNextStageReceived; + + /** + * Emitted on error. + */ + boost::signal<void (ErrorPayload::ref)> onError; + + /** + * Get the state of a given action. + * This is useful for a UI to determine which buttons should be visible, + * and which enabled. + * Use for Next, Prev, Cancel and Complete only. + * If no actions are available, the command has completed. + */ + ActionState getActionState(Command::Action action) const; + + private: + void handleResponse(boost::shared_ptr<Command> payload, ErrorPayload::ref error); + void submitForm(Form::ref, Command::Action action); + + private: + JID to_; + std::string commandNode_; + IQRouter* iqRouter_; + bool isMultiStage_; + std::string sessionID_; + std::map<Command::Action, ActionState> actionStates_; + }; +} diff --git a/Swiften/AdHoc/SConscript b/Swiften/AdHoc/SConscript new file mode 100644 index 0000000..69c9083 --- /dev/null +++ b/Swiften/AdHoc/SConscript @@ -0,0 +1,6 @@ +Import("swiften_env") + +objects = swiften_env.SwiftenObject([ + "OutgoingAdHocCommandSession.cpp", + ]) +swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Avatars/AvatarManager.h b/Swiften/Avatars/AvatarManager.h index e1af451..3461973 100644 --- a/Swiften/Avatars/AvatarManager.h +++ b/Swiften/Avatars/AvatarManager.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Base/ByteArray.h> diff --git a/Swiften/Avatars/AvatarManagerImpl.cpp b/Swiften/Avatars/AvatarManagerImpl.cpp index 509ff47..78d94dc 100644 --- a/Swiften/Avatars/AvatarManagerImpl.cpp +++ b/Swiften/Avatars/AvatarManagerImpl.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Avatars/AvatarManagerImpl.h" +#include <Swiften/Avatars/AvatarManagerImpl.h> #include <boost/bind.hpp> -#include "Swiften/Avatars/VCardUpdateAvatarManager.h" -#include "Swiften/Avatars/VCardAvatarManager.h" -#include "Swiften/Avatars/AvatarStorage.h" +#include <Swiften/Avatars/VCardUpdateAvatarManager.h> +#include <Swiften/Avatars/VCardAvatarManager.h> +#include <Swiften/Avatars/AvatarStorage.h> #include <Swiften/Avatars/OfflineAvatarManager.h> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> namespace Swift { diff --git a/Swiften/Avatars/AvatarProvider.cpp b/Swiften/Avatars/AvatarProvider.cpp index 680b58d..44c89d5 100644 --- a/Swiften/Avatars/AvatarProvider.cpp +++ b/Swiften/Avatars/AvatarProvider.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Avatars/AvatarProvider.h" +#include <Swiften/Avatars/AvatarProvider.h> namespace Swift { diff --git a/Swiften/Avatars/AvatarProvider.h b/Swiften/Avatars/AvatarProvider.h index 0f66904..d2d408e 100644 --- a/Swiften/Avatars/AvatarProvider.h +++ b/Swiften/Avatars/AvatarProvider.h @@ -6,9 +6,10 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" #include <string> +#include <Swiften/Base/boost_bsignals.h> + namespace Swift { class JID; diff --git a/Swiften/Avatars/AvatarStorage.cpp b/Swiften/Avatars/AvatarStorage.cpp index 1bf71e1..8bb1126 100644 --- a/Swiften/Avatars/AvatarStorage.cpp +++ b/Swiften/Avatars/AvatarStorage.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Avatars/AvatarStorage.h" +#include <Swiften/Avatars/AvatarStorage.h> namespace Swift { diff --git a/Swiften/Avatars/AvatarStorage.h b/Swiften/Avatars/AvatarStorage.h index 48fc885..c33d38b 100644 --- a/Swiften/Avatars/AvatarStorage.h +++ b/Swiften/Avatars/AvatarStorage.h @@ -6,12 +6,12 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <string> +#include <Swiften/Base/ByteArray.h> namespace Swift { class JID; - class ByteArray; class AvatarStorage { public: diff --git a/Swiften/Avatars/CombinedAvatarProvider.cpp b/Swiften/Avatars/CombinedAvatarProvider.cpp index eea0b89..d283664 100644 --- a/Swiften/Avatars/CombinedAvatarProvider.cpp +++ b/Swiften/Avatars/CombinedAvatarProvider.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Avatars/CombinedAvatarProvider.h" +#include <Swiften/Avatars/CombinedAvatarProvider.h> #include <algorithm> #include <boost/bind.hpp> diff --git a/Swiften/Avatars/CombinedAvatarProvider.h b/Swiften/Avatars/CombinedAvatarProvider.h index 72e67cf..7b29efc 100644 --- a/Swiften/Avatars/CombinedAvatarProvider.h +++ b/Swiften/Avatars/CombinedAvatarProvider.h @@ -9,8 +9,8 @@ #include <vector> #include <map> -#include "Swiften/Avatars/AvatarProvider.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Avatars/AvatarProvider.h> +#include <Swiften/JID/JID.h> namespace Swift { class CombinedAvatarProvider : public AvatarProvider { diff --git a/Swiften/Avatars/NullAvatarManager.h b/Swiften/Avatars/NullAvatarManager.h index e96ed7a..3f5b9f5 100644 --- a/Swiften/Avatars/NullAvatarManager.h +++ b/Swiften/Avatars/NullAvatarManager.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Avatars/AvatarManager.h" +#include <Swiften/Avatars/AvatarManager.h> namespace Swift { class NullAvatarManager : public AvatarManager { diff --git a/Swiften/Avatars/SConscript b/Swiften/Avatars/SConscript index 46ae897..9c219a4 100644 --- a/Swiften/Avatars/SConscript +++ b/Swiften/Avatars/SConscript @@ -1,7 +1,6 @@ Import("swiften_env") objects = swiften_env.SwiftenObject([ - "AvatarFileStorage.cpp", "VCardUpdateAvatarManager.cpp", "VCardAvatarManager.cpp", "OfflineAvatarManager.cpp", diff --git a/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp b/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp index 4894e14..50b0adb 100644 --- a/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp +++ b/Swiften/Avatars/UnitTest/CombinedAvatarProviderTest.cpp @@ -8,9 +8,9 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> #include <string> -#include "Swiften/Avatars/CombinedAvatarProvider.h" +#include <Swiften/Avatars/CombinedAvatarProvider.h> using namespace Swift; @@ -47,13 +47,13 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testGetAvatarWithNoAvatarProviderReturnsEmpty() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); CPPUNIT_ASSERT(testling->getAvatarHash(user1).empty()); } void testGetAvatarWithSingleAvatarProvider() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); avatarProvider1->avatars[user1] = avatarHash1; testling->addProvider(avatarProvider1); @@ -61,7 +61,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testGetAvatarWithMultipleAvatarProviderReturnsFirstAvatar() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); avatarProvider1->avatars[user1] = avatarHash1; avatarProvider2->avatars[user1] = avatarHash2; testling->addProvider(avatarProvider1); @@ -71,7 +71,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testGetAvatarWithMultipleAvatarProviderAndFailingFirstProviderReturnsSecondAvatar() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); avatarProvider2->avatars[user1] = avatarHash2; testling->addProvider(avatarProvider1); testling->addProvider(avatarProvider2); @@ -80,7 +80,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testProviderUpdateTriggersChange() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); avatarProvider1->avatars[user1] = avatarHash1; avatarProvider1->onAvatarChanged(user1); @@ -90,7 +90,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testProviderUpdateWithoutChangeDoesNotTriggerChange() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); testling->addProvider(avatarProvider2); avatarProvider1->avatars[user1] = avatarHash1; @@ -104,7 +104,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testProviderSecondUpdateTriggersChange() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); avatarProvider1->avatars[user1] = avatarHash1; avatarProvider1->onAvatarChanged(user1); @@ -118,7 +118,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { void testProviderUpdateWithAvatarDisappearingTriggersChange() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); avatarProvider1->avatars[user1] = avatarHash1; avatarProvider1->onAvatarChanged(user1); @@ -131,7 +131,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testProviderUpdateAfterAvatarDisappearedTriggersChange() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); avatarProvider1->avatars[user1] = avatarHash1; avatarProvider1->onAvatarChanged(user1); @@ -147,7 +147,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { void testProviderUpdateAfterGetDoesNotTriggerChange() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); avatarProvider1->avatars[user1] = avatarHash1; @@ -158,7 +158,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testRemoveProviderDisconnectsUpdates() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); testling->addProvider(avatarProvider1); testling->addProvider(avatarProvider2); testling->removeProvider(avatarProvider1); @@ -170,7 +170,7 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } void testProviderUpdateBareJIDAfterGetFullJID() { - std::auto_ptr<CombinedAvatarProvider> testling(createProvider()); + boost::shared_ptr<CombinedAvatarProvider> testling(createProvider()); avatarProvider1->useBare = true; testling->addProvider(avatarProvider1); @@ -183,8 +183,8 @@ class CombinedAvatarProviderTest : public CppUnit::TestFixture { } private: - std::auto_ptr<CombinedAvatarProvider> createProvider() { - std::auto_ptr<CombinedAvatarProvider> result(new CombinedAvatarProvider()); + boost::shared_ptr<CombinedAvatarProvider> createProvider() { + boost::shared_ptr<CombinedAvatarProvider> result(new CombinedAvatarProvider()); result->onAvatarChanged.connect(boost::bind(&CombinedAvatarProviderTest::handleAvatarChanged, this, _1)); return result; } diff --git a/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp b/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp index 7db9c95..81dc12c 100644 --- a/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp +++ b/Swiften/Avatars/UnitTest/VCardAvatarManagerTest.cpp @@ -4,22 +4,23 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "Swiften/Elements/VCard.h" -#include "Swiften/Avatars/VCardAvatarManager.h" -#include "Swiften/Avatars/AvatarMemoryStorage.h" -#include "Swiften/VCards/VCardManager.h" -#include "Swiften/VCards/VCardStorage.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/StringCodecs/Hexify.h" +#include <Swiften/Elements/VCard.h> +#include <Swiften/Avatars/VCardAvatarManager.h> +#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/VCards/VCardStorage.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> using namespace Swift; @@ -55,7 +56,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { return photoHashes.find(jid)->second; } VCard::ref vCard = getVCard(jid); - if (vCard && !vCard->getPhoto().isEmpty()) { + if (vCard && !vCard->getPhoto().empty()) { return Hexify::hexify(SHA1::getHash(vCard->getPhoto())); } else { @@ -79,7 +80,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { avatarStorage = new AvatarMemoryStorage(); vcardStorage = new TestVCardStorage(); vcardManager = new VCardManager(ownJID, iqRouter, vcardStorage); - avatar1 = ByteArray("abcdefg"); + avatar1 = createByteArray("abcdefg"); avatar1Hash = Hexify::hexify(SHA1::getHash(avatar1)); user1 = JID("user1@bar.com/bla"); user2 = JID("user2@foo.com/baz"); @@ -95,7 +96,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { } void testGetAvatarHashKnownAvatar() { - std::auto_ptr<VCardAvatarManager> testling = createManager(); + boost::shared_ptr<VCardAvatarManager> testling = createManager(); storeVCardWithPhoto(user1.toBare(), avatar1); avatarStorage->addAvatar(avatar1Hash, avatar1); @@ -105,7 +106,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { } void testGetAvatarHashEmptyAvatar() { - std::auto_ptr<VCardAvatarManager> testling = createManager(); + boost::shared_ptr<VCardAvatarManager> testling = createManager(); storeEmptyVCard(user1.toBare()); std::string result = testling->getAvatarHash(user1); @@ -114,7 +115,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { } void testGetAvatarHashUnknownAvatarKnownVCardStoresAvatar() { - std::auto_ptr<VCardAvatarManager> testling = createManager(); + boost::shared_ptr<VCardAvatarManager> testling = createManager(); storeVCardWithPhoto(user1.toBare(), avatar1); std::string result = testling->getAvatarHash(user1); @@ -125,7 +126,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { } void testGetAvatarHashUnknownAvatarUnknownVCard() { - std::auto_ptr<VCardAvatarManager> testling = createManager(); + boost::shared_ptr<VCardAvatarManager> testling = createManager(); std::string result = testling->getAvatarHash(user1); @@ -133,7 +134,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { } void testGetAvatarHashKnownAvatarUnknownVCard() { - std::auto_ptr<VCardAvatarManager> testling = createManager(); + boost::shared_ptr<VCardAvatarManager> testling = createManager(); vcardStorage->photoHashes[user1.toBare()] = avatar1Hash; std::string result = testling->getAvatarHash(user1); @@ -143,7 +144,7 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { void testVCardUpdateTriggersUpdate() { - std::auto_ptr<VCardAvatarManager> testling = createManager(); + boost::shared_ptr<VCardAvatarManager> testling = createManager(); vcardManager->requestVCard(user1); sendVCardResult(); @@ -151,8 +152,8 @@ class VCardAvatarManagerTest : public CppUnit::TestFixture { } private: - std::auto_ptr<VCardAvatarManager> createManager() { - std::auto_ptr<VCardAvatarManager> result(new VCardAvatarManager(vcardManager, avatarStorage, mucRegistry)); + boost::shared_ptr<VCardAvatarManager> createManager() { + boost::shared_ptr<VCardAvatarManager> result(new VCardAvatarManager(vcardManager, avatarStorage, mucRegistry)); result->onAvatarChanged.connect(boost::bind(&VCardAvatarManagerTest::handleAvatarChanged, this, _1)); return result; } diff --git a/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp b/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp index 1fb30f3..821412b 100644 --- a/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp +++ b/Swiften/Avatars/UnitTest/VCardUpdateAvatarManagerTest.cpp @@ -4,22 +4,23 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "Swiften/Elements/VCardUpdate.h" -#include "Swiften/Avatars/VCardUpdateAvatarManager.h" -#include "Swiften/Avatars/AvatarMemoryStorage.h" -#include "Swiften/VCards/VCardMemoryStorage.h" -#include "Swiften/VCards/VCardManager.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/StringCodecs/Hexify.h" +#include <Swiften/Elements/VCardUpdate.h> +#include <Swiften/Avatars/VCardUpdateAvatarManager.h> +#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> using namespace Swift; @@ -44,7 +45,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { avatarStorage = new AvatarMemoryStorage(); vcardStorage = new VCardMemoryStorage(); vcardManager = new VCardManager(ownJID, iqRouter, vcardStorage); - avatar1 = ByteArray("abcdefg"); + avatar1 = createByteArray("abcdefg"); avatar1Hash = Hexify::hexify(SHA1::getHash(avatar1)); user1 = JID("user1@bar.com/bla"); user2 = JID("user2@foo.com/baz"); @@ -60,7 +61,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testUpdate_NewHashNewVCardRequestsVCard() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); @@ -68,7 +69,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testUpdate_NewHashStoresAvatarAndEmitsNotificationOnVCardReceive() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); stanzaChannel->onIQReceived(createVCardResult(avatar1)); @@ -80,7 +81,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testUpdate_KnownHash() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); stanzaChannel->onIQReceived(createVCardResult(avatar1)); changes.clear(); @@ -93,7 +94,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testUpdate_KnownHashFromDifferentUserDoesNotRequestVCardButTriggersNotification() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); stanzaChannel->onIQReceived(createVCardResult(avatar1)); changes.clear(); @@ -108,7 +109,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testVCardWithEmptyPhoto() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); vcardManager->requestVCard(JID("foo@bar.com")); stanzaChannel->onIQReceived(createVCardResult(ByteArray())); @@ -117,7 +118,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testStanzaChannelReset_ClearsHash() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); stanzaChannel->onIQReceived(createVCardResult(avatar1)); changes.clear(); @@ -132,7 +133,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } void testStanzaChannelReset_ReceiveHashAfterResetUpdatesHash() { - std::auto_ptr<VCardUpdateAvatarManager> testling = createManager(); + boost::shared_ptr<VCardUpdateAvatarManager> testling = createManager(); stanzaChannel->onPresenceReceived(createPresenceWithPhotoHash(user1, avatar1Hash)); stanzaChannel->onIQReceived(createVCardResult(avatar1)); changes.clear(); @@ -148,8 +149,8 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { } private: - std::auto_ptr<VCardUpdateAvatarManager> createManager() { - std::auto_ptr<VCardUpdateAvatarManager> result(new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, mucRegistry)); + boost::shared_ptr<VCardUpdateAvatarManager> createManager() { + boost::shared_ptr<VCardUpdateAvatarManager> result(new VCardUpdateAvatarManager(vcardManager, stanzaChannel, avatarStorage, mucRegistry)); result->onAvatarChanged.connect(boost::bind(&VCardUpdateAvatarManagerTest::handleAvatarChanged, this, _1)); return result; } @@ -163,7 +164,7 @@ class VCardUpdateAvatarManagerTest : public CppUnit::TestFixture { IQ::ref createVCardResult(const ByteArray& avatar) { VCard::ref vcard(new VCard()); - if (!avatar.isEmpty()) { + if (!avatar.empty()) { vcard->setPhoto(avatar); } return IQ::createResult(JID("baz@fum.com"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), vcard); diff --git a/Swiften/Avatars/VCardAvatarManager.cpp b/Swiften/Avatars/VCardAvatarManager.cpp index a7e6fea..c9571c3 100644 --- a/Swiften/Avatars/VCardAvatarManager.cpp +++ b/Swiften/Avatars/VCardAvatarManager.cpp @@ -4,16 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Avatars/VCardAvatarManager.h" +#include <Swiften/Avatars/VCardAvatarManager.h> #include <boost/bind.hpp> -#include "Swiften/Elements/VCard.h" -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/StringCodecs/Hexify.h" -#include "Swiften/Avatars/AvatarStorage.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/VCards/VCardManager.h" +#include <Swiften/Elements/VCard.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Avatars/AvatarStorage.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/VCards/VCardManager.h> namespace Swift { diff --git a/Swiften/Avatars/VCardAvatarManager.h b/Swiften/Avatars/VCardAvatarManager.h index 3f99dad..cb3945d 100644 --- a/Swiften/Avatars/VCardAvatarManager.h +++ b/Swiften/Avatars/VCardAvatarManager.h @@ -6,11 +6,8 @@ #pragma once -#include <map> - -#include "Swiften/Avatars/AvatarProvider.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/VCard.h" +#include <Swiften/Avatars/AvatarProvider.h> +#include <Swiften/JID/JID.h> namespace Swift { class MUCRegistry; diff --git a/Swiften/Avatars/VCardUpdateAvatarManager.cpp b/Swiften/Avatars/VCardUpdateAvatarManager.cpp index ea074cc..0c3ad23 100644 --- a/Swiften/Avatars/VCardUpdateAvatarManager.cpp +++ b/Swiften/Avatars/VCardUpdateAvatarManager.cpp @@ -4,18 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Avatars/VCardUpdateAvatarManager.h" +#include <Swiften/Avatars/VCardUpdateAvatarManager.h> #include <boost/bind.hpp> -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Elements/VCardUpdate.h" -#include "Swiften/VCards/GetVCardRequest.h" -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/StringCodecs/Hexify.h" -#include "Swiften/Avatars/AvatarStorage.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/VCards/VCardManager.h" +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Elements/VCardUpdate.h> +#include <Swiften/VCards/GetVCardRequest.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Avatars/AvatarStorage.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/VCards/VCardManager.h> #include <Swiften/Base/Log.h> namespace Swift { @@ -50,7 +50,7 @@ void VCardUpdateAvatarManager::handleVCardChanged(const JID& from, VCard::ref vC return; } - if (vCard->getPhoto().isEmpty()) { + if (vCard->getPhoto().empty()) { setAvatarHash(from, ""); } else { diff --git a/Swiften/Avatars/VCardUpdateAvatarManager.h b/Swiften/Avatars/VCardUpdateAvatarManager.h index 1f03898..de68672 100644 --- a/Swiften/Avatars/VCardUpdateAvatarManager.h +++ b/Swiften/Avatars/VCardUpdateAvatarManager.h @@ -9,11 +9,11 @@ #include <boost/shared_ptr.hpp> #include <map> -#include "Swiften/Avatars/AvatarProvider.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/VCard.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Avatars/AvatarProvider.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/VCard.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { class MUCRegistry; diff --git a/Swiften/Base/Algorithm.h b/Swiften/Base/Algorithm.h new file mode 100644 index 0000000..4e68e70 --- /dev/null +++ b/Swiften/Base/Algorithm.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <list> +#include <map> +#include <algorithm> + +namespace Swift { + + /* + * Generic erase() + */ + namespace Detail { + struct VectorCategory {}; + struct ListCategory {}; + struct MapCategory {}; + + template<typename T> + struct ContainerTraits; + + template<typename A, typename B> + struct ContainerTraits< std::vector<A, B> > { + typedef VectorCategory Category; + }; + + template<> + struct ContainerTraits< std::string > { + typedef VectorCategory Category; + }; + + template<typename A, typename B> + struct ContainerTraits< std::list<A, B> > { + typedef ListCategory Category; + }; + + template<typename A, typename B, typename C, typename D> + struct ContainerTraits< std::map<A, B, C, D> > { + typedef MapCategory Category; + }; + + template<typename C, typename V> + void eraseImpl(C& c, const V& v, VectorCategory) { + c.erase(std::remove(c.begin(), c.end(), v), c.end()); + } + + template<typename C, typename V> + void eraseImpl(C& c, const V& v, ListCategory) { + c.remove(v); + } + + template<typename C, typename V> + void eraseImpl(C& c, const V& v, MapCategory) { + for (typename C::iterator it = c.begin(); it != c.end(); ) { + if (it->second == v) { + c.erase(it++); + } + else { + ++it; + } + } + } + + template<typename C, typename P> + void eraseIfImpl(C& c, const P& p, MapCategory) { + for (typename C::iterator it = c.begin(); it != c.end(); ) { + if (p(*it)) { + c.erase(it++); + } + else { + ++it; + } + } + } + + template<typename C, typename P> + void eraseIfImpl(C& c, const P& p, VectorCategory) { + c.erase(std::remove_if(c.begin(), c.end(), p), c.end()); + } + } + + template<typename C, typename V> + void erase(C& container, const V& value) { + Detail::eraseImpl(container, value, typename Detail::ContainerTraits<C>::Category()); + } + + template<typename C, typename P> + void eraseIf(C& container, const P& predicate) { + Detail::eraseIfImpl(container, predicate, typename Detail::ContainerTraits<C>::Category()); + } + + template<typename Source, typename Target> + void append(Target& target, const Source& source) { + target.insert(target.end(), source.begin(), source.end()); + } + + template<typename A, typename B, typename C, typename D> + B get(const std::map<A, B, C, D>& map, const A& key, const B& defaultValue) { + typename std::map<A, B, C, D>::const_iterator i = map.find(key); + if (i != map.end()) { + return i->second; + } + else { + return defaultValue; + } + } + + template<typename Container> + void safeClear(Container& c) { + std::fill(c.begin(), c.end(), 0); + c.clear(); + } + + /* + * Functors + */ + template<typename K, typename V> + class PairFirstEquals { + public: + PairFirstEquals(const K& value) : value(value) { + } + + bool operator()(const std::pair<K,V>& pair) const { + return pair.first == value; + } + + private: + K value; + }; + + template<typename K, typename V> + class PairSecondEquals { + public: + PairSecondEquals(const V& value) : value(value) { + } + + bool operator()(const std::pair<K,V>& pair) const { + return pair.second == value; + } + + private: + V value; + }; +} diff --git a/Swiften/Base/ByteArray.cpp b/Swiften/Base/ByteArray.cpp index 928e145..6be96aa 100644 --- a/Swiften/Base/ByteArray.cpp +++ b/Swiften/Base/ByteArray.cpp @@ -4,37 +4,46 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> #include <fstream> -std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s) { - std::ios::fmtflags oldFlags = os.flags(); - os << std::hex; - for (Swift::ByteArray::const_iterator i = s.begin(); i != s.end(); ++i) { - os << "0x" << static_cast<unsigned int>(static_cast<unsigned char>(*i)); - if (i + 1 < s.end()) { - os << " "; - } - } - os << std::endl; - os.flags(oldFlags); - return os; -} - namespace Swift { static const int BUFFER_SIZE = 4096; -void ByteArray::readFromFile(const std::string& file) { +void readByteArrayFromFile(ByteArray& data, const std::string& file) { std::ifstream input(file.c_str(), std::ios_base::in|std::ios_base::binary); while (input.good()) { - size_t oldSize = data_.size(); - data_.resize(oldSize + BUFFER_SIZE); - input.read(reinterpret_cast<char*>(&data_[oldSize]), BUFFER_SIZE); - data_.resize(oldSize + input.gcount()); + size_t oldSize = data.size(); + data.resize(oldSize + BUFFER_SIZE); + input.read(reinterpret_cast<char*>(&data[oldSize]), BUFFER_SIZE); + data.resize(oldSize + input.gcount()); } input.close(); } +std::vector<unsigned char> createByteArray(const std::string& s) { + return std::vector<unsigned char>(s.begin(), s.end()); +} + +std::vector<unsigned char> createByteArray(const char* c) { + std::vector<unsigned char> data; + while (*c) { + data.push_back(static_cast<unsigned char>(*c)); + ++c; + } + return data; +} + +std::string byteArrayToString(const ByteArray& b) { + size_t i; + for (i = b.size(); i > 0; --i) { + if (b[i - 1] != 0) { + break; + } + } + return i > 0 ? std::string(reinterpret_cast<const char*>(vecptr(b)), i) : ""; +} + } diff --git a/Swiften/Base/ByteArray.h b/Swiften/Base/ByteArray.h index ad2c1e5..b368ef8 100644 --- a/Swiften/Base/ByteArray.h +++ b/Swiften/Base/ByteArray.h @@ -6,135 +6,39 @@ #pragma once -#include <cstring> #include <vector> -#include <iostream> - #include <string> namespace Swift { - class ByteArray - { - public: - typedef std::vector<unsigned char>::const_iterator const_iterator; - - ByteArray() : data_() {} - - ByteArray(const std::string& s) : data_(s.begin(), s.end()) {} - - ByteArray(const char* c) { - while (*c) { - data_.push_back(*c); - ++c; - } - } - - ByteArray(const char* c, size_t n) { - if (n > 0) { - data_.resize(n); - memcpy(&data_[0], c, n); - } - } - - ByteArray(const unsigned char* c, size_t n) { - if (n > 0) { - data_.resize(n); - memcpy(&data_[0], c, n); - } - } - - ByteArray(const std::vector<unsigned char>& data) : data_(data) { - } - - const unsigned char* getData() const { - return data_.empty() ? NULL : &data_[0]; - } - - unsigned char* getData() { - return data_.empty() ? NULL : &data_[0]; - } - - const std::vector<unsigned char>& getVector() const { - return data_; - } - - std::vector<unsigned char>& getVector() { - return data_; - } - - size_t getSize() const { - return data_.size(); - } - - bool isEmpty() const { - return data_.empty(); - } - - void resize(size_t size) { - return data_.resize(size); - } - - void resize(size_t size, char c) { - return data_.resize(size, c); - } - - friend ByteArray operator+(const ByteArray& a, const ByteArray&b) { - ByteArray result(a); - result.data_.insert(result.data_.end(), b.data_.begin(), b.data_.end()); - return result; - } - - friend ByteArray operator+(const ByteArray& a, char b) { - ByteArray x; - x.resize(1); - x[0] = b; - return a + x; - } - - ByteArray& operator+=(const ByteArray& b) { - data_.insert(data_.end(), b.data_.begin(), b.data_.end()); - return *this; - } - - ByteArray& operator+=(char c) { - data_.push_back(c); - return *this; - } - - friend bool operator==(const ByteArray& a, const ByteArray& b) { - return a.data_ == b.data_; - } + typedef std::vector<unsigned char> ByteArray; + ByteArray createByteArray(const std::string& s); + ByteArray createByteArray(const char* c); - const unsigned char& operator[](size_t i) const { - return data_[i]; - } + inline ByteArray createByteArray(const unsigned char* c, size_t n) { + return ByteArray(c, c + n); + } - unsigned char& operator[](size_t i) { - return data_[i]; - } + inline ByteArray createByteArray(const char* c, size_t n) { + return ByteArray(c, c + n); + } - const_iterator begin() const { - return data_.begin(); - } - - const_iterator end() const { - return data_.end(); - } + inline ByteArray createByteArray(char c) { + return std::vector<unsigned char>(1, c); + } - std::string toString() const { - return std::string(reinterpret_cast<const char*>(getData()), getSize()); - } + template<typename T, typename A> + static const T* vecptr(const std::vector<T, A>& v) { + return v.empty() ? NULL : &v[0]; + } - void readFromFile(const std::string& file); + template<typename T, typename A> + static T* vecptr(std::vector<T, A>& v) { + return v.empty() ? NULL : &v[0]; + } - void clear() { - data_.clear(); - } + std::string byteArrayToString(const ByteArray& b); - private: - std::vector<unsigned char> data_; - }; + void readByteArrayFromFile(ByteArray&, const std::string& file); } -std::ostream& operator<<(std::ostream& os, const Swift::ByteArray& s); diff --git a/Swiften/Base/Concat.h b/Swiften/Base/Concat.h new file mode 100644 index 0000000..83a43b6 --- /dev/null +++ b/Swiften/Base/Concat.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +namespace Swift { + template<typename C> + C concat(const C& c1, const C& c2) { + C result; + result.resize(c1.size() + c2.size()); + std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3) { + C result; + result.resize(c1.size() + c2.size() + c3.size()); + std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3, const C& c4) { + C result; + result.resize(c1.size() + c2.size() + c3.size() + c4.size()); + std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())))); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5) { + C result; + result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size()); + std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))))); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6) { + C result; + result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size()); + std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())))))); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6, const C& c7) { + C result; + result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size() + c7.size()); + std::copy(c7.begin(), c7.end(), std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))))))); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6, const C& c7, const C& c8) { + C result; + result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size() + c7.size() + c8.size()); + std::copy(c8.begin(), c8.end(), std::copy(c7.begin(), c7.end(), std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin())))))))); + return result; + } + + template<typename C> + C concat(const C& c1, const C& c2, const C& c3, const C& c4, const C& c5, const C& c6, const C& c7, const C& c8, const C& c9) { + C result; + result.resize(c1.size() + c2.size() + c3.size() + c4.size() + c5.size() + c6.size() + c7.size() + c8.size() + c9.size()); + std::copy(c9.begin(), c9.end(), std::copy(c8.begin(), c8.end(), std::copy(c7.begin(), c7.end(), std::copy(c6.begin(), c6.end(), std::copy(c5.begin(), c5.end(), std::copy(c4.begin(), c4.end(), std::copy(c3.begin(), c3.end(), std::copy(c2.begin(), c2.end(), std::copy(c1.begin(), c1.end(), result.begin()))))))))); + return result; + } +} diff --git a/Swiften/Base/DateTime.cpp b/Swiften/Base/DateTime.cpp new file mode 100644 index 0000000..fae26d4 --- /dev/null +++ b/Swiften/Base/DateTime.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/DateTime.h> + +#include <locale> +#include <boost/date_time/time_facet.hpp> +#include <boost/date_time/local_time/local_time.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/Base/String.h> + +namespace Swift { + +boost::posix_time::ptime stringToDateTime(const std::string& string) { + static std::locale locale(std::locale::classic(), new boost::local_time::local_time_input_facet("%Y-%m-%d %H:%M:%S%F%ZP")); + std::istringstream stream(string); + stream.imbue(locale); + boost::local_time::local_date_time result(boost::date_time::not_a_date_time); + stream >> result; + return result.utc_time(); +} + +std::string dateTimeToString(const boost::posix_time::ptime& time) { + std::string stampString = std::string(boost::posix_time::to_iso_extended_string(time)); + String::replaceAll(stampString, ',', "."); + stampString += "Z"; + return stampString; +} + +} diff --git a/Swiften/Base/DateTime.h b/Swiften/Base/DateTime.h new file mode 100644 index 0000000..2407ddc --- /dev/null +++ b/Swiften/Base/DateTime.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/date_time/posix_time/ptime.hpp> + +namespace Swift { + /** + * Converts a date formatted according to XEP-0082 into a ptime + * object (in UTC). + */ + boost::posix_time::ptime stringToDateTime(const std::string& string); + + /** + * Converts a UTC ptime object to a XEP-0082 formatted string. + */ + std::string dateTimeToString(const boost::posix_time::ptime& time); +} diff --git a/Swiften/Base/Error.cpp b/Swiften/Base/Error.cpp index dd127a6..60ad7ac 100644 --- a/Swiften/Base/Error.cpp +++ b/Swiften/Base/Error.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/Error.h" +#include <Swiften/Base/Error.h> namespace Swift { diff --git a/Swiften/Base/IDGenerator.cpp b/Swiften/Base/IDGenerator.cpp index 74a0f65..5556f7b 100644 --- a/Swiften/Base/IDGenerator.cpp +++ b/Swiften/Base/IDGenerator.cpp @@ -1,10 +1,15 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/IDGenerator.h" +#include <Swiften/Base/IDGenerator.h> + +#include <boost/uuid/uuid.hpp> +#include <boost/uuid/uuid_io.hpp> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/lexical_cast.hpp> namespace Swift { @@ -12,23 +17,8 @@ IDGenerator::IDGenerator() { } std::string IDGenerator::generateID() { - bool carry = true; - size_t i = 0; - while (carry && i < currentID_.size()) { - char c = currentID_[i]; - if (c >= 'z') { - currentID_[i] = 'a'; - } - else { - currentID_[i] = c+1; - carry = false; - } - ++i; - } - if (carry) { - currentID_ += 'a'; - } - return currentID_; + static boost::uuids::random_generator generator; + return boost::lexical_cast<std::string>(generator()); } } diff --git a/Swiften/Base/IDGenerator.h b/Swiften/Base/IDGenerator.h index 4b6289b..44eeb76 100644 --- a/Swiften/Base/IDGenerator.h +++ b/Swiften/Base/IDGenerator.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IDGenerator_H -#define SWIFTEN_IDGenerator_H +#pragma once #include <string> @@ -15,10 +14,5 @@ namespace Swift { IDGenerator(); std::string generateID(); - - private: - std::string currentID_; }; } - -#endif diff --git a/Swiften/Base/Log.cpp b/Swiften/Base/Log.cpp index 2041013..4132353 100644 --- a/Swiften/Base/Log.cpp +++ b/Swiften/Base/Log.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/Log.h" +#include <Swiften/Base/Log.h> namespace Swift { diff --git a/Swiften/Base/Paths.cpp b/Swiften/Base/Paths.cpp index 43eee57..b40f9b8 100644 --- a/Swiften/Base/Paths.cpp +++ b/Swiften/Base/Paths.cpp @@ -24,22 +24,22 @@ boost::filesystem::path Paths::getExecutablePath() { ByteArray path; uint32_t size = 4096; path.resize(size); - if (_NSGetExecutablePath(reinterpret_cast<char*>(path.getData()), &size) == 0) { - return boost::filesystem::path(path.toString().c_str()).parent_path(); + if (_NSGetExecutablePath(const_cast<char*>(reinterpret_cast<const char*>(vecptr(path))), &size) == 0) { + return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(path)), path.size()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_LINUX) ByteArray path; path.resize(4096); - size_t size = readlink("/proc/self/exe", reinterpret_cast<char*>(path.getData()), path.getSize()); + size_t size = readlink("/proc/self/exe", reinterpret_cast<char*>(vecptr(path)), path.size()); if (size > 0) { path.resize(size); - return boost::filesystem::path(path.toString().c_str()).parent_path(); + return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(path)), path.size()).c_str()).parent_path(); } #elif defined(SWIFTEN_PLATFORM_WINDOWS) ByteArray data; data.resize(2048); - GetModuleFileName(NULL, reinterpret_cast<char*>(data.getData()), data.getSize()); - return boost::filesystem::path(data.toString().c_str()).parent_path(); + GetModuleFileName(NULL, reinterpret_cast<char*>(vecptr(data)), data.size()); + return boost::filesystem::path(std::string(reinterpret_cast<const char*>(vecptr(data)), data.size()).c_str()).parent_path(); #endif return boost::filesystem::path(); } diff --git a/Swiften/Base/Paths.h b/Swiften/Base/Paths.h index 06c6aeb..8ac4640 100644 --- a/Swiften/Base/Paths.h +++ b/Swiften/Base/Paths.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> namespace Swift { class Paths { diff --git a/Swiften/Base/Platform.h b/Swiften/Base/Platform.h index 32e2671..395747c 100644 --- a/Swiften/Base/Platform.h +++ b/Swiften/Base/Platform.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Platform_H -#define SWIFTEN_Platform_H +#pragma once // Base platforms #if defined(linux) || defined(__linux) || defined(__linux__) @@ -26,6 +25,10 @@ #define SWIFTEN_PLATFORM_BEOS #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #define SWIFTEN_PLATFORM_MACOSX +#include <TargetConditionals.h> +# if defined(TARGET_OS_IPHONE) +# define SWIFTEN_PLATFORM_IPHONE +# endif #elif defined(__IBMCPP__) || defined(_AIX) #define SWIFTEN_PLATFORM_AIX #elif defined(__amigaos__) @@ -46,5 +49,3 @@ #elif defined(BOOST_BIG_ENDIAN) #define SWIFTEN_BIG_ENDIAN #endif - -#endif diff --git a/Swiften/Base/SConscript b/Swiften/Base/SConscript index 01252e5..8752ea8 100644 --- a/Swiften/Base/SConscript +++ b/Swiften/Base/SConscript @@ -2,6 +2,8 @@ Import("swiften_env") objects = swiften_env.SwiftenObject([ "ByteArray.cpp", + "DateTime.cpp", + "SafeByteArray.cpp", "Error.cpp", "Log.cpp", "Paths.cpp", diff --git a/Swiften/Base/SafeAllocator.h b/Swiften/Base/SafeAllocator.h new file mode 100644 index 0000000..9f9dd42 --- /dev/null +++ b/Swiften/Base/SafeAllocator.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <algorithm> + +namespace Swift { + template<typename T> + class SafeAllocator : public std::allocator<T> { + public: + template <class U> struct rebind { + typedef SafeAllocator<U> other; + }; + + SafeAllocator() throw() {} + SafeAllocator(const SafeAllocator&) throw() : std::allocator<T>() {} + template <class U> SafeAllocator(const SafeAllocator<U>&) throw() {} + ~SafeAllocator() throw() {} + + void deallocate (T* p, size_t num) { + std::fill(reinterpret_cast<char*>(p), reinterpret_cast<char*>(p + num), 0); + std::allocator<T>::deallocate(p, num); + } + }; +}; diff --git a/Swiften/Base/SafeByteArray.cpp b/Swiften/Base/SafeByteArray.cpp new file mode 100644 index 0000000..848b6d8 --- /dev/null +++ b/Swiften/Base/SafeByteArray.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/SafeByteArray.h> + +using namespace Swift; + +namespace Swift { + +SafeByteArray createSafeByteArray(const char* c) { + SafeByteArray data; + while (*c) { + data.push_back(static_cast<unsigned char>(*c)); + ++c; + } + return data; +} + +} diff --git a/Swiften/Base/SafeByteArray.h b/Swiften/Base/SafeByteArray.h new file mode 100644 index 0000000..1ef1d84 --- /dev/null +++ b/Swiften/Base/SafeByteArray.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/Base/SafeAllocator.h> +#include <Swiften/Base/ByteArray.h> +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + typedef std::vector<unsigned char, SafeAllocator<unsigned char> > SafeByteArray; + + inline SafeByteArray createSafeByteArray(const ByteArray& a) { + return SafeByteArray(a.begin(), a.end()); + } + + SafeByteArray createSafeByteArray(const char* c); + + inline SafeByteArray createSafeByteArray(const std::string& s) { + return SafeByteArray(s.begin(), s.end()); + } + + inline boost::shared_ptr<SafeByteArray> createSafeByteArrayRef(const std::string& s) { + return boost::make_shared<SafeByteArray>(s.begin(), s.end()); + } + + inline SafeByteArray createSafeByteArray(char c) { + return SafeByteArray(1, c); + } + + inline SafeByteArray createSafeByteArray(const char* c, size_t n) { + return SafeByteArray(c, c + n); + } + + inline boost::shared_ptr<SafeByteArray> createSafeByteArrayRef(const char* c, size_t n) { + return boost::make_shared<SafeByteArray>(c, c + n); + } + + inline SafeByteArray createSafeByteArray(const unsigned char* c, size_t n) { + return SafeByteArray(c, c + n); + } + + inline boost::shared_ptr<SafeByteArray> createSafeByteArrayRef(const unsigned char* c, size_t n) { + return boost::make_shared<SafeByteArray>(c, c + n); + } + + /* WARNING! This breaks the safety of the data in the safe byte array. + * Do not use in modes that require data safety. */ + inline std::string safeByteArrayToString(const SafeByteArray& b) { + return byteArrayToString(ByteArray(b.begin(), b.end())); + } +} + diff --git a/Swiften/Base/SafeString.h b/Swiften/Base/SafeString.h new file mode 100644 index 0000000..ef9c7cc --- /dev/null +++ b/Swiften/Base/SafeString.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/SafeByteArray.h> + +namespace Swift { + class SafeString { + public: + SafeString(const SafeByteArray& data) : data(data) { + } + + SafeString(const std::string& s) { + data = createSafeByteArray(s); + } + + SafeString(const char* s) { + data = createSafeByteArray(s); + } + + operator SafeByteArray () const { + return data; + } + + private: + SafeByteArray data; + }; +} diff --git a/Swiften/Base/String.h b/Swiften/Base/String.h index 192d53b..db6c28b 100644 --- a/Swiften/Base/String.h +++ b/Swiften/Base/String.h @@ -6,9 +6,9 @@ #pragma once -#include <map> #include <string> #include <vector> +#include <sstream> #define SWIFTEN_STRING_TO_CFSTRING(a) \ CFStringCreateWithBytes(NULL, reinterpret_cast<const UInt8*>(a.c_str()), a.size(), kCFStringEncodingUTF8, false) @@ -19,11 +19,28 @@ namespace Swift { std::pair<std::string, std::string> getSplittedAtFirst(const std::string&, char c); std::vector<std::string> split(const std::string&, char c); void replaceAll(std::string&, char c, const std::string& s); + inline bool beginsWith(const std::string& s, char c) { return s.size() > 0 && s[0] == c; } + inline bool endsWith(const std::string& s, char c) { return s.size() > 0 && s[s.size()-1] == c; } }; + + class makeString { + public: + template <typename T> makeString& operator<<(T const& v) { + stream << v; + return *this; + } + + operator std::string() const { + return stream.str(); + } + + private: + std::ostringstream stream; + }; } diff --git a/Swiften/Base/UnitTest/ByteArrayTest.cpp b/Swiften/Base/UnitTest/ByteArrayTest.cpp index cb10dd4..ecd0439 100644 --- a/Swiften/Base/UnitTest/ByteArrayTest.cpp +++ b/Swiften/Base/UnitTest/ByteArrayTest.cpp @@ -7,20 +7,49 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <boost/lexical_cast.hpp> using namespace Swift; class ByteArrayTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ByteArrayTest); CPPUNIT_TEST(testGetData_NoData); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST(testToString_NullTerminated); + CPPUNIT_TEST(testToString_TwoNullTerminated); + CPPUNIT_TEST(testToString_AllNull); CPPUNIT_TEST_SUITE_END(); public: void testGetData_NoData() { ByteArray testling; - CPPUNIT_ASSERT_EQUAL(reinterpret_cast<const char*>(NULL), reinterpret_cast<const char*>(testling.getData())); + CPPUNIT_ASSERT_EQUAL(reinterpret_cast<const char*>(NULL), reinterpret_cast<const char*>(vecptr(testling))); + } + + void testToString() { + ByteArray testling(createByteArray("abcde")); + + CPPUNIT_ASSERT_EQUAL(std::string("abcde"), byteArrayToString(testling)); + } + + void testToString_NullTerminated() { + ByteArray testling(createByteArray("abcde\0", 6)); + + CPPUNIT_ASSERT_EQUAL(std::string("abcde"), byteArrayToString(testling)); + } + + void testToString_TwoNullTerminated() { + ByteArray testling(createByteArray("abcde\0\0", 7)); + + CPPUNIT_ASSERT_EQUAL(std::string("abcde"), byteArrayToString(testling)); + } + + void testToString_AllNull() { + ByteArray testling(createByteArray("\0\0", 2)); + + CPPUNIT_ASSERT_EQUAL(std::string(""), byteArrayToString(testling)); } }; diff --git a/Swiften/Base/UnitTest/DateTimeTest.cpp b/Swiften/Base/UnitTest/DateTimeTest.cpp new file mode 100644 index 0000000..8c3903a --- /dev/null +++ b/Swiften/Base/UnitTest/DateTimeTest.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <string> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/Base/DateTime.h> + +using namespace Swift; + +class DateTimeTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(DateTimeTest); + CPPUNIT_TEST(testStringToDateTime_UTC); + CPPUNIT_TEST(testStringToDateTime_WithTimezone); + CPPUNIT_TEST(testDateTimeToString); + CPPUNIT_TEST_SUITE_END(); + + public: + void testStringToDateTime_UTC() { + boost::posix_time::ptime time = stringToDateTime("1969-07-21T02:56:15Z"); + + CPPUNIT_ASSERT_EQUAL(std::string("1969-07-21T02:56:15"), boost::posix_time::to_iso_extended_string(time)); + } + + void testStringToDateTime_WithTimezone() { + boost::posix_time::ptime time = stringToDateTime("1969-07-20T21:56:15-05:00"); + + CPPUNIT_ASSERT_EQUAL(std::string("1969-07-21T02:56:15"), boost::posix_time::to_iso_extended_string(time)); + } + + void testDateTimeToString() { + boost::posix_time::ptime time = stringToDateTime("1969-07-20T21:56:15-05:00"); + + CPPUNIT_ASSERT_EQUAL(std::string("1969-07-21T02:56:15Z"), dateTimeToString(time)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(DateTimeTest); diff --git a/Swiften/Base/UnitTest/IDGeneratorTest.cpp b/Swiften/Base/UnitTest/IDGeneratorTest.cpp index 4874684..610138f 100644 --- a/Swiften/Base/UnitTest/IDGeneratorTest.cpp +++ b/Swiften/Base/UnitTest/IDGeneratorTest.cpp @@ -8,7 +8,7 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <set> -#include "Swiften/Base/IDGenerator.h" +#include <Swiften/Base/IDGenerator.h> using namespace Swift; diff --git a/Swiften/Base/foreach.h b/Swiften/Base/foreach.h index 05366d6..87f6147 100644 --- a/Swiften/Base/foreach.h +++ b/Swiften/Base/foreach.h @@ -4,12 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_FOREACH_H -#define SWIFTEN_FOREACH_H +#pragma once #include <boost/foreach.hpp> #undef foreach #define foreach BOOST_FOREACH - -#endif diff --git a/Swiften/Base/format.h b/Swiften/Base/format.h index 4591827..0e49eaa 100644 --- a/Swiften/Base/format.h +++ b/Swiften/Base/format.h @@ -7,6 +7,7 @@ #pragma once #include <boost/format.hpp> +#include <iostream> namespace Swift { inline boost::format format(const std::string& s) { diff --git a/Swiften/Base/sleep.cpp b/Swiften/Base/sleep.cpp index 892a3ba..7161217 100644 --- a/Swiften/Base/sleep.cpp +++ b/Swiften/Base/sleep.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/sleep.h" +#include <Swiften/Base/sleep.h> #include <boost/thread.hpp> diff --git a/Swiften/Base/sleep.h b/Swiften/Base/sleep.h index c2bc601..a95e907 100644 --- a/Swiften/Base/sleep.h +++ b/Swiften/Base/sleep.h @@ -4,11 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_sleep_H -#define SWIFTEN_sleep_H +#pragma once namespace Swift { void sleep(unsigned int msecs); } - -#endif diff --git a/Swiften/Chat/ChatStateNotifier.cpp b/Swiften/Chat/ChatStateNotifier.cpp index 6e0f458..d507c4d 100644 --- a/Swiften/Chat/ChatStateNotifier.cpp +++ b/Swiften/Chat/ChatStateNotifier.cpp @@ -4,14 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Chat/ChatStateNotifier.h" +#include <Swiften/Chat/ChatStateNotifier.h> #include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/ChatState.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Disco/EntityCapsProvider.h" +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/ChatState.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Disco/EntityCapsProvider.h> namespace Swift { @@ -68,15 +69,15 @@ bool ChatStateNotifier::contactShouldReceiveStates() { } void ChatStateNotifier::changeState(ChatState::ChatStateType state) { - boost::shared_ptr<Message> message(new Message()); + boost::shared_ptr<Message> message(boost::make_shared<Message>()); message->setTo(contact_); - message->addPayload(boost::shared_ptr<Payload>(new ChatState(state))); + message->addPayload(boost::make_shared<ChatState>(state)); stanzaChannel_->sendMessage(message); } void ChatStateNotifier::addChatStateRequest(Message::ref message) { if (contactShouldReceiveStates()) { - message->addPayload(boost::shared_ptr<Payload>(new ChatState(ChatState::Active))); + message->addPayload(boost::make_shared<ChatState>(ChatState::Active)); } } diff --git a/Swiften/Chat/ChatStateNotifier.h b/Swiften/Chat/ChatStateNotifier.h index 1185ed0..c691092 100644 --- a/Swiften/Chat/ChatStateNotifier.h +++ b/Swiften/Chat/ChatStateNotifier.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/ChatState.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/ChatState.h> +#include <Swiften/JID/JID.h> namespace Swift { class StanzaChannel; diff --git a/Swiften/Chat/ChatStateTracker.cpp b/Swiften/Chat/ChatStateTracker.cpp index 2afcf67..27be86c 100644 --- a/Swiften/Chat/ChatStateTracker.cpp +++ b/Swiften/Chat/ChatStateTracker.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Chat/ChatStateTracker.h" +#include <Swiften/Chat/ChatStateTracker.h> namespace Swift { ChatStateTracker::ChatStateTracker() { diff --git a/Swiften/Chat/ChatStateTracker.h b/Swiften/Chat/ChatStateTracker.h index 343d828..b356644 100644 --- a/Swiften/Chat/ChatStateTracker.h +++ b/Swiften/Chat/ChatStateTracker.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/ChatState.h" +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/ChatState.h> namespace Swift { class ChatStateTracker { diff --git a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp index 5d7961b..1b91076 100644 --- a/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp +++ b/Swiften/Chat/UnitTest/ChatStateNotifierTest.cpp @@ -8,9 +8,10 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "Swiften/Chat/ChatStateNotifier.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Disco/DummyEntityCapsProvider.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Chat/ChatStateNotifier.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Disco/DummyEntityCapsProvider.h> using namespace Swift; diff --git a/Swiften/Client/BlockList.cpp b/Swiften/Client/BlockList.cpp new file mode 100644 index 0000000..0b2fc12 --- /dev/null +++ b/Swiften/Client/BlockList.cpp @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/BlockList.h> + +using namespace Swift; + +BlockList::~BlockList() { + +} diff --git a/Swiften/Client/BlockList.h b/Swiften/Client/BlockList.h new file mode 100644 index 0000000..39a211d --- /dev/null +++ b/Swiften/Client/BlockList.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <set> + +#include <Swiften/JID/JID.h> +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class BlockList { + public: + enum State { + Requesting, + Available, + Error, + }; + virtual ~BlockList(); + + virtual State getState() const = 0; + + virtual const std::set<JID>& getItems() const = 0; + + public: + boost::signal<void ()> onStateChanged; + boost::signal<void (const JID&)> onItemAdded; + boost::signal<void (const JID&)> onItemRemoved; + }; +} diff --git a/Swiften/Client/BlockListImpl.cpp b/Swiften/Client/BlockListImpl.cpp new file mode 100644 index 0000000..dfaaaf1 --- /dev/null +++ b/Swiften/Client/BlockListImpl.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/BlockListImpl.h> + +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +BlockListImpl::BlockListImpl() { + +} + +void BlockListImpl::setItems(const std::vector<JID>& items) { + this->items = std::set<JID>(items.begin(), items.end()); +} + +void BlockListImpl::addItem(const JID& item) { + if (items.insert(item).second) { + onItemAdded(item); + } +} + +void BlockListImpl::removeItem(const JID& item) { + if (items.erase(item)) { + onItemRemoved(item); + } +} + +void BlockListImpl::setState(State state) { + if (this->state != state) { + onStateChanged(); + } +} + +void BlockListImpl::addItems(const std::vector<JID>& items) { + foreach (const JID& item, items) { + addItem(item); + } +} + +void BlockListImpl::removeItems(const std::vector<JID>& items) { + foreach (const JID& item, items) { + removeItem(item); + } +} + +void BlockListImpl::removeAllItems() { + foreach (const JID& item, items) { + removeItem(item); + } +} + diff --git a/Swiften/Client/BlockListImpl.h b/Swiften/Client/BlockListImpl.h new file mode 100644 index 0000000..ef08340 --- /dev/null +++ b/Swiften/Client/BlockListImpl.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Client/BlockList.h> + +namespace Swift { + class BlockListImpl : public BlockList { + public: + BlockListImpl(); + + virtual State getState() const { + return state; + } + + void setState(State state); + + virtual const std::set<JID>& getItems() const { + return items; + } + + void setItems(const std::vector<JID>& items); + void addItem(const JID& item); + void removeItem(const JID& item); + void addItems(const std::vector<JID>& items); + void removeItems(const std::vector<JID>& items); + void removeAllItems(); + + private: + State state; + std::set<JID> items; + }; +} diff --git a/Swiften/Client/Client.cpp b/Swiften/Client/Client.cpp index 7918c46..48eddc2 100644 --- a/Swiften/Client/Client.cpp +++ b/Swiften/Client/Client.cpp @@ -4,38 +4,45 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/Client.h" - -#include "Swiften/Queries/Responders/SoftwareVersionResponder.h" -#include "Swiften/Roster/XMPPRosterImpl.h" -#include "Swiften/Roster/XMPPRosterController.h" -#include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Presence/StanzaChannelPresenceSender.h" -#include "Swiften/Presence/DirectedPresenceSender.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/MUC/MUCManager.h" -#include "Swiften/Client/MemoryStorages.h" -#include "Swiften/VCards/VCardManager.h" -#include "Swiften/VCards/VCardManager.h" -#include "Swiften/Avatars/AvatarManagerImpl.h" -#include "Swiften/Disco/CapsManager.h" -#include "Swiften/Disco/EntityCapsManager.h" -#include "Swiften/Disco/ClientDiscoManager.h" -#include "Swiften/Client/NickResolver.h" -#include "Swiften/Presence/SubscriptionManager.h" -#include "Swiften/TLS/BlindCertificateTrustChecker.h" +#include <Swiften/Client/Client.h> + +#include <Swiften/Queries/Responders/SoftwareVersionResponder.h> +#include <Swiften/Roster/XMPPRosterImpl.h> +#include <Swiften/Roster/XMPPRosterController.h> +#include <Swiften/Presence/PresenceOracle.h> +#include <Swiften/Presence/StanzaChannelPresenceSender.h> +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/MUC/MUCManager.h> +#include <Swiften/Client/MemoryStorages.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/Avatars/AvatarManagerImpl.h> +#include <Swiften/Disco/CapsManager.h> +#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Disco/ClientDiscoManager.h> +#include <Swiften/Client/NickResolver.h> +#include <Swiften/Presence/SubscriptionManager.h> +#include <Swiften/TLS/BlindCertificateTrustChecker.h> #include <Swiften/Client/NickManagerImpl.h> +#include <Swiften/Client/ClientSession.h> +#include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/FileTransfer/FileTransferManagerImpl.h> +#ifndef SWIFT_EXPERIMENTAL_FT +#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> +#endif namespace Swift { -Client::Client(const JID& jid, const std::string& password, NetworkFactories* networkFactories, Storages* storages) : CoreClient(jid, password, networkFactories), storages(storages) { +Client::Client(const JID& jid, const SafeString& password, NetworkFactories* networkFactories, Storages* storages) : CoreClient(jid, password, networkFactories), storages(storages) { memoryStorages = new MemoryStorages(); softwareVersionResponder = new SoftwareVersionResponder(getIQRouter()); softwareVersionResponder->start(); roster = new XMPPRosterImpl(); - rosterController = new XMPPRosterController(getIQRouter(), roster); + rosterController = new XMPPRosterController(getIQRouter(), roster, getStorages()->getRosterStorage()); subscriptionManager = new SubscriptionManager(getStanzaChannel()); @@ -58,9 +65,15 @@ Client::Client(const JID& jid, const std::string& password, NetworkFactories* ne nickResolver = new NickResolver(jid.toBare(), roster, vcardManager, mucRegistry); blindCertificateTrustChecker = new BlindCertificateTrustChecker(); + + jingleSessionManager = new JingleSessionManager(getIQRouter()); + fileTransferManager = NULL; } Client::~Client() { + delete fileTransferManager; + delete jingleSessionManager; + delete blindCertificateTrustChecker; delete nickResolver; @@ -97,7 +110,20 @@ void Client::setSoftwareVersion(const std::string& name, const std::string& vers softwareVersionResponder->setVersion(name, version, os); } +void Client::handleConnected() { +#ifdef SWIFT_EXPERIMENTAL_FT + fileTransferManager = new FileTransferManagerImpl(getJID(), jingleSessionManager, getIQRouter(), getEntityCapsProvider(), presenceOracle, getNetworkFactories()->getConnectionFactory(), getNetworkFactories()->getConnectionServerFactory(), getNetworkFactories()->getTimerFactory(), getNetworkFactories()->getNATTraverser()); +#else + fileTransferManager = new DummyFileTransferManager(); +#endif +} + void Client::requestRoster() { + // FIXME: We should set this once when the session is finished, but there + // is currently no callback for this + if (getSession()) { + rosterController->setUseVersioning(getSession()->getRosterVersioningSupported()); + } rosterController->requestRoster(); } @@ -133,4 +159,8 @@ NickManager* Client::getNickManager() const { return nickManager; } +FileTransferManager* Client::getFileTransferManager() const { + return fileTransferManager; +} + } diff --git a/Swiften/Client/Client.h b/Swiften/Client/Client.h index 083b8a0..940a526 100644 --- a/Swiften/Client/Client.h +++ b/Swiften/Client/Client.h @@ -6,7 +6,9 @@ #pragma once -#include "Swiften/Client/CoreClient.h" +#include <Swiften/Client/CoreClient.h> + +#include <Swiften/Base/SafeString.h> namespace Swift { class SoftwareVersionResponder; @@ -31,6 +33,9 @@ namespace Swift { class SubscriptionManager; class ClientDiscoManager; class NickManager; + class FileTransferManager; + class JingleSessionManager; + class FileTransferManager; /** * Provides the core functionality for writing XMPP client software. @@ -47,7 +52,7 @@ namespace Swift { * this is NULL, * all data will be stored in memory (and be lost on shutdown) */ - Client(const JID& jid, const std::string& password, NetworkFactories* networkFactories, Storages* storages = NULL); + Client(const JID& jid, const SafeString& password, NetworkFactories* networkFactories, Storages* storages = NULL); ~Client(); @@ -85,12 +90,12 @@ namespace Swift { /** * Returns the last received presence for the given (full) JID. */ - Presence::ref getLastPresence(const JID& jid) const; + boost::shared_ptr<Presence> getLastPresence(const JID& jid) const; /** * Returns the presence with the highest priority received for the given JID. */ - Presence::ref getHighestPriorityPresence(const JID& bareJID) const; + boost::shared_ptr<Presence> getHighestPriorityPresence(const JID& bareJID) const; PresenceOracle* getPresenceOracle() const { return presenceOracle; @@ -129,6 +134,14 @@ namespace Swift { ClientDiscoManager* getDiscoManager() const { return discoManager; } + + /** + * Returns a FileTransferManager for the client. This is only available after the onConnected + * signal has been fired. + * + * WARNING: File transfer will only work if Swiften is built in 'experimental' mode. + */ + FileTransferManager* getFileTransferManager() const; /** * Configures the client to always trust a non-validating @@ -142,11 +155,14 @@ namespace Swift { /** * This signal is emitted when a JID changes presence. */ - boost::signal<void (Presence::ref)> onPresenceChange; + boost::signal<void (boost::shared_ptr<Presence>)> onPresenceChange; private: Storages* getStorages() const; + protected: + void handleConnected(); + private: Storages* storages; MemoryStorages* memoryStorages; @@ -166,6 +182,8 @@ namespace Swift { SubscriptionManager* subscriptionManager; MUCManager* mucManager; ClientDiscoManager* discoManager; + JingleSessionManager* jingleSessionManager; + FileTransferManager* fileTransferManager; BlindCertificateTrustChecker* blindCertificateTrustChecker; }; } diff --git a/Swiften/Client/ClientBlockListManager.cpp b/Swiften/Client/ClientBlockListManager.cpp new file mode 100644 index 0000000..7222cea --- /dev/null +++ b/Swiften/Client/ClientBlockListManager.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/ClientBlockListManager.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <cassert> + +#include <Swiften/Client/BlockListImpl.h> + +using namespace Swift; + +namespace { + class BlockResponder : public SetResponder<BlockPayload> { + public: + BlockResponder(boost::shared_ptr<BlockListImpl> blockList, IQRouter* iqRouter) : SetResponder<BlockPayload>(iqRouter), blockList(blockList) { + } + + virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, boost::shared_ptr<BlockPayload> payload) { + if (getIQRouter()->isAccountJID(from)) { + if (payload) { + blockList->addItems(payload->getItems()); + } + sendResponse(from, id, boost::shared_ptr<BlockPayload>()); + } + else { + sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Cancel); + } + return true; + } + + private: + boost::shared_ptr<BlockListImpl> blockList; + }; + + class UnblockResponder : public SetResponder<UnblockPayload> { + public: + UnblockResponder(boost::shared_ptr<BlockListImpl> blockList, IQRouter* iqRouter) : SetResponder<UnblockPayload>(iqRouter), blockList(blockList) { + } + + virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, boost::shared_ptr<UnblockPayload> payload) { + if (getIQRouter()->isAccountJID(from)) { + if (payload) { + if (payload->getItems().empty()) { + blockList->removeAllItems(); + } + else { + blockList->removeItems(payload->getItems()); + } + } + sendResponse(from, id, boost::shared_ptr<UnblockPayload>()); + } + else { + sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Cancel); + } + return true; + } + + private: + boost::shared_ptr<BlockListImpl> blockList; + }; +} + +ClientBlockListManager::ClientBlockListManager(IQRouter* iqRouter) : iqRouter(iqRouter) { +} + +ClientBlockListManager::~ClientBlockListManager() { + unblockResponder->stop(); + blockResponder->stop(); + if (getRequest) { + getRequest->onResponse.disconnect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2)); + } +} + +boost::shared_ptr<BlockList> ClientBlockListManager::getBlockList() { + if (!blockList) { + blockList = boost::make_shared<BlockListImpl>(); + blockList->setState(BlockList::Requesting); + assert(!getRequest); + getRequest = boost::make_shared< GenericRequest<BlockListPayload> >(IQ::Get, JID(), boost::make_shared<BlockListPayload>(), iqRouter); + getRequest->onResponse.connect(boost::bind(&ClientBlockListManager::handleBlockListReceived, this, _1, _2)); + getRequest->send(); + } + return blockList; +} + +void ClientBlockListManager::handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref error) { + if (error || !payload) { + blockList->setState(BlockList::Error); + } + else { + blockList->setState(BlockList::Available); + blockList->setItems(payload->getItems()); + blockResponder = boost::make_shared<BlockResponder>(blockList, iqRouter); + blockResponder->start(); + unblockResponder = boost::make_shared<UnblockResponder>(blockList, iqRouter); + unblockResponder->start(); + } +} + diff --git a/Swiften/Client/ClientBlockListManager.h b/Swiften/Client/ClientBlockListManager.h new file mode 100644 index 0000000..21d35e3 --- /dev/null +++ b/Swiften/Client/ClientBlockListManager.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/BlockPayload.h> +#include <Swiften/Elements/BlockListPayload.h> +#include <Swiften/Elements/UnblockPayload.h> +#include <Swiften/Queries/SetResponder.h> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Client/BlockList.h> +#include <Swiften/Client/BlockListImpl.h> + +namespace Swift { + class IQRouter; + + class ClientBlockListManager { + public: + ClientBlockListManager(IQRouter *iqRouter); + ~ClientBlockListManager(); + + bool isSupported() const; + + /** + * Returns the blocklist. + */ + boost::shared_ptr<BlockList> getBlockList(); + + private: + void handleBlockListReceived(boost::shared_ptr<BlockListPayload> payload, ErrorPayload::ref); + + private: + IQRouter* iqRouter; + boost::shared_ptr<GenericRequest<BlockListPayload> > getRequest; + boost::shared_ptr<SetResponder<BlockPayload> > blockResponder; + boost::shared_ptr<SetResponder<UnblockPayload> > unblockResponder; + boost::shared_ptr<BlockListImpl> blockList; + }; +} + diff --git a/Swiften/Client/ClientOptions.h b/Swiften/Client/ClientOptions.h new file mode 100644 index 0000000..3b51a87 --- /dev/null +++ b/Swiften/Client/ClientOptions.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +namespace Swift { + struct ClientOptions { + enum UseTLS { + NeverUseTLS, + UseTLSWhenAvailable, + RequireTLS + }; + + ClientOptions() : useStreamCompression(true), useTLS(UseTLSWhenAvailable), allowPLAINWithoutTLS(false), useStreamResumption(false), forgetPassword(false), useAcks(true) { + } + + /** + * Whether ZLib stream compression should be used when available. + * + * Default: true + */ + bool useStreamCompression; + + /** + * Sets whether TLS encryption should be used. + * + * Default: UseTLSWhenAvailable + */ + UseTLS useTLS; + + /** + * Sets whether plaintext authentication is + * allowed over non-TLS-encrypted connections. + * + * Default: false + */ + bool allowPLAINWithoutTLS; + + /** + * Use XEP-196 stream resumption when available. + * + * Default: false + */ + bool useStreamResumption; + + /** + * Forget the password once it's used. + * This makes the Client useless after the first login attempt. + * + * FIXME: This is a temporary workaround. + * + * Default: false + */ + bool forgetPassword; + + /** + * Use XEP-0198 acks in the stream when available. + * Default: true + */ + bool useAcks; + }; +} diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp index e1c1d8e..791ee75 100644 --- a/Swiften/Client/ClientSession.cpp +++ b/Swiften/Client/ClientSession.cpp @@ -4,41 +4,42 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/ClientSession.h" +#include <Swiften/Client/ClientSession.h> #include <boost/bind.hpp> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_io.hpp> #include <boost/uuid/uuid_generators.hpp> +#include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Elements/StreamFeatures.h" -#include "Swiften/Elements/StreamError.h" -#include "Swiften/Elements/StartTLSRequest.h" -#include "Swiften/Elements/StartTLSFailure.h" -#include "Swiften/Elements/TLSProceed.h" -#include "Swiften/Elements/AuthRequest.h" -#include "Swiften/Elements/AuthSuccess.h" -#include "Swiften/Elements/AuthFailure.h" -#include "Swiften/Elements/AuthChallenge.h" -#include "Swiften/Elements/AuthResponse.h" -#include "Swiften/Elements/Compressed.h" -#include "Swiften/Elements/CompressFailure.h" -#include "Swiften/Elements/CompressRequest.h" -#include "Swiften/Elements/EnableStreamManagement.h" -#include "Swiften/Elements/StreamManagementEnabled.h" -#include "Swiften/Elements/StreamManagementFailed.h" -#include "Swiften/Elements/StartSession.h" -#include "Swiften/Elements/StanzaAck.h" -#include "Swiften/Elements/StanzaAckRequest.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/ResourceBind.h" -#include "Swiften/SASL/PLAINClientAuthenticator.h" -#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" -#include "Swiften/SASL/DIGESTMD5ClientAuthenticator.h" -#include "Swiften/Session/SessionStream.h" -#include "Swiften/TLS/CertificateTrustChecker.h" -#include "Swiften/TLS/ServerIdentityVerifier.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Elements/StreamFeatures.h> +#include <Swiften/Elements/StreamError.h> +#include <Swiften/Elements/StartTLSRequest.h> +#include <Swiften/Elements/StartTLSFailure.h> +#include <Swiften/Elements/TLSProceed.h> +#include <Swiften/Elements/AuthRequest.h> +#include <Swiften/Elements/AuthSuccess.h> +#include <Swiften/Elements/AuthFailure.h> +#include <Swiften/Elements/AuthChallenge.h> +#include <Swiften/Elements/AuthResponse.h> +#include <Swiften/Elements/Compressed.h> +#include <Swiften/Elements/CompressFailure.h> +#include <Swiften/Elements/CompressRequest.h> +#include <Swiften/Elements/EnableStreamManagement.h> +#include <Swiften/Elements/StreamManagementEnabled.h> +#include <Swiften/Elements/StreamManagementFailed.h> +#include <Swiften/Elements/StartSession.h> +#include <Swiften/Elements/StanzaAck.h> +#include <Swiften/Elements/StanzaAckRequest.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/ResourceBind.h> +#include <Swiften/SASL/PLAINClientAuthenticator.h> +#include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h> +#include <Swiften/SASL/DIGESTMD5ClientAuthenticator.h> +#include <Swiften/Session/SessionStream.h> +#include <Swiften/TLS/CertificateTrustChecker.h> +#include <Swiften/TLS/ServerIdentityVerifier.h> namespace Swift { @@ -51,9 +52,11 @@ ClientSession::ClientSession( allowPLAINOverNonTLS(false), useStreamCompression(true), useTLS(UseTLSWhenAvailable), + useAcks(true), needSessionStart(false), needResourceBind(false), needAcking(false), + rosterVersioningSupported(false), authenticator(NULL), certificateTrustChecker(NULL) { } @@ -173,17 +176,20 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption() && useTLS != NeverUseTLS) { state = WaitingForEncrypt; - stream->writeElement(boost::shared_ptr<StartTLSRequest>(new StartTLSRequest())); + stream->writeElement(boost::make_shared<StartTLSRequest>()); + } + else if (useTLS == RequireTLS && !stream->isTLSEncrypted()) { + finishSession(Error::NoSupportedAuthMechanismsError); } else if (useStreamCompression && streamFeatures->hasCompressionMethod("zlib")) { state = Compressing; - stream->writeElement(boost::shared_ptr<CompressRequest>(new CompressRequest("zlib"))); + stream->writeElement(boost::make_shared<CompressRequest>("zlib")); } else if (streamFeatures->hasAuthenticationMechanisms()) { if (stream->hasTLSCertificate()) { if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { state = Authenticating; - stream->writeElement(boost::shared_ptr<Element>(new AuthRequest("EXTERNAL", ""))); + stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); } else { finishSession(Error::TLSClientCertificateError); @@ -191,7 +197,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) { state = Authenticating; - stream->writeElement(boost::shared_ptr<Element>(new AuthRequest("EXTERNAL", ""))); + stream->writeElement(boost::make_shared<AuthRequest>("EXTERNAL", createSafeByteArray(""))); } else if (streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1") || streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1-PLUS")) { std::ostringstream s; @@ -223,10 +229,11 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { } else { // Start the session + rosterVersioningSupported = streamFeatures->hasRosterVersioning(); stream->setWhitespacePingEnabled(true); needSessionStart = streamFeatures->hasSession(); needResourceBind = streamFeatures->hasResourceBind(); - needAcking = streamFeatures->hasStreamManagement(); + needAcking = streamFeatures->hasStreamManagement() && useAcks; if (!needResourceBind) { // Resource binding is a MUST finishSession(Error::ResourceBindError); @@ -247,10 +254,10 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { finishSession(Error::CompressionFailedError); } else if (boost::dynamic_pointer_cast<StreamManagementEnabled>(element)) { - stanzaAckRequester_ = boost::shared_ptr<StanzaAckRequester>(new StanzaAckRequester()); + stanzaAckRequester_ = boost::make_shared<StanzaAckRequester>(); stanzaAckRequester_->onRequestAck.connect(boost::bind(&ClientSession::requestAck, shared_from_this())); stanzaAckRequester_->onStanzaAcked.connect(boost::bind(&ClientSession::handleStanzaAcked, shared_from_this(), _1)); - stanzaAckResponder_ = boost::shared_ptr<StanzaAckResponder>(new StanzaAckResponder()); + stanzaAckResponder_ = boost::make_shared<StanzaAckResponder>(); stanzaAckResponder_->onAck.connect(boost::bind(&ClientSession::ack, shared_from_this(), _1)); needAcking = false; continueSessionInitialization(); @@ -263,7 +270,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { checkState(Authenticating); assert(authenticator); if (authenticator->setChallenge(challenge->getValue())) { - stream->writeElement(boost::shared_ptr<AuthResponse>(new AuthResponse(authenticator->getResponse()))); + stream->writeElement(boost::make_shared<AuthResponse>(authenticator->getResponse())); } else { finishSession(Error::AuthenticationFailedError); @@ -272,6 +279,8 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { else if (AuthSuccess* authSuccess = dynamic_cast<AuthSuccess*>(element.get())) { checkState(Authenticating); if (authenticator && !authenticator->setChallenge(authSuccess->getValue())) { + delete authenticator; + authenticator = NULL; finishSession(Error::ServerVerificationFailedError); } else { @@ -305,7 +314,7 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) { void ClientSession::continueSessionInitialization() { if (needResourceBind) { state = BindingResource; - boost::shared_ptr<ResourceBind> resourceBind(new ResourceBind()); + boost::shared_ptr<ResourceBind> resourceBind(boost::make_shared<ResourceBind>()); if (!localJID.getResource().empty()) { resourceBind->setResource(localJID.getResource()); } @@ -313,11 +322,11 @@ void ClientSession::continueSessionInitialization() { } else if (needAcking) { state = EnablingSessionManagement; - stream->writeElement(boost::shared_ptr<EnableStreamManagement>(new EnableStreamManagement())); + stream->writeElement(boost::make_shared<EnableStreamManagement>()); } else if (needSessionStart) { state = StartingSession; - sendStanza(IQ::createRequest(IQ::Set, JID(), "session-start", boost::shared_ptr<StartSession>(new StartSession()))); + sendStanza(IQ::createRequest(IQ::Set, JID(), "session-start", boost::make_shared<StartSession>())); } else { state = Initialized; @@ -333,11 +342,11 @@ bool ClientSession::checkState(State state) { return true; } -void ClientSession::sendCredentials(const std::string& password) { +void ClientSession::sendCredentials(const SafeByteArray& password) { assert(WaitingForCredentials); state = Authenticating; authenticator->setCredentials(localJID.getNode(), password); - stream->writeElement(boost::shared_ptr<AuthRequest>(new AuthRequest(authenticator->getName(), authenticator->getResponse()))); + stream->writeElement(boost::make_shared<AuthRequest>(authenticator->getName(), authenticator->getResponse())); } void ClientSession::handleTLSEncrypted() { @@ -354,8 +363,7 @@ void ClientSession::handleTLSEncrypted() { continueAfterTLSEncrypted(); } else { - boost::shared_ptr<CertificateVerificationError> identityError(new CertificateVerificationError(CertificateVerificationError::InvalidServerIdentity)); - checkTrustOrFinish(certificate, identityError); + checkTrustOrFinish(certificate, boost::make_shared<CertificateVerificationError>(CertificateVerificationError::InvalidServerIdentity)); } } } @@ -407,19 +415,22 @@ void ClientSession::finish() { } void ClientSession::finishSession(Error::Type error) { - finishSession(boost::shared_ptr<Swift::ClientSession::Error>(new Swift::ClientSession::Error(error))); + finishSession(boost::make_shared<Swift::ClientSession::Error>(error)); } void ClientSession::finishSession(boost::shared_ptr<Swift::Error> error) { state = Finishing; error_ = error; assert(stream->isOpen()); + if (stanzaAckResponder_) { + stanzaAckResponder_->handleAckRequestReceived(); + } stream->writeFooter(); stream->close(); } void ClientSession::requestAck() { - stream->writeElement(boost::shared_ptr<StanzaAckRequest>(new StanzaAckRequest())); + stream->writeElement(boost::make_shared<StanzaAckRequest>()); } void ClientSession::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) { @@ -427,7 +438,7 @@ void ClientSession::handleStanzaAcked(boost::shared_ptr<Stanza> stanza) { } void ClientSession::ack(unsigned int handledStanzasCount) { - stream->writeElement(boost::shared_ptr<StanzaAck>(new StanzaAck(handledStanzasCount))); + stream->writeElement(boost::make_shared<StanzaAck>(handledStanzasCount)); } } diff --git a/Swiften/Client/ClientSession.h b/Swiften/Client/ClientSession.h index 25ee694..2205c8d 100644 --- a/Swiften/Client/ClientSession.h +++ b/Swiften/Client/ClientSession.h @@ -6,17 +6,17 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/Base/Error.h" -#include "Swiften/Session/SessionStream.h" +#include <Swiften/Base/Error.h> +#include <Swiften/Session/SessionStream.h> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/Element.h" -#include "Swiften/StreamManagement/StanzaAckRequester.h" -#include "Swiften/StreamManagement/StanzaAckResponder.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Element.h> +#include <Swiften/StreamManagement/StanzaAckRequester.h> +#include <Swiften/StreamManagement/StanzaAckResponder.h> namespace Swift { class ClientAuthenticator; @@ -59,7 +59,8 @@ namespace Swift { enum UseTLS { NeverUseTLS, - UseTLSWhenAvailable + UseTLSWhenAvailable, + RequireTLS }; ~ClientSession(); @@ -84,11 +85,19 @@ namespace Swift { useTLS = b; } + void setUseAcks(bool b) { + useAcks = b; + } + bool getStreamManagementEnabled() const { return stanzaAckRequester_; } + bool getRosterVersioningSupported() const { + return rosterVersioningSupported; + } + const JID& getLocalJID() const { return localJID; } @@ -100,7 +109,7 @@ namespace Swift { return getState() == Finished; } - void sendCredentials(const std::string& password); + void sendCredentials(const SafeByteArray& password); void sendStanza(boost::shared_ptr<Stanza>); void setCertificateTrustChecker(CertificateTrustChecker* checker) { @@ -150,9 +159,11 @@ namespace Swift { bool allowPLAINOverNonTLS; bool useStreamCompression; UseTLS useTLS; + bool useAcks; bool needSessionStart; bool needResourceBind; bool needAcking; + bool rosterVersioningSupported; ClientAuthenticator* authenticator; boost::shared_ptr<StanzaAckRequester> stanzaAckRequester_; boost::shared_ptr<StanzaAckResponder> stanzaAckResponder_; diff --git a/Swiften/Client/ClientSessionStanzaChannel.cpp b/Swiften/Client/ClientSessionStanzaChannel.cpp index 6b32b3d..5dc0a42 100644 --- a/Swiften/Client/ClientSessionStanzaChannel.cpp +++ b/Swiften/Client/ClientSessionStanzaChannel.cpp @@ -4,9 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/ClientSessionStanzaChannel.h" +#include <Swiften/Client/ClientSessionStanzaChannel.h> #include <boost/bind.hpp> +#include <iostream> namespace Swift { diff --git a/Swiften/Client/ClientSessionStanzaChannel.h b/Swiften/Client/ClientSessionStanzaChannel.h index 8a56301..47fb50e 100644 --- a/Swiften/Client/ClientSessionStanzaChannel.h +++ b/Swiften/Client/ClientSessionStanzaChannel.h @@ -8,12 +8,12 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Base/IDGenerator.h" -#include "Swiften/Client/ClientSession.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Client/ClientSession.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Presence.h> namespace Swift { /** diff --git a/Swiften/Client/ClientXMLTracer.cpp b/Swiften/Client/ClientXMLTracer.cpp new file mode 100644 index 0000000..c1093eb --- /dev/null +++ b/Swiften/Client/ClientXMLTracer.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/ClientXMLTracer.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +ClientXMLTracer::ClientXMLTracer(CoreClient* client) { + beautifier = new XMLBeautifier(true, true); + client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, this, '<', _1)); + client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, this, '>', _1)); +} + +ClientXMLTracer::~ClientXMLTracer() { + delete beautifier; +} + +void ClientXMLTracer::printData(char direction, const SafeByteArray& data) { + printLine(direction); + std::cerr << beautifier->beautify(byteArrayToString(ByteArray(data.begin(), data.end()))) << std::endl; +} + +void ClientXMLTracer::printLine(char c) { + for (unsigned int i = 0; i < 80; ++i) { + std::cerr << c; + } + std::cerr << std::endl; +} + +} diff --git a/Swiften/Client/ClientXMLTracer.h b/Swiften/Client/ClientXMLTracer.h index bca2a54..0752faa 100644 --- a/Swiften/Client/ClientXMLTracer.h +++ b/Swiften/Client/ClientXMLTracer.h @@ -6,29 +6,20 @@ #pragma once -#include <boost/bind.hpp> - #include <Swiften/Client/CoreClient.h> +#include <Swiften/Client/XMLBeautifier.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class ClientXMLTracer { public: - ClientXMLTracer(CoreClient* client) { - client->onDataRead.connect(boost::bind(&ClientXMLTracer::printData, '<', _1)); - client->onDataWritten.connect(boost::bind(&ClientXMLTracer::printData, '>', _1)); - } - + ClientXMLTracer(CoreClient* client); + ~ClientXMLTracer(); private: - static void printData(char direction, const std::string& data) { - printLine(direction); - std::cerr << data << std::endl; - } + void printData(char direction, const SafeByteArray& data); + void printLine(char c); - static void printLine(char c) { - for (unsigned int i = 0; i < 80; ++i) { - std::cerr << c; - } - std::cerr << std::endl; - } + private: + XMLBeautifier *beautifier; }; } diff --git a/Swiften/Client/CoreClient.cpp b/Swiften/Client/CoreClient.cpp index 8799d4e..a223e3d 100644 --- a/Swiften/Client/CoreClient.cpp +++ b/Swiften/Client/CoreClient.cpp @@ -4,25 +4,31 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/CoreClient.h" +#include <Swiften/Client/CoreClient.h> #include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Client/ClientSession.h" -#include "Swiften/TLS/PlatformTLSFactories.h" -#include "Swiften/TLS/CertificateVerificationError.h" -#include "Swiften/Network/Connector.h" -#include "Swiften/Network/NetworkFactories.h" -#include "Swiften/TLS/PKCS12Certificate.h" -#include "Swiften/Session/BasicSessionStream.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Base/IDGenerator.h" -#include "Swiften/Client/ClientSessionStanzaChannel.h" +#include <Swiften/Base/IDGenerator.h> #include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Client/ClientSession.h> +#include <Swiften/TLS/PlatformTLSFactories.h> +#include <Swiften/TLS/CertificateVerificationError.h> +#include <Swiften/Network/ChainedConnector.h> +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/TLS/PKCS12Certificate.h> +#include <Swiften/Session/BasicSessionStream.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/ClientSessionStanzaChannel.h> +#include <Swiften/Network/PlatformProxyProvider.h> +#include <Swiften/Network/SOCKS5ProxiedConnectionFactory.h> +#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> namespace Swift { -CoreClient::CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), useStreamCompression(true), useTLS(UseTLSWhenAvailable), disconnectRequested_(false), certificateTrustChecker(NULL) { +CoreClient::CoreClient(const JID& jid, const SafeByteArray& password, NetworkFactories* networkFactories) : jid_(jid), password_(password), networkFactories(networkFactories), disconnectRequested_(false), certificateTrustChecker(NULL) { stanzaChannel_ = new ClientSessionStanzaChannel(); stanzaChannel_->onMessageReceived.connect(boost::bind(&CoreClient::handleMessageReceived, this, _1)); stanzaChannel_->onPresenceReceived.connect(boost::bind(&CoreClient::handlePresenceReceived, this, _1)); @@ -48,8 +54,9 @@ CoreClient::~CoreClient() { delete stanzaChannel_; } -void CoreClient::connect() { +void CoreClient::connect(const ClientOptions& o) { SWIFT_LOG(debug) << "Connecting" << std::endl; + options = o; connect(jid_.getDomain()); } @@ -57,7 +64,19 @@ void CoreClient::connect(const std::string& host) { SWIFT_LOG(debug) << "Connecting to host " << host << std::endl; disconnectRequested_ = false; assert(!connector_); - connector_ = Connector::create(host, networkFactories->getDomainNameResolver(), networkFactories->getConnectionFactory(), networkFactories->getTimerFactory()); + + assert(proxyConnectionFactories.empty()); + PlatformProxyProvider proxyProvider; + if(proxyProvider.getSOCKS5Proxy().isValid()) { + proxyConnectionFactories.push_back(new SOCKS5ProxiedConnectionFactory(networkFactories->getConnectionFactory(), proxyProvider.getSOCKS5Proxy())); + } + if(proxyProvider.getHTTPConnectProxy().isValid()) { + proxyConnectionFactories.push_back(new HTTPConnectProxiedConnectionFactory(networkFactories->getConnectionFactory(), proxyProvider.getHTTPConnectProxy())); + } + std::vector<ConnectionFactory*> connectionFactories(proxyConnectionFactories); + connectionFactories.push_back(networkFactories->getConnectionFactory()); + + connector_ = boost::make_shared<ChainedConnector>(host, networkFactories->getDomainNameResolver(), connectionFactories, networkFactories->getTimerFactory()); connector_->onConnectFinished.connect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); connector_->setTimeoutMilliseconds(60*1000); connector_->start(); @@ -66,7 +85,15 @@ void CoreClient::connect(const std::string& host) { void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connection) { connector_->onConnectFinished.disconnect(boost::bind(&CoreClient::handleConnectorFinished, this, _1)); connector_.reset(); + foreach(ConnectionFactory* f, proxyConnectionFactories) { + delete f; + } + proxyConnectionFactories.clear(); + if (!connection) { + if (options.forgetPassword) { + purgePassword(); + } onDisconnected(disconnectRequested_ ? boost::optional<ClientError>() : boost::optional<ClientError>(ClientError::ConnectionError)); } else { @@ -74,7 +101,7 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio connection_ = connection; assert(!sessionStream_); - sessionStream_ = boost::shared_ptr<BasicSessionStream>(new BasicSessionStream(ClientStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), tlsFactories->getTLSContextFactory(), networkFactories->getTimerFactory())); + sessionStream_ = boost::make_shared<BasicSessionStream>(ClientStreamType, connection_, getPayloadParserFactories(), getPayloadSerializers(), tlsFactories->getTLSContextFactory(), networkFactories->getTimerFactory()); if (!certificate_.empty()) { sessionStream_->setTLSCertificate(PKCS12Certificate(certificate_, password_)); } @@ -83,15 +110,20 @@ void CoreClient::handleConnectorFinished(boost::shared_ptr<Connection> connectio session_ = ClientSession::create(jid_, sessionStream_); session_->setCertificateTrustChecker(certificateTrustChecker); - session_->setUseStreamCompression(useStreamCompression); - switch(useTLS) { - case UseTLSWhenAvailable: + session_->setUseStreamCompression(options.useStreamCompression); + session_->setAllowPLAINOverNonTLS(options.allowPLAINWithoutTLS); + switch(options.useTLS) { + case ClientOptions::UseTLSWhenAvailable: session_->setUseTLS(ClientSession::UseTLSWhenAvailable); break; - case NeverUseTLS: + case ClientOptions::NeverUseTLS: session_->setUseTLS(ClientSession::NeverUseTLS); break; + case ClientOptions::RequireTLS: + session_->setUseTLS(ClientSession::RequireTLS); + break; } + session_->setUseAcks(options.useAcks); stanzaChannel_->setSession(session_); session_->onFinished.connect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); session_->onNeedCredentials.connect(boost::bind(&CoreClient::handleNeedCredentials, this)); @@ -116,6 +148,9 @@ void CoreClient::setCertificate(const std::string& certificate) { } void CoreClient::handleSessionFinished(boost::shared_ptr<Error> error) { + if (options.forgetPassword) { + purgePassword(); + } session_->onFinished.disconnect(boost::bind(&CoreClient::handleSessionFinished, this, _1)); session_->onNeedCredentials.disconnect(boost::bind(&CoreClient::handleNeedCredentials, this)); @@ -227,18 +262,22 @@ void CoreClient::handleSessionFinished(boost::shared_ptr<Error> error) { void CoreClient::handleNeedCredentials() { assert(session_); session_->sendCredentials(password_); + if (options.forgetPassword) { + purgePassword(); + } } -void CoreClient::handleDataRead(const std::string& data) { +void CoreClient::handleDataRead(const SafeByteArray& data) { onDataRead(data); } -void CoreClient::handleDataWritten(const std::string& data) { +void CoreClient::handleDataWritten(const SafeByteArray& data) { onDataWritten(data); } void CoreClient::handleStanzaChannelAvailableChanged(bool available) { if (available) { + handleConnected(); onConnected(); } } @@ -276,13 +315,29 @@ void CoreClient::handleStanzaAcked(Stanza::ref stanza) { onStanzaAcked(stanza); } -void CoreClient::setUseStreamCompression(bool b) { - useStreamCompression = b; +bool CoreClient::isAvailable() const { + return stanzaChannel_->isAvailable(); +} + +bool CoreClient::getStreamManagementEnabled() const { + return stanzaChannel_->getStreamManagementEnabled(); } -void CoreClient::setUseTLS(UseTLS b) { - useTLS = b; +StanzaChannel* CoreClient::getStanzaChannel() const { + return stanzaChannel_; } +const JID& CoreClient::getJID() const { + if (session_) { + return session_->getLocalJID(); + } + else { + return jid_; + } +} + +void CoreClient::purgePassword() { + safeClear(password_); +} } diff --git a/Swiften/Client/CoreClient.h b/Swiften/Client/CoreClient.h index eb9c42c..3472e76 100644 --- a/Swiften/Client/CoreClient.h +++ b/Swiften/Client/CoreClient.h @@ -6,35 +6,34 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <string> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Network/PlatformDomainNameResolver.h" -#include "Swiften/Network/Connector.h" -#include "Swiften/Base/Error.h" -#include "Swiften/Client/ClientSession.h" -#include "Swiften/Client/ClientError.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/JID/JID.h" -#include <string> -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" #include <Swiften/Entity/Entity.h> - -#include "Swiften/Client/ClientSessionStanzaChannel.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Client/ClientError.h> +#include <Swiften/Client/ClientOptions.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { + class ChainedConnector; + class Message; + class Presence; + class Error; class IQRouter; class TLSContextFactory; class ConnectionFactory; + class Connection; class TimerFactory; class ClientSession; + class StanzaChannel; + class Stanza; class BasicSessionStream; class PlatformTLSFactories; class CertificateTrustChecker; class NetworkFactories; + class ClientSessionStanzaChannel; /** * The central class for communicating with an XMPP server. @@ -48,16 +47,11 @@ namespace Swift { */ class CoreClient : public Entity { public: - enum UseTLS { - NeverUseTLS, - UseTLSWhenAvailable - }; - /** * Constructs a client for the given JID with the given password. * The given eventLoop will be used to post events to. */ - CoreClient(const JID& jid, const std::string& password, NetworkFactories* networkFactories); + CoreClient(const JID& jid, const SafeByteArray& password, NetworkFactories* networkFactories); ~CoreClient(); void setCertificate(const std::string& certificate); @@ -68,7 +62,7 @@ namespace Swift { * After the connection is established, the client will set * initialize the stream and authenticate. */ - void connect(); + void connect(const ClientOptions& = ClientOptions()); /** * Disconnects the client from the server. @@ -80,12 +74,12 @@ namespace Swift { /** * Sends a message. */ - void sendMessage(Message::ref); + void sendMessage(boost::shared_ptr<Message>); /** * Sends a presence stanza. */ - void sendPresence(Presence::ref); + void sendPresence(boost::shared_ptr<Presence>); /** * Sends raw, unchecked data. @@ -103,9 +97,7 @@ namespace Swift { * Checks whether the client is connected to the server, * and stanzas can be sent. */ - bool isAvailable() const { - return stanzaChannel_->isAvailable(); - } + bool isAvailable() const; /** * Checks whether the client is active. @@ -118,14 +110,7 @@ namespace Swift { * Returns the JID of the client. * After the session was initialized, this returns the bound JID. */ - const JID& getJID() const { - if (session_) { - return session_->getLocalJID(); - } - else { - return jid_; - } - } + const JID& getJID() const; /** * Checks whether stream management is enabled. @@ -135,13 +120,9 @@ namespace Swift { * * \see onStanzaAcked */ - bool getStreamManagementEnabled() const { - return stanzaChannel_->getStreamManagementEnabled(); - } + bool getStreamManagementEnabled() const; - StanzaChannel* getStanzaChannel() const { - return stanzaChannel_; - } + StanzaChannel* getStanzaChannel() const; /** * Sets the certificate trust checker. @@ -153,16 +134,6 @@ namespace Swift { */ void setCertificateTrustChecker(CertificateTrustChecker*); - /** - * Sets whether ZLib stream compression should be used when available. - */ - void setUseStreamCompression(bool b); - - /** - * Sets whether TLS encryption should be used. - */ - void setUseTLS(UseTLS useTLS); - public: /** * Emitted when the client was disconnected from the network. @@ -184,7 +155,7 @@ namespace Swift { * This signal is emitted before the XML data is parsed, * so this data is unformatted. */ - boost::signal<void (const std::string&)> onDataRead; + boost::signal<void (const SafeByteArray&)> onDataRead; /** * Emitted when the client sends data. @@ -192,17 +163,17 @@ namespace Swift { * This signal is emitted after the XML was serialized, and * is unformatted. */ - boost::signal<void (const std::string&)> onDataWritten; + boost::signal<void (const SafeByteArray&)> onDataWritten; /** * Emitted when a message is received. */ - boost::signal<void (Message::ref)> onMessageReceived; + boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; /** * Emitted when a presence stanza is received. */ - boost::signal<void (Presence::ref) > onPresenceReceived; + boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived; /** * Emitted when the server acknowledges receipt of a @@ -210,28 +181,43 @@ namespace Swift { * * \see getStreamManagementEnabled() */ - boost::signal<void (Stanza::ref)> onStanzaAcked; + boost::signal<void (boost::shared_ptr<Stanza>)> onStanzaAcked; + + protected: + boost::shared_ptr<ClientSession> getSession() const { + return session_; + } + + NetworkFactories* getNetworkFactories() const { + return networkFactories; + } + + /** + * Called before onConnected signal is emmitted. + */ + virtual void handleConnected() {}; private: void handleConnectorFinished(boost::shared_ptr<Connection>); void handleStanzaChannelAvailableChanged(bool available); void handleSessionFinished(boost::shared_ptr<Error>); void handleNeedCredentials(); - void handleDataRead(const std::string&); - void handleDataWritten(const std::string&); - void handlePresenceReceived(Presence::ref); - void handleMessageReceived(Message::ref); - void handleStanzaAcked(Stanza::ref); + void handleDataRead(const SafeByteArray&); + void handleDataWritten(const SafeByteArray&); + void handlePresenceReceived(boost::shared_ptr<Presence>); + void handleMessageReceived(boost::shared_ptr<Message>); + void handleStanzaAcked(boost::shared_ptr<Stanza>); + void purgePassword(); private: JID jid_; - std::string password_; + SafeByteArray password_; NetworkFactories* networkFactories; - bool useStreamCompression; - UseTLS useTLS; ClientSessionStanzaChannel* stanzaChannel_; IQRouter* iqRouter_; - Connector::ref connector_; + ClientOptions options; + boost::shared_ptr<ChainedConnector> connector_; + std::vector<ConnectionFactory*> proxyConnectionFactories; PlatformTLSFactories* tlsFactories; boost::shared_ptr<Connection> connection_; boost::shared_ptr<BasicSessionStream> sessionStream_; diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index b9f05c3..c2f3919 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -8,7 +8,7 @@ #include <vector> -#include "Swiften/Client/StanzaChannel.h" +#include <Swiften/Client/StanzaChannel.h> namespace Swift { class DummyStanzaChannel : public StanzaChannel { @@ -56,6 +56,22 @@ namespace Swift { return iqStanza && iqStanza->getType() == type && iqStanza->getTo() == jid && iqStanza->getPayload<T>(); } + bool isResultAtIndex(size_t index, const std::string& id) { + if (index >= sentStanzas.size()) { + return false; + } + boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]); + return iqStanza && iqStanza->getType() == IQ::Result && iqStanza->getID() == id; + } + + bool isErrorAtIndex(size_t index, const std::string& id) { + if (index >= sentStanzas.size()) { + return false; + } + boost::shared_ptr<IQ> iqStanza = boost::dynamic_pointer_cast<IQ>(sentStanzas[index]); + return iqStanza && iqStanza->getType() == IQ::Error && iqStanza->getID() == id; + } + template<typename T> boost::shared_ptr<T> getStanzaAtIndex(size_t index) { if (sentStanzas.size() <= index) { return boost::shared_ptr<T>(); diff --git a/Swiften/Client/MemoryStorages.cpp b/Swiften/Client/MemoryStorages.cpp index 5f6371b..fe171f7 100644 --- a/Swiften/Client/MemoryStorages.cpp +++ b/Swiften/Client/MemoryStorages.cpp @@ -4,10 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/MemoryStorages.h" -#include "Swiften/VCards/VCardMemoryStorage.h" -#include "Swiften/Avatars/AvatarMemoryStorage.h" -#include "Swiften/Disco/CapsMemoryStorage.h" +#include <Swiften/Client/MemoryStorages.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/Disco/CapsMemoryStorage.h> +#include <Swiften/Roster/RosterMemoryStorage.h> namespace Swift { @@ -15,9 +16,11 @@ MemoryStorages::MemoryStorages() { vcardStorage = new VCardMemoryStorage(); capsStorage = new CapsMemoryStorage(); avatarStorage = new AvatarMemoryStorage(); + rosterStorage = new RosterMemoryStorage(); } MemoryStorages::~MemoryStorages() { + delete rosterStorage; delete avatarStorage; delete capsStorage; delete vcardStorage; @@ -35,4 +38,9 @@ AvatarStorage* MemoryStorages::getAvatarStorage() const { return avatarStorage; } +RosterStorage* MemoryStorages::getRosterStorage() const { + return rosterStorage; +} + + } diff --git a/Swiften/Client/MemoryStorages.h b/Swiften/Client/MemoryStorages.h index 67025cd..ca01a7a 100644 --- a/Swiften/Client/MemoryStorages.h +++ b/Swiften/Client/MemoryStorages.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Client/Storages.h" +#include <Swiften/Client/Storages.h> namespace Swift { class VCardMemoryStorage; @@ -23,10 +23,12 @@ namespace Swift { virtual VCardStorage* getVCardStorage() const; virtual AvatarStorage* getAvatarStorage() const; virtual CapsStorage* getCapsStorage() const; + virtual RosterStorage* getRosterStorage() const; private: VCardMemoryStorage* vcardStorage; AvatarStorage* avatarStorage; CapsStorage* capsStorage; + RosterStorage* rosterStorage; }; } diff --git a/Swiften/Client/NickResolver.cpp b/Swiften/Client/NickResolver.cpp index 6d5e742..e6f2e41 100644 --- a/Swiften/Client/NickResolver.cpp +++ b/Swiften/Client/NickResolver.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Client/NickResolver.h" +#include <Swiften/Client/NickResolver.h> #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/Roster/XMPPRoster.h" -#include "Swiften/VCards/VCardManager.h" +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Swiften/VCards/VCardManager.h> // FIXME: The NickResolver currently relies on the vcard being requested by the client on login. // The VCardManager should get an onConnected() signal (which is signalled when the stanzachannel is available(, and each time this is emitted, diff --git a/Swiften/Client/NickResolver.h b/Swiften/Client/NickResolver.h index 881362a..584f2ce 100644 --- a/Swiften/Client/NickResolver.h +++ b/Swiften/Client/NickResolver.h @@ -5,12 +5,12 @@ */ #include <map> -#include <boost/signals.hpp> #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/VCard.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/VCard.h> namespace Swift { class XMPPRoster; diff --git a/Swiften/Client/StanzaChannel.h b/Swiften/Client/StanzaChannel.h index 4d6392c..f1d76e0 100644 --- a/Swiften/Client/StanzaChannel.h +++ b/Swiften/Client/StanzaChannel.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Queries/IQChannel.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/Queries/IQChannel.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> namespace Swift { class StanzaChannel : public IQChannel { diff --git a/Swiften/Client/Storages.cpp b/Swiften/Client/Storages.cpp new file mode 100644 index 0000000..3c2dbc5 --- /dev/null +++ b/Swiften/Client/Storages.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Client/Storages.h> + +using namespace Swift; + +Storages::~Storages() { +} diff --git a/Swiften/Client/Storages.h b/Swiften/Client/Storages.h index e62f0a9..1c5bbe9 100644 --- a/Swiften/Client/Storages.h +++ b/Swiften/Client/Storages.h @@ -10,6 +10,7 @@ namespace Swift { class VCardStorage; class AvatarStorage; class CapsStorage; + class RosterStorage; /** * An interface to hold storage classes for different @@ -17,10 +18,11 @@ namespace Swift { */ class Storages { public: - virtual ~Storages() {} + virtual ~Storages(); virtual VCardStorage* getVCardStorage() const = 0; virtual AvatarStorage* getAvatarStorage() const = 0; virtual CapsStorage* getCapsStorage() const = 0; + virtual RosterStorage* getRosterStorage() const = 0; }; } diff --git a/Swiften/Client/UnitTest/ClientSessionTest.cpp b/Swiften/Client/UnitTest/ClientSessionTest.cpp index 756287c..e9d1b21 100644 --- a/Swiften/Client/UnitTest/ClientSessionTest.cpp +++ b/Swiften/Client/UnitTest/ClientSessionTest.cpp @@ -11,23 +11,25 @@ #include <boost/optional.hpp> #include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Session/SessionStream.h" -#include "Swiften/Client/ClientSession.h" -#include "Swiften/Elements/StartTLSRequest.h" -#include "Swiften/Elements/StreamFeatures.h" -#include "Swiften/Elements/StreamError.h" -#include "Swiften/Elements/TLSProceed.h" -#include "Swiften/Elements/StartTLSFailure.h" -#include "Swiften/Elements/AuthRequest.h" -#include "Swiften/Elements/AuthSuccess.h" -#include "Swiften/Elements/AuthFailure.h" -#include "Swiften/Elements/StreamManagementEnabled.h" -#include "Swiften/Elements/StreamManagementFailed.h" -#include "Swiften/Elements/EnableStreamManagement.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/ResourceBind.h" -#include "Swiften/TLS/SimpleCertificate.h" -#include "Swiften/TLS/BlindCertificateTrustChecker.h" +#include <Swiften/Session/SessionStream.h> +#include <Swiften/Client/ClientSession.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/StartTLSRequest.h> +#include <Swiften/Elements/StreamFeatures.h> +#include <Swiften/Elements/StreamError.h> +#include <Swiften/Elements/TLSProceed.h> +#include <Swiften/Elements/StartTLSFailure.h> +#include <Swiften/Elements/AuthRequest.h> +#include <Swiften/Elements/AuthSuccess.h> +#include <Swiften/Elements/AuthFailure.h> +#include <Swiften/Elements/StreamManagementEnabled.h> +#include <Swiften/Elements/StreamManagementFailed.h> +#include <Swiften/Elements/StanzaAck.h> +#include <Swiften/Elements/EnableStreamManagement.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/ResourceBind.h> +#include <Swiften/TLS/SimpleCertificate.h> +#include <Swiften/TLS/BlindCertificateTrustChecker.h> using namespace Swift; @@ -43,8 +45,11 @@ class ClientSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testAuthenticate); CPPUNIT_TEST(testAuthenticate_Unauthorized); CPPUNIT_TEST(testAuthenticate_NoValidAuthMechanisms); + CPPUNIT_TEST(testAuthenticate_PLAINOverNonTLS); + CPPUNIT_TEST(testAuthenticate_RequireTLS); CPPUNIT_TEST(testStreamManagement); CPPUNIT_TEST(testStreamManagement_Failed); + CPPUNIT_TEST(testFinishAcksStanzas); /* CPPUNIT_TEST(testResourceBind); CPPUNIT_TEST(testResourceBind_ChangeResource); @@ -178,7 +183,7 @@ class ClientSessionTest : public CppUnit::TestFixture { server->sendStreamFeaturesWithPLAINAuthentication(); CPPUNIT_ASSERT(needCredentials); CPPUNIT_ASSERT_EQUAL(ClientSession::WaitingForCredentials, session->getState()); - session->sendCredentials("mypass"); + session->sendCredentials(createSafeByteArray("mypass")); server->receiveAuthRequest("PLAIN"); server->sendAuthSuccess(); server->receiveStreamStart(); @@ -194,7 +199,7 @@ class ClientSessionTest : public CppUnit::TestFixture { server->sendStreamFeaturesWithPLAINAuthentication(); CPPUNIT_ASSERT(needCredentials); CPPUNIT_ASSERT_EQUAL(ClientSession::WaitingForCredentials, session->getState()); - session->sendCredentials("mypass"); + session->sendCredentials(createSafeByteArray("mypass")); server->receiveAuthRequest("PLAIN"); server->sendAuthFailure(); @@ -216,6 +221,20 @@ class ClientSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(sessionFinishedError); } + void testAuthenticate_RequireTLS() { + boost::shared_ptr<ClientSession> session(createSession()); + session->setUseTLS(ClientSession::RequireTLS); + session->setAllowPLAINOverNonTLS(true); + session->start(); + server->receiveStreamStart(); + server->sendStreamStart(); + server->sendStreamFeaturesWithMultipleAuthentication(); + + CPPUNIT_ASSERT_EQUAL(ClientSession::Finished, session->getState()); + CPPUNIT_ASSERT(sessionFinishedReceived); + CPPUNIT_ASSERT(sessionFinishedError); + } + void testAuthenticate_NoValidAuthMechanisms() { boost::shared_ptr<ClientSession> session(createSession()); session->start(); @@ -234,7 +253,7 @@ class ClientSessionTest : public CppUnit::TestFixture { server->receiveStreamStart(); server->sendStreamStart(); server->sendStreamFeaturesWithPLAINAuthentication(); - session->sendCredentials("mypass"); + session->sendCredentials(createSafeByteArray("mypass")); server->receiveAuthRequest("PLAIN"); server->sendAuthSuccess(); server->receiveStreamStart(); @@ -258,7 +277,7 @@ class ClientSessionTest : public CppUnit::TestFixture { server->receiveStreamStart(); server->sendStreamStart(); server->sendStreamFeaturesWithPLAINAuthentication(); - session->sendCredentials("mypass"); + session->sendCredentials(createSafeByteArray("mypass")); server->receiveAuthRequest("PLAIN"); server->sendAuthSuccess(); server->receiveStreamStart(); @@ -275,6 +294,17 @@ class ClientSessionTest : public CppUnit::TestFixture { session->finish(); } + void testFinishAcksStanzas() { + boost::shared_ptr<ClientSession> session(createSession()); + initializeSession(session); + server->sendMessage(); + server->sendMessage(); + server->sendMessage(); + + session->finish(); + + server->receiveAck(3); + } private: boost::shared_ptr<ClientSession> createSession() { @@ -285,6 +315,23 @@ class ClientSessionTest : public CppUnit::TestFixture { return session; } + void initializeSession(boost::shared_ptr<ClientSession> session) { + session->start(); + server->receiveStreamStart(); + server->sendStreamStart(); + server->sendStreamFeaturesWithPLAINAuthentication(); + session->sendCredentials(createSafeByteArray("mypass")); + server->receiveAuthRequest("PLAIN"); + server->sendAuthSuccess(); + server->receiveStreamStart(); + server->sendStreamStart(); + server->sendStreamFeaturesWithBindAndStreamManagement(); + server->receiveBind(); + server->sendBindResult(); + server->receiveStreamManagementEnable(); + server->sendStreamManagementEnabled(); + } + void handleSessionFinished(boost::shared_ptr<Error> error) { sessionFinishedReceived = true; sessionFinishedError = error; @@ -401,6 +448,14 @@ class ClientSessionTest : public CppUnit::TestFixture { onElementReceived(boost::shared_ptr<StartTLSFailure>(new StartTLSFailure())); } + void sendStreamFeaturesWithMultipleAuthentication() { + boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); + streamFeatures->addAuthenticationMechanism("PLAIN"); + streamFeatures->addAuthenticationMechanism("DIGEST-MD5"); + streamFeatures->addAuthenticationMechanism("SCRAM-SHA1"); + onElementReceived(streamFeatures); + } + void sendStreamFeaturesWithPLAINAuthentication() { boost::shared_ptr<StreamFeatures> streamFeatures(new StreamFeatures()); streamFeatures->addAuthenticationMechanism("PLAIN"); @@ -447,6 +502,12 @@ class ClientSessionTest : public CppUnit::TestFixture { onElementReceived(iq); } + void sendMessage() { + boost::shared_ptr<Message> message = boost::make_shared<Message>(); + message->setTo(JID("foo@bar.com/bla")); + onElementReceived(message); + } + void receiveStreamStart() { Event event = popEvent(); CPPUNIT_ASSERT(event.header); @@ -481,8 +542,16 @@ class ClientSessionTest : public CppUnit::TestFixture { bindID = iq->getID(); } + void receiveAck(unsigned int n) { + Event event = popEvent(); + CPPUNIT_ASSERT(event.element); + boost::shared_ptr<StanzaAck> ack = boost::dynamic_pointer_cast<StanzaAck>(event.element); + CPPUNIT_ASSERT(ack); + CPPUNIT_ASSERT_EQUAL(n, ack->getHandledStanzasCount()); + } + Event popEvent() { - CPPUNIT_ASSERT(receivedEvents.size() > 0); + CPPUNIT_ASSERT(!receivedEvents.empty()); Event event = receivedEvents.front(); receivedEvents.pop_front(); return event; diff --git a/Swiften/Client/UnitTest/NickResolverTest.cpp b/Swiften/Client/UnitTest/NickResolverTest.cpp index bd778d4..dfc90fe 100644 --- a/Swiften/Client/UnitTest/NickResolverTest.cpp +++ b/Swiften/Client/UnitTest/NickResolverTest.cpp @@ -7,13 +7,13 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Client/NickResolver.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/Roster/XMPPRosterImpl.h" -#include "Swiften/VCards/VCardManager.h" -#include "Swiften/VCards/VCardMemoryStorage.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Client/DummyStanzaChannel.h" +#include <Swiften/Client/NickResolver.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Roster/XMPPRosterImpl.h> +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; diff --git a/Swiften/Client/XMLBeautifier.cpp b/Swiften/Client/XMLBeautifier.cpp new file mode 100644 index 0000000..b70fc48 --- /dev/null +++ b/Swiften/Client/XMLBeautifier.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <sstream> +#include <stack> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Client/XMLBeautifier.h> +#include <Swiften/Parser/PlatformXMLParserFactory.h> + +namespace Swift { + +XMLBeautifier::XMLBeautifier(bool indention, bool coloring) : doIndention(indention), doColoring(coloring), intLevel(0), parser(NULL), lastWasStepDown(false) { + factory = new PlatformXMLParserFactory(); +} + +XMLBeautifier::~XMLBeautifier() { + delete factory; +} + +std::string XMLBeautifier::beautify(const std::string &text) { + parser = factory->createXMLParser(this); + intLevel = 0; + buffer.str(std::string()); + parser->parse(text); + delete parser; + return buffer.str(); +} + +void XMLBeautifier::indent() { + for (int i = 0; i < intLevel; ++i) { + buffer << " "; + } +} + +// all bold but reset +const char colorBlue[] = "\x1b[01;34m"; +const char colorCyan[] = "\x1b[01;36m"; +const char colorGreen[] = "\x1b[01;32m"; +const char colorMagenta[] = "\x1b[01;35m"; +const char colorRed[] = "\x1b[01;31m"; +const char colorReset[] = "\x1b[0m"; +const char colorYellow[] = "\x1b[01;33m"; + + + +std::string XMLBeautifier::styleTag(const std::string& text) const { + std::string result; + result += colorYellow; + result += text; + result += colorReset; + return result; +} + +std::string XMLBeautifier::styleNamespace(const std::string& text) const { + std::string result; + result += colorRed; + result += text; + result += colorReset; + return result; +} + +std::string XMLBeautifier::styleAttribute(const std::string& text) const { + std::string result; + result += colorGreen; + result += text; + result += colorReset; + return result; +} +std::string XMLBeautifier::styleValue(const std::string& text) const { + std::string result; + result += colorCyan; + result += text; + result += colorReset; + return result; +} + +void XMLBeautifier::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (doIndention) { + if (intLevel) buffer << std::endl; + } + indent(); + buffer << "<" << (doColoring ? styleTag(element) : element); + if (!ns.empty() && (!parentNSs.empty() && parentNSs.top() != ns)) { + buffer << " "; + buffer << (doColoring ? styleAttribute("xmlns") : "xmlns"); + buffer << "="; + buffer << "\"" << (doColoring ? styleNamespace(ns) : ns) << "\""; + } + if (!attributes.getEntries().empty()) { + foreach(AttributeMap::Entry entry, attributes.getEntries()) { + buffer << " "; + buffer << (doColoring ? styleAttribute(entry.getAttribute().getName()) : entry.getAttribute().getName()); + buffer << "="; + buffer << "\"" << (doColoring ? styleValue(entry.getValue()) : entry.getValue()) << "\""; + } + } + buffer << ">"; + ++intLevel; + lastWasStepDown = false; + parentNSs.push(ns); +} + +void XMLBeautifier::handleEndElement(const std::string& element, const std::string& /* ns */) { + --intLevel; + parentNSs.pop(); + if (/*hadCDATA.top() ||*/ lastWasStepDown) { + if (doIndention) { + buffer << std::endl; + } + indent(); + } + buffer << "</" << (doColoring ? styleTag(element) : element) << ">"; + lastWasStepDown = true; +} + +void XMLBeautifier::handleCharacterData(const std::string& data) { + buffer << data; + lastWasStepDown = false; +} + +} diff --git a/Swiften/Client/XMLBeautifier.h b/Swiften/Client/XMLBeautifier.h new file mode 100644 index 0000000..44dfd20 --- /dev/null +++ b/Swiften/Client/XMLBeautifier.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> +#include <stack> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Parser/XMLParserFactory.h> +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/XMLParser.h> + +namespace Swift { + +class XMLBeautifier : public XMLParserClient { +public: + XMLBeautifier(bool indention, bool coloring); + virtual ~XMLBeautifier(); + + std::string beautify(const std::string&); + +private: + void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); + void handleEndElement(const std::string& element, const std::string& ns); + void handleCharacterData(const std::string& data); + +private: + void indent(); + +private: + std::string styleTag(const std::string& text) const; + std::string styleNamespace(const std::string& text) const; + std::string styleAttribute(const std::string& text) const; + std::string styleValue(const std::string& text) const; + +private: + bool doIndention; + bool doColoring; + + int intLevel; + std::string inputBuffer; + std::stringstream buffer; + XMLParserFactory* factory; + XMLParser* parser; + + bool lastWasStepDown; + std::stack<std::string> parentNSs; +}; +} diff --git a/Swiften/Component/Component.cpp b/Swiften/Component/Component.cpp index fb4ba4c..af378a7 100644 --- a/Swiften/Component/Component.cpp +++ b/Swiften/Component/Component.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Component/Component.h" +#include <Swiften/Component/Component.h> -#include "Swiften/Queries/Responders/SoftwareVersionResponder.h" +#include <Swiften/Queries/Responders/SoftwareVersionResponder.h> namespace Swift { diff --git a/Swiften/Component/Component.h b/Swiften/Component/Component.h index 0119db0..0b29ff7 100644 --- a/Swiften/Component/Component.h +++ b/Swiften/Component/Component.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Component/CoreComponent.h" +#include <Swiften/Component/CoreComponent.h> namespace Swift { class SoftwareVersionResponder; diff --git a/Swiften/Component/ComponentConnector.cpp b/Swiften/Component/ComponentConnector.cpp index 2af45f6..b7bdd34 100644 --- a/Swiften/Component/ComponentConnector.cpp +++ b/Swiften/Component/ComponentConnector.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Component/ComponentConnector.h" +#include <Swiften/Component/ComponentConnector.h> #include <boost/bind.hpp> #include <iostream> -#include "Swiften/Network/ConnectionFactory.h" -#include "Swiften/Network/DomainNameResolver.h" -#include "Swiften/Network/DomainNameAddressQuery.h" -#include "Swiften/Network/TimerFactory.h" +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/TimerFactory.h> namespace Swift { diff --git a/Swiften/Component/ComponentConnector.h b/Swiften/Component/ComponentConnector.h index c5e8f80..b47f5da 100644 --- a/Swiften/Component/ComponentConnector.h +++ b/Swiften/Component/ComponentConnector.h @@ -7,14 +7,14 @@ #pragma once #include <deque> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/Timer.h" -#include "Swiften/Network/HostAddressPort.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/Network/HostAddressPort.h> #include <string> -#include "Swiften/Network/DomainNameResolveError.h" +#include <Swiften/Network/DomainNameResolveError.h> namespace Swift { class DomainNameAddressQuery; @@ -27,7 +27,7 @@ namespace Swift { typedef boost::shared_ptr<ComponentConnector> ref; static ComponentConnector::ref create(const std::string& hostname, int port, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { - return ComponentConnector::ref(new ComponentConnector(hostname, port, resolver, connectionFactory, timerFactory)); + return ref(new ComponentConnector(hostname, port, resolver, connectionFactory, timerFactory)); } void setTimeoutMilliseconds(int milliseconds); diff --git a/Swiften/Component/ComponentHandshakeGenerator.cpp b/Swiften/Component/ComponentHandshakeGenerator.cpp index 4081420..79ba9b3 100644 --- a/Swiften/Component/ComponentHandshakeGenerator.cpp +++ b/Swiften/Component/ComponentHandshakeGenerator.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Component/ComponentHandshakeGenerator.h" -#include "Swiften/StringCodecs/Hexify.h" -#include "Swiften/StringCodecs/SHA1.h" +#include <Swiften/Component/ComponentHandshakeGenerator.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/StringCodecs/SHA1.h> #include <Swiften/Base/String.h> namespace Swift { @@ -18,7 +18,7 @@ std::string ComponentHandshakeGenerator::getHandshake(const std::string& streamI String::replaceAll(concatenatedString, '>', ">"); String::replaceAll(concatenatedString, '\'', "'"); String::replaceAll(concatenatedString, '"', """); - return Hexify::hexify(SHA1::getHash(ByteArray(concatenatedString))); + return Hexify::hexify(SHA1::getHash(createByteArray(concatenatedString))); } } diff --git a/Swiften/Component/ComponentSession.cpp b/Swiften/Component/ComponentSession.cpp index 17e0dfd..af11146 100644 --- a/Swiften/Component/ComponentSession.cpp +++ b/Swiften/Component/ComponentSession.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Component/ComponentSession.h" +#include <Swiften/Component/ComponentSession.h> #include <boost/bind.hpp> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Elements/ComponentHandshake.h" -#include "Swiften/Session/SessionStream.h" -#include "Swiften/Component/ComponentHandshakeGenerator.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Elements/ComponentHandshake.h> +#include <Swiften/Session/SessionStream.h> +#include <Swiften/Component/ComponentHandshakeGenerator.h> namespace Swift { diff --git a/Swiften/Component/ComponentSession.h b/Swiften/Component/ComponentSession.h index 168e618..647bad7 100644 --- a/Swiften/Component/ComponentSession.h +++ b/Swiften/Component/ComponentSession.h @@ -9,13 +9,13 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/JID/JID.h" -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Base/Error.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/Error.h> #include <string> -#include "Swiften/Elements/Element.h" -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Session/SessionStream.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Session/SessionStream.h> namespace Swift { class ComponentAuthenticator; diff --git a/Swiften/Component/ComponentSessionStanzaChannel.cpp b/Swiften/Component/ComponentSessionStanzaChannel.cpp index b9fecb2..3e96dce 100644 --- a/Swiften/Component/ComponentSessionStanzaChannel.cpp +++ b/Swiften/Component/ComponentSessionStanzaChannel.cpp @@ -4,9 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Component/ComponentSessionStanzaChannel.h" +#include <Swiften/Component/ComponentSessionStanzaChannel.h> #include <boost/bind.hpp> +#include <iostream> namespace Swift { diff --git a/Swiften/Component/ComponentSessionStanzaChannel.h b/Swiften/Component/ComponentSessionStanzaChannel.h index 605c8dc..45f90b5 100644 --- a/Swiften/Component/ComponentSessionStanzaChannel.h +++ b/Swiften/Component/ComponentSessionStanzaChannel.h @@ -8,12 +8,12 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Base/IDGenerator.h" -#include "Swiften/Component/ComponentSession.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Component/ComponentSession.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Presence.h> namespace Swift { /** diff --git a/Swiften/Component/ComponentXMLTracer.cpp b/Swiften/Component/ComponentXMLTracer.cpp new file mode 100644 index 0000000..d77eef7 --- /dev/null +++ b/Swiften/Component/ComponentXMLTracer.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Component/ComponentXMLTracer.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +ComponentXMLTracer::ComponentXMLTracer(CoreComponent* client) { + client->onDataRead.connect(boost::bind(&ComponentXMLTracer::printData, '<', _1)); + client->onDataWritten.connect(boost::bind(&ComponentXMLTracer::printData, '>', _1)); +} + +void ComponentXMLTracer::printData(char direction, const SafeByteArray& data) { + printLine(direction); + std::cerr << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl; +} + +void ComponentXMLTracer::printLine(char c) { + for (unsigned int i = 0; i < 80; ++i) { + std::cerr << c; + } + std::cerr << std::endl; +} + +} diff --git a/Swiften/Component/ComponentXMLTracer.h b/Swiften/Component/ComponentXMLTracer.h index 70a617b..c12ec07 100644 --- a/Swiften/Component/ComponentXMLTracer.h +++ b/Swiften/Component/ComponentXMLTracer.h @@ -6,29 +6,15 @@ #pragma once -#include <boost/bind.hpp> - -#include "Swiften/Component/Component.h" +#include <Swiften/Component/Component.h> namespace Swift { class ComponentXMLTracer { public: - ComponentXMLTracer(Component* component) { - component->onDataRead.connect(boost::bind(&ComponentXMLTracer::printData, '<', _1)); - component->onDataWritten.connect(boost::bind(&ComponentXMLTracer::printData, '>', _1)); - } + ComponentXMLTracer(CoreComponent* component); private: - static void printData(char direction, const std::string& data) { - printLine(direction); - std::cerr << data << std::endl; - } - - static void printLine(char c) { - for (unsigned int i = 0; i < 80; ++i) { - std::cerr << c; - } - std::cerr << std::endl; - } + static void printData(char direction, const SafeByteArray& data); + static void printLine(char c); }; } diff --git a/Swiften/Component/CoreComponent.cpp b/Swiften/Component/CoreComponent.cpp index e79d735..7ee1ff5 100644 --- a/Swiften/Component/CoreComponent.cpp +++ b/Swiften/Component/CoreComponent.cpp @@ -4,18 +4,19 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Component/CoreComponent.h" +#include <Swiften/Component/CoreComponent.h> #include <boost/bind.hpp> +#include <iostream> -#include "Swiften/Component/ComponentSession.h" -#include "Swiften/Network/Connector.h" -#include "Swiften/Network/NetworkFactories.h" -#include "Swiften/TLS/PKCS12Certificate.h" -#include "Swiften/Session/BasicSessionStream.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Base/IDGenerator.h" -#include "Swiften/Component/ComponentSessionStanzaChannel.h" +#include <Swiften/Component/ComponentSession.h> +#include <Swiften/Network/Connector.h> +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/TLS/PKCS12Certificate.h> +#include <Swiften/Session/BasicSessionStream.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Component/ComponentSessionStanzaChannel.h> namespace Swift { @@ -138,11 +139,11 @@ void CoreComponent::handleSessionFinished(boost::shared_ptr<Error> error) { } } -void CoreComponent::handleDataRead(const std::string& data) { +void CoreComponent::handleDataRead(const SafeByteArray& data) { onDataRead(data); } -void CoreComponent::handleDataWritten(const std::string& data) { +void CoreComponent::handleDataWritten(const SafeByteArray& data) { onDataWritten(data); } diff --git a/Swiften/Component/CoreComponent.h b/Swiften/Component/CoreComponent.h index 64c9071..e7945d1 100644 --- a/Swiften/Component/CoreComponent.h +++ b/Swiften/Component/CoreComponent.h @@ -8,20 +8,21 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Base/Error.h" -#include "Swiften/Network/PlatformDomainNameResolver.h" -#include "Swiften/Component/ComponentConnector.h" -#include "Swiften/Component/ComponentSession.h" -#include "Swiften/Component/ComponentError.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/Error.h> +#include <Swiften/Network/PlatformDomainNameResolver.h> +#include <Swiften/Component/ComponentConnector.h> +#include <Swiften/Component/ComponentSession.h> +#include <Swiften/Component/ComponentError.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/JID/JID.h> #include <string> -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" -#include "Swiften/Component/ComponentSessionStanzaChannel.h" +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Component/ComponentSessionStanzaChannel.h> #include <Swiften/Entity/Entity.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class IQRouter; @@ -72,8 +73,8 @@ namespace Swift { public: boost::signal<void (const ComponentError&)> onError; boost::signal<void ()> onConnected; - boost::signal<void (const std::string&)> onDataRead; - boost::signal<void (const std::string&)> onDataWritten; + boost::signal<void (const SafeByteArray&)> onDataRead; + boost::signal<void (const SafeByteArray&)> onDataWritten; boost::signal<void (boost::shared_ptr<Message>)> onMessageReceived; boost::signal<void (boost::shared_ptr<Presence>) > onPresenceReceived; @@ -82,8 +83,8 @@ namespace Swift { void handleConnectorFinished(boost::shared_ptr<Connection>); void handleStanzaChannelAvailableChanged(bool available); void handleSessionFinished(boost::shared_ptr<Error>); - void handleDataRead(const std::string&); - void handleDataWritten(const std::string&); + void handleDataRead(const SafeByteArray&); + void handleDataWritten(const SafeByteArray&); private: EventLoop* eventLoop; diff --git a/Swiften/Component/SConscript b/Swiften/Component/SConscript index 0a9f250..ef5700c 100644 --- a/Swiften/Component/SConscript +++ b/Swiften/Component/SConscript @@ -7,6 +7,7 @@ sources = [ "ComponentSessionStanzaChannel.cpp", "CoreComponent.cpp", "Component.cpp", + "ComponentXMLTracer.cpp", ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) diff --git a/Swiften/Component/UnitTest/ComponentConnectorTest.cpp b/Swiften/Component/UnitTest/ComponentConnectorTest.cpp index 052b5de..1b2a36b 100644 --- a/Swiften/Component/UnitTest/ComponentConnectorTest.cpp +++ b/Swiften/Component/UnitTest/ComponentConnectorTest.cpp @@ -10,13 +10,13 @@ #include <boost/optional.hpp> #include <boost/bind.hpp> -#include "Swiften/Component/ComponentConnector.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/ConnectionFactory.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/Network/StaticDomainNameResolver.h" -#include "Swiften/Network/DummyTimerFactory.h" -#include "Swiften/EventLoop/DummyEventLoop.h" +#include <Swiften/Component/ComponentConnector.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; @@ -174,7 +174,7 @@ class ComponentConnectorTest : public CppUnit::TestFixture { } void disconnect() { assert(false); } - void write(const ByteArray&) { assert(false); } + void write(const SafeByteArray&) { assert(false); } HostAddressPort getLocalAddress() const { return HostAddressPort(); } EventLoop* eventLoop; diff --git a/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp b/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp index 5366478..fd8f6fc 100644 --- a/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp +++ b/Swiften/Component/UnitTest/ComponentHandshakeGeneratorTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Component/ComponentHandshakeGenerator.h" +#include <Swiften/Component/ComponentHandshakeGenerator.h> using namespace Swift; diff --git a/Swiften/Component/UnitTest/ComponentSessionTest.cpp b/Swiften/Component/UnitTest/ComponentSessionTest.cpp index 953973c..c27ade5 100644 --- a/Swiften/Component/UnitTest/ComponentSessionTest.cpp +++ b/Swiften/Component/UnitTest/ComponentSessionTest.cpp @@ -10,10 +10,10 @@ #include <boost/bind.hpp> #include <boost/optional.hpp> -#include "Swiften/Session/SessionStream.h" -#include "Swiften/Component/ComponentSession.h" -#include "Swiften/Elements/ComponentHandshake.h" -#include "Swiften/Elements/AuthFailure.h" +#include <Swiften/Session/SessionStream.h> +#include <Swiften/Component/ComponentSession.h> +#include <Swiften/Elements/ComponentHandshake.h> +#include <Swiften/Elements/AuthFailure.h> using namespace Swift; @@ -187,7 +187,7 @@ class ComponentSessionTest : public CppUnit::TestFixture { } Event popEvent() { - CPPUNIT_ASSERT(receivedEvents.size() > 0); + CPPUNIT_ASSERT(!receivedEvents.empty()); Event event = receivedEvents.front(); receivedEvents.pop_front(); return event; diff --git a/Swiften/Compress/UnitTest/ZLibCompressorTest.cpp b/Swiften/Compress/UnitTest/ZLibCompressorTest.cpp index 0b2fa5a..1de9322 100644 --- a/Swiften/Compress/UnitTest/ZLibCompressorTest.cpp +++ b/Swiften/Compress/UnitTest/ZLibCompressorTest.cpp @@ -4,12 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Compress/ZLibCompressor.h" +#include <Swiften/Compress/ZLibCompressor.h> using namespace Swift; @@ -26,17 +27,17 @@ class ZLibCompressorTest : public CppUnit::TestFixture void testProcess() { ZLibCompressor testling; - ByteArray result = testling.process("foo"); + SafeByteArray result = testling.process(createSafeByteArray("foo")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x78\xda\x4a\xcb\xcf\x07\x00\x00\x00\xff\xff", 11), result); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("\x78\xda\x4a\xcb\xcf\x07\x00\x00\x00\xff\xff", 11), result); } void testProcess_Twice() { ZLibCompressor testling; - testling.process("foo"); - ByteArray result = testling.process("bar"); + testling.process(createSafeByteArray("foo")); + SafeByteArray result = testling.process(createSafeByteArray("bar")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x4a\x4a\x2c\x02\x00\x00\x00\xff\xff",9), result); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("\x4a\x4a\x2c\x02\x00\x00\x00\xff\xff",9), result); } }; diff --git a/Swiften/Compress/UnitTest/ZLibDecompressorTest.cpp b/Swiften/Compress/UnitTest/ZLibDecompressorTest.cpp index 3ee5c4f..906c2dd 100644 --- a/Swiften/Compress/UnitTest/ZLibDecompressorTest.cpp +++ b/Swiften/Compress/UnitTest/ZLibDecompressorTest.cpp @@ -4,14 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Compress/ZLibDecompressor.h" -#include "Swiften/Compress/ZLibCompressor.h" -#include "Swiften/Compress/ZLibException.h" +#include <Swiften/Compress/ZLibDecompressor.h> +#include <Swiften/Compress/ZLibCompressor.h> +#include <Swiften/Compress/ZLibException.h> using namespace Swift; @@ -31,22 +32,22 @@ class ZLibDecompressorTest : public CppUnit::TestFixture void testProcess() { ZLibDecompressor testling; - ByteArray result = testling.process(ByteArray("\x78\xda\x4a\xcb\xcf\x07\x00\x00\x00\xff\xff", 11)); + SafeByteArray result = testling.process(createSafeByteArray("\x78\xda\x4a\xcb\xcf\x07\x00\x00\x00\xff\xff", 11)); - CPPUNIT_ASSERT_EQUAL(ByteArray("foo"), result); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("foo"), result); } void testProcess_Twice() { ZLibDecompressor testling; - testling.process(ByteArray("\x78\xda\x4a\xcb\xcf\x07\x00\x00\x00\xff\xff", 11)); - ByteArray result = testling.process(ByteArray("\x4a\x4a\x2c\x02\x00\x00\x00\xff\xff", 9)); + testling.process(createSafeByteArray("\x78\xda\x4a\xcb\xcf\x07\x00\x00\x00\xff\xff", 11)); + SafeByteArray result = testling.process(createSafeByteArray("\x4a\x4a\x2c\x02\x00\x00\x00\xff\xff", 9)); - CPPUNIT_ASSERT_EQUAL(ByteArray("bar"), result); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("bar"), result); } void testProcess_Invalid() { ZLibDecompressor testling; - CPPUNIT_ASSERT_THROW(testling.process(ByteArray("invalid")), ZLibException); + CPPUNIT_ASSERT_THROW(testling.process(createSafeByteArray("invalid")), ZLibException); } void testProcess_Huge() { @@ -55,9 +56,9 @@ class ZLibDecompressorTest : public CppUnit::TestFixture for (unsigned int i = 0; i < 2048; ++i) { data.push_back(static_cast<char>(i)); } - ByteArray original(&data[0], data.size()); - ByteArray compressed = ZLibCompressor().process(original); - ByteArray decompressed = ZLibDecompressor().process(compressed); + SafeByteArray original(createSafeByteArray(&data[0], data.size())); + SafeByteArray compressed = ZLibCompressor().process(original); + SafeByteArray decompressed = ZLibDecompressor().process(compressed); CPPUNIT_ASSERT_EQUAL(original, decompressed); } @@ -68,9 +69,9 @@ class ZLibDecompressorTest : public CppUnit::TestFixture for (unsigned int i = 0; i < 1024; ++i) { data.push_back(static_cast<char>(i)); } - ByteArray original(&data[0], data.size()); - ByteArray compressed = ZLibCompressor().process(original); - ByteArray decompressed = ZLibDecompressor().process(compressed); + SafeByteArray original(createSafeByteArray(&data[0], data.size())); + SafeByteArray compressed = ZLibCompressor().process(original); + SafeByteArray decompressed = ZLibDecompressor().process(compressed); CPPUNIT_ASSERT_EQUAL(original, decompressed); } diff --git a/Swiften/Compress/ZLibCodecompressor.cpp b/Swiften/Compress/ZLibCodecompressor.cpp index c093fb3..0869d6b 100644 --- a/Swiften/Compress/ZLibCodecompressor.cpp +++ b/Swiften/Compress/ZLibCodecompressor.cpp @@ -4,11 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Compress/ZLibCodecompressor.h" +#include <Swiften/Compress/ZLibCodecompressor.h> #include <cassert> +#include <string.h> -#include "Swiften/Compress/ZLibException.h" +#include <Swiften/Compress/ZLibException.h> namespace Swift { @@ -24,15 +25,15 @@ ZLibCodecompressor::ZLibCodecompressor() { ZLibCodecompressor::~ZLibCodecompressor() { } -ByteArray ZLibCodecompressor::process(const ByteArray& input) { - ByteArray output; - stream_.avail_in = input.getSize(); - stream_.next_in = reinterpret_cast<Bytef*>(const_cast<unsigned char*>(input.getData())); +SafeByteArray ZLibCodecompressor::process(const SafeByteArray& input) { + SafeByteArray output; + stream_.avail_in = input.size(); + stream_.next_in = reinterpret_cast<Bytef*>(const_cast<unsigned char*>(vecptr(input))); int outputPosition = 0; do { output.resize(outputPosition + CHUNK_SIZE); stream_.avail_out = CHUNK_SIZE; - stream_.next_out = reinterpret_cast<Bytef*>(output.getData() + outputPosition); + stream_.next_out = reinterpret_cast<Bytef*>(vecptr(output) + outputPosition); int result = processZStream(); if (result != Z_OK && result != Z_BUF_ERROR) { throw ZLibException(/* stream_.msg */); diff --git a/Swiften/Compress/ZLibCodecompressor.h b/Swiften/Compress/ZLibCodecompressor.h index 289704d..93babf0 100644 --- a/Swiften/Compress/ZLibCodecompressor.h +++ b/Swiften/Compress/ZLibCodecompressor.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ZLibCodecompressor_H -#define SWIFTEN_ZLibCodecompressor_H +#pragma once #include <zlib.h> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class ZLibCodecompressor { @@ -17,12 +16,10 @@ namespace Swift { ZLibCodecompressor(); virtual ~ZLibCodecompressor(); - ByteArray process(const ByteArray& data); + SafeByteArray process(const SafeByteArray& data); virtual int processZStream() = 0; protected: z_stream stream_; }; } - -#endif diff --git a/Swiften/Compress/ZLibCompressor.cpp b/Swiften/Compress/ZLibCompressor.cpp index 7e3116e..5d98e38 100644 --- a/Swiften/Compress/ZLibCompressor.cpp +++ b/Swiften/Compress/ZLibCompressor.cpp @@ -4,7 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Compress/ZLibCompressor.h" +#include <Swiften/Compress/ZLibCompressor.h> + +#include <cassert> #pragma GCC diagnostic ignored "-Wold-style-cast" diff --git a/Swiften/Compress/ZLibCompressor.h b/Swiften/Compress/ZLibCompressor.h index 7fe5387..1add725 100644 --- a/Swiften/Compress/ZLibCompressor.h +++ b/Swiften/Compress/ZLibCompressor.h @@ -6,10 +6,8 @@ #pragma once -#include <cassert> - -#include "Swiften/Compress/ZLibCodecompressor.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Compress/ZLibCodecompressor.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class ZLibCompressor : public ZLibCodecompressor { diff --git a/Swiften/Compress/ZLibDecompressor.cpp b/Swiften/Compress/ZLibDecompressor.cpp index af7349b..ab954f4 100644 --- a/Swiften/Compress/ZLibDecompressor.cpp +++ b/Swiften/Compress/ZLibDecompressor.cpp @@ -4,7 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Compress/ZLibDecompressor.h" +#include <Swiften/Compress/ZLibDecompressor.h> + +#include <cassert> #pragma GCC diagnostic ignored "-Wold-style-cast" diff --git a/Swiften/Compress/ZLibDecompressor.h b/Swiften/Compress/ZLibDecompressor.h index ec08a4f..67994d1 100644 --- a/Swiften/Compress/ZLibDecompressor.h +++ b/Swiften/Compress/ZLibDecompressor.h @@ -6,10 +6,8 @@ #pragma once -#include <cassert> - -#include "Swiften/Compress/ZLibCodecompressor.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Compress/ZLibCodecompressor.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class ZLibDecompressor : public ZLibCodecompressor { diff --git a/Swiften/Compress/ZLibException.h b/Swiften/Compress/ZLibException.h index 8e9fdb3..8e60aa3 100644 --- a/Swiften/Compress/ZLibException.h +++ b/Swiften/Compress/ZLibException.h @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ZLIBEXCEPTION_H -#define SWIFTEN_ZLIBEXCEPTION_H +#pragma once + namespace Swift { class ZLibException { @@ -13,5 +13,3 @@ namespace Swift { ZLibException() {} }; } - -#endif diff --git a/Swiften/Config/swiften-config.cpp b/Swiften/Config/swiften-config.cpp index b616711..81a8357 100644 --- a/Swiften/Config/swiften-config.cpp +++ b/Swiften/Config/swiften-config.cpp @@ -11,6 +11,7 @@ #include <boost/program_options/variables_map.hpp> #include <boost/program_options.hpp> #include <boost/version.hpp> +#include <boost/filesystem.hpp> #include <string> #include <Swiften/Base/Platform.h> diff --git a/Swiften/Disco/CapsFileStorage.cpp b/Swiften/Disco/CapsFileStorage.cpp deleted file mode 100644 index 1e53854..0000000 --- a/Swiften/Disco/CapsFileStorage.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/Disco/CapsFileStorage.h" - -#include <iostream> -#include <boost/filesystem/fstream.hpp> - -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" -#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h" -#include "Swiften/StringCodecs/Hexify.h" -#include "Swiften/StringCodecs/Base64.h" - -namespace Swift { - -CapsFileStorage::CapsFileStorage(const boost::filesystem::path& path) : path(path) { -} - -DiscoInfo::ref CapsFileStorage::getDiscoInfo(const std::string& hash) const { - boost::filesystem::path capsPath(getCapsPath(hash)); - if (boost::filesystem::exists(capsPath)) { - ByteArray data; - data.readFromFile(capsPath.string()); - - DiscoInfoParser parser; - PayloadParserTester tester(&parser); - tester.parse(data.toString()); - return boost::dynamic_pointer_cast<DiscoInfo>(parser.getPayload()); - } - else { - return DiscoInfo::ref(); - } -} - -void CapsFileStorage::setDiscoInfo(const std::string& hash, DiscoInfo::ref discoInfo) { - boost::filesystem::path capsPath(getCapsPath(hash)); - if (!boost::filesystem::exists(capsPath.parent_path())) { - try { - boost::filesystem::create_directories(capsPath.parent_path()); - } - catch (const boost::filesystem::filesystem_error& e) { - std::cerr << "ERROR: " << e.what() << std::endl; - } - } - DiscoInfo::ref bareDiscoInfo(new DiscoInfo(*discoInfo.get())); - bareDiscoInfo->setNode(""); - boost::filesystem::ofstream file(capsPath); - file << DiscoInfoSerializer().serializePayload(bareDiscoInfo); - file.close(); -} - -boost::filesystem::path CapsFileStorage::getCapsPath(const std::string& hash) const { - return path / (Hexify::hexify(Base64::decode(hash)) + ".xml"); -} - -} diff --git a/Swiften/Disco/CapsInfoGenerator.cpp b/Swiften/Disco/CapsInfoGenerator.cpp index 5c0e9a7..6d84984 100644 --- a/Swiften/Disco/CapsInfoGenerator.cpp +++ b/Swiften/Disco/CapsInfoGenerator.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/CapsInfoGenerator.h" +#include <Swiften/Disco/CapsInfoGenerator.h> #include <algorithm> -#include "Swiften/Base/foreach.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Elements/FormField.h" -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Elements/FormField.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Base64.h> namespace { bool compareFields(Swift::FormField::ref f1, Swift::FormField::ref f2) { @@ -57,7 +57,7 @@ CapsInfo CapsInfoGenerator::generateCapsInfo(const DiscoInfo& discoInfo) const { } } - std::string version(Base64::encode(SHA1::getHash(serializedCaps))); + std::string version(Base64::encode(SHA1::getHash(createByteArray(serializedCaps)))); return CapsInfo(node_, version, "sha-1"); } diff --git a/Swiften/Disco/CapsInfoGenerator.h b/Swiften/Disco/CapsInfoGenerator.h index 41a1d94..d1b2663 100644 --- a/Swiften/Disco/CapsInfoGenerator.h +++ b/Swiften/Disco/CapsInfoGenerator.h @@ -7,7 +7,7 @@ #pragma once #include <string> -#include "Swiften/Elements/CapsInfo.h" +#include <Swiften/Elements/CapsInfo.h> namespace Swift { class DiscoInfo; diff --git a/Swiften/Disco/CapsManager.cpp b/Swiften/Disco/CapsManager.cpp index b08a895..66eb47e 100644 --- a/Swiften/Disco/CapsManager.cpp +++ b/Swiften/Disco/CapsManager.cpp @@ -4,15 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/CapsManager.h" +#include <Swiften/Disco/CapsManager.h> #include <boost/bind.hpp> +#include <iostream> -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Disco/CapsStorage.h" -#include "Swiften/Disco/CapsInfoGenerator.h" -#include "Swiften/Elements/CapsInfo.h" -#include "Swiften/Disco/GetDiscoInfoRequest.h" +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Disco/CapsStorage.h> +#include <Swiften/Disco/CapsInfoGenerator.h> +#include <Swiften/Elements/CapsInfo.h> +#include <Swiften/Disco/GetDiscoInfoRequest.h> namespace Swift { diff --git a/Swiften/Disco/CapsManager.h b/Swiften/Disco/CapsManager.h index 961dae8..ddc7997 100644 --- a/Swiften/Disco/CapsManager.h +++ b/Swiften/Disco/CapsManager.h @@ -9,12 +9,12 @@ #include <set> #include <map> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Elements/CapsInfo.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/Disco/CapsProvider.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Elements/CapsInfo.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Disco/CapsProvider.h> namespace Swift { class StanzaChannel; diff --git a/Swiften/Disco/CapsMemoryStorage.h b/Swiften/Disco/CapsMemoryStorage.h index 1e2d7be..2503d7d 100644 --- a/Swiften/Disco/CapsMemoryStorage.h +++ b/Swiften/Disco/CapsMemoryStorage.h @@ -10,7 +10,7 @@ #include <map> #include <string> -#include "Swiften/Disco/CapsStorage.h" +#include <Swiften/Disco/CapsStorage.h> namespace Swift { class CapsMemoryStorage : public CapsStorage { diff --git a/Swiften/Disco/CapsProvider.h b/Swiften/Disco/CapsProvider.h index 71e2741..8bb3767 100644 --- a/Swiften/Disco/CapsProvider.h +++ b/Swiften/Disco/CapsProvider.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Elements/CapsInfo.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Elements/CapsInfo.h> namespace Swift { diff --git a/Swiften/Disco/CapsStorage.cpp b/Swiften/Disco/CapsStorage.cpp index acb58fe..fe4a6ac 100644 --- a/Swiften/Disco/CapsStorage.cpp +++ b/Swiften/Disco/CapsStorage.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/CapsStorage.h" +#include <Swiften/Disco/CapsStorage.h> namespace Swift { diff --git a/Swiften/Disco/CapsStorage.h b/Swiften/Disco/CapsStorage.h index f0a71a3..fb6e442 100644 --- a/Swiften/Disco/CapsStorage.h +++ b/Swiften/Disco/CapsStorage.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { diff --git a/Swiften/Disco/ClientDiscoManager.cpp b/Swiften/Disco/ClientDiscoManager.cpp index fb7cce9..99c0175 100644 --- a/Swiften/Disco/ClientDiscoManager.cpp +++ b/Swiften/Disco/ClientDiscoManager.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/ClientDiscoManager.h" +#include <Swiften/Disco/ClientDiscoManager.h> -#include "Swiften/Disco/DiscoInfoResponder.h" -#include "Swiften/Disco/CapsInfoGenerator.h" -#include "Swiften/Presence/PayloadAddingPresenceSender.h" +#include <Swiften/Disco/DiscoInfoResponder.h> +#include <Swiften/Disco/CapsInfoGenerator.h> +#include <Swiften/Presence/PayloadAddingPresenceSender.h> namespace Swift { diff --git a/Swiften/Disco/ClientDiscoManager.h b/Swiften/Disco/ClientDiscoManager.h index 3771044..f8ba9ac 100644 --- a/Swiften/Disco/ClientDiscoManager.h +++ b/Swiften/Disco/ClientDiscoManager.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Elements/CapsInfo.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Presence/PayloadAddingPresenceSender.h" +#include <Swiften/Elements/CapsInfo.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Presence/PayloadAddingPresenceSender.h> namespace Swift { class IQRouter; diff --git a/Swiften/Disco/DiscoInfoResponder.cpp b/Swiften/Disco/DiscoInfoResponder.cpp index 7ba044e..a8dd9f0 100644 --- a/Swiften/Disco/DiscoInfoResponder.cpp +++ b/Swiften/Disco/DiscoInfoResponder.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/DiscoInfoResponder.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Disco/DiscoInfoResponder.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { diff --git a/Swiften/Disco/DiscoInfoResponder.h b/Swiften/Disco/DiscoInfoResponder.h index f114a21..af9f48f 100644 --- a/Swiften/Disco/DiscoInfoResponder.h +++ b/Swiften/Disco/DiscoInfoResponder.h @@ -8,8 +8,8 @@ #include <map> -#include "Swiften/Queries/GetResponder.h" -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Queries/GetResponder.h> +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { class IQRouter; diff --git a/Swift/Controllers/DiscoServiceWalker.cpp b/Swiften/Disco/DiscoServiceWalker.cpp index ce29927..c8c3e1b 100644 --- a/Swift/Controllers/DiscoServiceWalker.cpp +++ b/Swiften/Disco/DiscoServiceWalker.cpp @@ -4,8 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <Swift/Controllers/DiscoServiceWalker.h> +#include <Swiften/Disco/DiscoServiceWalker.h> + #include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> #include <boost/bind.hpp> @@ -46,21 +48,6 @@ void DiscoServiceWalker::walkNode(const JID& jid) { discoInfoRequest->send(); } -void DiscoServiceWalker::handleReceivedDiscoItem(const JID& item) { - SWIFT_LOG(debug) << "Received disco item " << item << std::endl; - - /* If we got canceled, don't do anything */ - if (!active_) { - return; - } - - if (std::find(searchedServices_.begin(), searchedServices_.end(), item) != searchedServices_.end()) { - /* Don't recurse infinitely */ - return; - } - walkNode(item); -} - void DiscoServiceWalker::handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, GetDiscoInfoRequest::ref request) { /* If we got canceled, don't do anything */ if (!active_) { @@ -102,8 +89,7 @@ void DiscoServiceWalker::handleDiscoItemsResponse(boost::shared_ptr<DiscoItems> return; } - SWIFT_LOG(debug) << "Received disco item from " << request->getReceiver() << std::endl; - + SWIFT_LOG(debug) << "Received disco items from " << request->getReceiver() << std::endl; pendingDiscoItemsRequests_.erase(request); if (error) { handleDiscoError(request->getReceiver(), error); @@ -114,33 +100,25 @@ void DiscoServiceWalker::handleDiscoItemsResponse(boost::shared_ptr<DiscoItems> /* Don't look at noded items. It's possible that this will exclude some services, * but I've never seen one in the wild, and it's an easy fix for not looping. */ - handleReceivedDiscoItem(item.getJID()); + if (std::find(searchedServices_.begin(), searchedServices_.end(), item.getJID()) == searchedServices_.end()) { /* Don't recurse infinitely */ + SWIFT_LOG(debug) << "Received disco item " << item.getJID() << std::endl; + walkNode(item.getJID()); + } } } markNodeCompleted(request->getReceiver()); } void DiscoServiceWalker::handleDiscoError(const JID& jid, ErrorPayload::ref /*error*/) { - /* If we got canceled, don't do anything */ - if (!active_) { - return; - } - SWIFT_LOG(debug) << "Disco error from " << jid << std::endl; - markNodeCompleted(jid); } void DiscoServiceWalker::markNodeCompleted(const JID& jid) { - // Check whether we weren't canceled in between a 'emit result' and this call - if (!active_) { - return; - } SWIFT_LOG(debug) << "Node completed " << jid << std::endl; - servicesBeingSearched_.erase(jid); /* All results are in */ - if (servicesBeingSearched_.size() == 0) { + if (servicesBeingSearched_.empty()) { active_ = false; onWalkComplete(); } diff --git a/Swift/Controllers/DiscoServiceWalker.h b/Swiften/Disco/DiscoServiceWalker.h index 7982bbc..fd749fc 100644 --- a/Swift/Controllers/DiscoServiceWalker.h +++ b/Swiften/Disco/DiscoServiceWalker.h @@ -52,7 +52,6 @@ namespace Swift { boost::signal<void()> onWalkComplete; private: - void handleReceivedDiscoItem(const JID& item); void walkNode(const JID& jid); void markNodeCompleted(const JID& jid); void handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, GetDiscoInfoRequest::ref request); diff --git a/Swiften/Disco/DummyEntityCapsProvider.cpp b/Swiften/Disco/DummyEntityCapsProvider.cpp new file mode 100644 index 0000000..a906652 --- /dev/null +++ b/Swiften/Disco/DummyEntityCapsProvider.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Disco/DummyEntityCapsProvider.h> + +#include <iostream> + +namespace Swift { + +DiscoInfo::ref DummyEntityCapsProvider::getCaps(const JID& jid) const { + std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid); + if (i != caps.end()) { + return i->second; + } + return DiscoInfo::ref(); +} + +} diff --git a/Swiften/Disco/DummyEntityCapsProvider.h b/Swiften/Disco/DummyEntityCapsProvider.h index 68cef2f..a1e3db6 100644 --- a/Swiften/Disco/DummyEntityCapsProvider.h +++ b/Swiften/Disco/DummyEntityCapsProvider.h @@ -7,8 +7,8 @@ #pragma once #include <map> -#include <iostream> -#include "Swiften/Disco/EntityCapsProvider.h" + +#include <Swiften/Disco/EntityCapsProvider.h> namespace Swift { class DummyEntityCapsProvider : public EntityCapsProvider { @@ -16,13 +16,7 @@ namespace Swift { DummyEntityCapsProvider() { } - DiscoInfo::ref getCaps(const JID& jid) const { - std::map<JID, DiscoInfo::ref>::const_iterator i = caps.find(jid); - if (i != caps.end()) { - return i->second; - } - return DiscoInfo::ref(); - } + DiscoInfo::ref getCaps(const JID& jid) const; std::map<JID, DiscoInfo::ref> caps; }; diff --git a/Swiften/Disco/EntityCapsManager.cpp b/Swiften/Disco/EntityCapsManager.cpp index 3f2e3d7..1a9f5fb 100644 --- a/Swiften/Disco/EntityCapsManager.cpp +++ b/Swiften/Disco/EntityCapsManager.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/EntityCapsManager.h" +#include <Swiften/Disco/EntityCapsManager.h> #include <boost/bind.hpp> -#include "Swiften/Disco/CapsProvider.h" -#include "Swiften/Client/StanzaChannel.h" +#include <Swiften/Disco/CapsProvider.h> +#include <Swiften/Client/StanzaChannel.h> namespace Swift { diff --git a/Swiften/Disco/EntityCapsManager.h b/Swiften/Disco/EntityCapsManager.h index 190f876..e41c15f 100644 --- a/Swiften/Disco/EntityCapsManager.h +++ b/Swiften/Disco/EntityCapsManager.h @@ -8,11 +8,11 @@ #include <map> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/Disco/EntityCapsProvider.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Disco/EntityCapsProvider.h> namespace Swift { class StanzaChannel; diff --git a/Swiften/Disco/EntityCapsProvider.cpp b/Swiften/Disco/EntityCapsProvider.cpp index a337328..e3262b6 100644 --- a/Swiften/Disco/EntityCapsProvider.cpp +++ b/Swiften/Disco/EntityCapsProvider.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/EntityCapsProvider.h" +#include <Swiften/Disco/EntityCapsProvider.h> namespace Swift { diff --git a/Swiften/Disco/EntityCapsProvider.h b/Swiften/Disco/EntityCapsProvider.h index 07fa452..b38992c 100644 --- a/Swiften/Disco/EntityCapsProvider.h +++ b/Swiften/Disco/EntityCapsProvider.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { /** diff --git a/Swiften/Disco/GetDiscoInfoRequest.h b/Swiften/Disco/GetDiscoInfoRequest.h index 5cec530..e211632 100644 --- a/Swiften/Disco/GetDiscoInfoRequest.h +++ b/Swiften/Disco/GetDiscoInfoRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { class GetDiscoInfoRequest : public GenericRequest<DiscoInfo> { diff --git a/Swiften/Disco/GetDiscoItemsRequest.h b/Swiften/Disco/GetDiscoItemsRequest.h index 0a94402..20d18f8 100644 --- a/Swiften/Disco/GetDiscoItemsRequest.h +++ b/Swiften/Disco/GetDiscoItemsRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/DiscoItems.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/DiscoItems.h> namespace Swift { class GetDiscoItemsRequest : public GenericRequest<DiscoItems> { @@ -18,9 +18,18 @@ namespace Swift { return ref(new GetDiscoItemsRequest(jid, router)); } + static ref create(const JID& jid, const std::string& node, IQRouter* router) { + return ref(new GetDiscoItemsRequest(jid, node, router)); + } + private: GetDiscoItemsRequest(const JID& jid, IQRouter* router) : GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) { } + + GetDiscoItemsRequest(const JID& jid, const std::string& node, IQRouter* router) : + GenericRequest<DiscoItems>(IQ::Get, jid, boost::shared_ptr<DiscoItems>(new DiscoItems()), router) { + getPayloadGeneric()->setNode(node); + } }; } diff --git a/Swiften/Disco/JIDDiscoInfoResponder.cpp b/Swiften/Disco/JIDDiscoInfoResponder.cpp index 1298e5a..0a25bef 100644 --- a/Swiften/Disco/JIDDiscoInfoResponder.cpp +++ b/Swiften/Disco/JIDDiscoInfoResponder.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Disco/JIDDiscoInfoResponder.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Disco/JIDDiscoInfoResponder.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { diff --git a/Swiften/Disco/JIDDiscoInfoResponder.h b/Swiften/Disco/JIDDiscoInfoResponder.h index d532d0f..ebc1452 100644 --- a/Swiften/Disco/JIDDiscoInfoResponder.h +++ b/Swiften/Disco/JIDDiscoInfoResponder.h @@ -8,9 +8,9 @@ #include <map> -#include "Swiften/Queries/GetResponder.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Queries/GetResponder.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/JID/JID.h> namespace Swift { class IQRouter; diff --git a/Swiften/Disco/SConscript b/Swiften/Disco/SConscript index 9982192..c821b42 100644 --- a/Swiften/Disco/SConscript +++ b/Swiften/Disco/SConscript @@ -5,10 +5,11 @@ objects = swiften_env.SwiftenObject([ "CapsManager.cpp", "EntityCapsManager.cpp", "EntityCapsProvider.cpp", + "DummyEntityCapsProvider.cpp", "CapsStorage.cpp", - "CapsFileStorage.cpp", "ClientDiscoManager.cpp", "DiscoInfoResponder.cpp", "JIDDiscoInfoResponder.cpp", + "DiscoServiceWalker.cpp", ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp index d4cb331..52fdbaa 100644 --- a/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp +++ b/Swiften/Disco/UnitTest/CapsInfoGeneratorTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Disco/CapsInfoGenerator.h" +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Disco/CapsInfoGenerator.h> using namespace Swift; diff --git a/Swiften/Disco/UnitTest/CapsManagerTest.cpp b/Swiften/Disco/UnitTest/CapsManagerTest.cpp index 793fdba..0681569 100644 --- a/Swiften/Disco/UnitTest/CapsManagerTest.cpp +++ b/Swiften/Disco/UnitTest/CapsManagerTest.cpp @@ -9,13 +9,13 @@ #include <vector> #include <boost/bind.hpp> -#include "Swiften/Disco/CapsManager.h" -#include "Swiften/Disco/CapsMemoryStorage.h" -#include "Swiften/Disco/CapsInfoGenerator.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Elements/CapsInfo.h" -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Client/DummyStanzaChannel.h" +#include <Swiften/Disco/CapsManager.h> +#include <Swiften/Disco/CapsMemoryStorage.h> +#include <Swiften/Disco/CapsInfoGenerator.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/CapsInfo.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; @@ -64,7 +64,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveNewHashRequestsDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<DiscoInfo>(0, user1, IQ::Get)); @@ -74,7 +74,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSameHashDoesNotRequestDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->sentStanzas.clear(); sendPresenceWithCaps(user1, capsInfo1); @@ -83,14 +83,14 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveLegacyCapsDoesNotRequestDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, legacyCapsInfo); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testReceiveSameHashAfterSuccesfulDiscoDoesNotRequestDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo1); @@ -101,7 +101,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSameHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID())); @@ -112,7 +112,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSameHashFromSameUserAfterIncorrectVerificationDoesNotRequestDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo2); @@ -123,7 +123,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSameHashFromDifferentUserAfterFailedDiscoRequestsDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); @@ -133,7 +133,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSameHashFromDifferentUserAfterIncorrectVerificationRequestsDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo2); @@ -143,7 +143,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveDifferentHashFromSameUserAfterFailedDiscoDoesNotRequestDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getID())); @@ -154,7 +154,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSuccesfulDiscoStoresCaps() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo1); @@ -164,7 +164,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveIncorrectVerificationDiscoDoesNotStoreCaps() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendDiscoInfoResult(discoInfo2); @@ -173,7 +173,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveFailingDiscoFallsBack() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); @@ -185,7 +185,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveNoDiscoFallsBack() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); stanzaChannel->onIQReceived(IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID(), boost::shared_ptr<DiscoInfo>())); @@ -197,7 +197,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveFailingFallbackDiscoFallsBack() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); sendPresenceWithCaps(user3, capsInfo1); @@ -208,7 +208,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReceiveSameHashFromFailingUserAfterReconnectRequestsDisco() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); stanzaChannel->setAvailable(false); @@ -221,7 +221,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReconnectResetsFallback() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); sendPresenceWithCaps(user2, capsInfo1alt); stanzaChannel->setAvailable(false); @@ -234,7 +234,7 @@ class CapsManagerTest : public CppUnit::TestFixture { } void testReconnectResetsRequests() { - std::auto_ptr<CapsManager> testling = createManager(); + boost::shared_ptr<CapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); stanzaChannel->sentStanzas.clear(); stanzaChannel->setAvailable(false); @@ -245,8 +245,8 @@ class CapsManagerTest : public CppUnit::TestFixture { } private: - std::auto_ptr<CapsManager> createManager() { - std::auto_ptr<CapsManager> manager(new CapsManager(storage, stanzaChannel, iqRouter)); + boost::shared_ptr<CapsManager> createManager() { + boost::shared_ptr<CapsManager> manager(new CapsManager(storage, stanzaChannel, iqRouter)); manager->setWarnOnInvalidHash(false); //manager->onCapsChanged.connect(boost::bind(&CapsManagerTest::handleCapsChanged, this, _1)); return manager; diff --git a/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp b/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp index bccf0d4..1477e23 100644 --- a/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp +++ b/Swiften/Disco/UnitTest/DiscoInfoResponderTest.cpp @@ -8,9 +8,9 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <typeinfo> -#include "Swiften/Disco/DiscoInfoResponder.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/DummyIQChannel.h" +#include <Swiften/Disco/DiscoInfoResponder.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/DummyIQChannel.h> using namespace Swift; diff --git a/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp b/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp index 544bdad..7b61cb5 100644 --- a/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp +++ b/Swiften/Disco/UnitTest/EntityCapsManagerTest.cpp @@ -9,11 +9,11 @@ #include <vector> #include <boost/bind.hpp> -#include "Swiften/Disco/EntityCapsManager.h" -#include "Swiften/Disco/CapsProvider.h" -#include "Swiften/Elements/CapsInfo.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Disco/CapsInfoGenerator.h" +#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Disco/CapsProvider.h> +#include <Swiften/Elements/CapsInfo.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Disco/CapsInfoGenerator.h> using namespace Swift; @@ -52,7 +52,7 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } void testReceiveKnownHash() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); @@ -62,7 +62,7 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } void testReceiveKnownHashTwiceDoesNotTriggerChange() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); changes.clear(); @@ -73,14 +73,14 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } void testReceiveUnknownHashDoesNotTriggerChange() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(changes.size())); } void testHashAvailable() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); sendPresenceWithCaps(user1, capsInfo1); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; @@ -92,7 +92,7 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } void testReceiveUnknownHashAfterKnownHashTriggersChangeAndClearsCaps() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); changes.clear(); @@ -104,7 +104,7 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } void testReceiveUnavailablePresenceAfterKnownHashTriggersChangeAndClearsCaps() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; sendPresenceWithCaps(user1, capsInfo1); changes.clear(); @@ -116,7 +116,7 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } void testReconnectTriggersChangeAndClearsCaps() { - std::auto_ptr<EntityCapsManager> testling = createManager(); + boost::shared_ptr<EntityCapsManager> testling = createManager(); capsProvider->caps[capsInfo1->getVersion()] = discoInfo1; capsProvider->caps[capsInfo2->getVersion()] = discoInfo2; sendPresenceWithCaps(user1, capsInfo1); @@ -133,8 +133,8 @@ class EntityCapsManagerTest : public CppUnit::TestFixture { } private: - std::auto_ptr<EntityCapsManager> createManager() { - std::auto_ptr<EntityCapsManager> manager(new EntityCapsManager(capsProvider, stanzaChannel)); + boost::shared_ptr<EntityCapsManager> createManager() { + boost::shared_ptr<EntityCapsManager> manager(new EntityCapsManager(capsProvider, stanzaChannel)); manager->onCapsChanged.connect(boost::bind(&EntityCapsManagerTest::handleCapsChanged, this, _1)); return manager; } diff --git a/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp b/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp index ef61afa..7e2e3dd 100644 --- a/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp +++ b/Swiften/Disco/UnitTest/JIDDiscoInfoResponderTest.cpp @@ -8,9 +8,9 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <typeinfo> -#include "Swiften/Disco/JIDDiscoInfoResponder.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/DummyIQChannel.h" +#include <Swiften/Disco/JIDDiscoInfoResponder.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/DummyIQChannel.h> using namespace Swift; diff --git a/Swiften/Elements/AuthChallenge.h b/Swiften/Elements/AuthChallenge.h index 74d7dba..f7f2796 100644 --- a/Swiften/Elements/AuthChallenge.h +++ b/Swiften/Elements/AuthChallenge.h @@ -7,9 +7,9 @@ #pragma once #include <boost/optional.hpp> +#include <vector> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { class AuthChallenge : public Element { @@ -17,18 +17,18 @@ namespace Swift { AuthChallenge() { } - AuthChallenge(const ByteArray& value) : value(value) { + AuthChallenge(const std::vector<unsigned char>& value) : value(value) { } - const boost::optional<ByteArray>& getValue() const { + const boost::optional< std::vector<unsigned char> >& getValue() const { return value; } - void setValue(const ByteArray& value) { - this->value = boost::optional<ByteArray>(value); + void setValue(const std::vector<unsigned char>& value) { + this->value = boost::optional<std::vector<unsigned char> >(value); } private: - boost::optional<ByteArray> value; + boost::optional< std::vector<unsigned char> > value; }; } diff --git a/Swiften/Elements/AuthFailure.h b/Swiften/Elements/AuthFailure.h index 7ffc762..ac40956 100644 --- a/Swiften/Elements/AuthFailure.h +++ b/Swiften/Elements/AuthFailure.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { class AuthFailure : public Element { diff --git a/Swiften/Elements/AuthRequest.h b/Swiften/Elements/AuthRequest.h index ba86900..bfc86c2 100644 --- a/Swiften/Elements/AuthRequest.h +++ b/Swiften/Elements/AuthRequest.h @@ -6,10 +6,12 @@ #pragma once +#include <vector> +#include <string> #include <boost/optional.hpp> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class AuthRequest : public Element { @@ -17,20 +19,20 @@ namespace Swift { AuthRequest(const std::string& mechanism = "") : mechanism_(mechanism) { } - AuthRequest(const std::string& mechanism, const ByteArray& message) : + AuthRequest(const std::string& mechanism, const SafeByteArray& message) : mechanism_(mechanism), message_(message) { } - AuthRequest(const std::string& mechanism, const boost::optional<ByteArray>& message) : + AuthRequest(const std::string& mechanism, const boost::optional<SafeByteArray>& message) : mechanism_(mechanism), message_(message) { } - const boost::optional<ByteArray>& getMessage() const { + const boost::optional<SafeByteArray>& getMessage() const { return message_; } - void setMessage(const ByteArray& message) { - message_ = boost::optional<ByteArray>(message); + void setMessage(const SafeByteArray& message) { + message_ = boost::optional<SafeByteArray>(message); } const std::string& getMechanism() const { @@ -43,6 +45,6 @@ namespace Swift { private: std::string mechanism_; - boost::optional<ByteArray> message_; + boost::optional<SafeByteArray> message_; }; } diff --git a/Swiften/Elements/AuthResponse.h b/Swiften/Elements/AuthResponse.h index 96d1b13..db2dcea 100644 --- a/Swiften/Elements/AuthResponse.h +++ b/Swiften/Elements/AuthResponse.h @@ -6,10 +6,11 @@ #pragma once +#include <vector> #include <boost/optional.hpp> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class AuthResponse : public Element { @@ -17,21 +18,21 @@ namespace Swift { AuthResponse() { } - AuthResponse(const ByteArray& value) : value(value) { + AuthResponse(const SafeByteArray& value) : value(value) { } - AuthResponse(const boost::optional<ByteArray>& value) : value(value) { + AuthResponse(const boost::optional<SafeByteArray>& value) : value(value) { } - const boost::optional<ByteArray>& getValue() const { + const boost::optional<SafeByteArray>& getValue() const { return value; } - void setValue(const ByteArray& value) { - this->value = boost::optional<ByteArray>(value); + void setValue(const SafeByteArray& value) { + this->value = boost::optional<SafeByteArray>(value); } private: - boost::optional<ByteArray> value; + boost::optional<SafeByteArray> value; }; } diff --git a/Swiften/Elements/AuthSuccess.h b/Swiften/Elements/AuthSuccess.h index af5f9bb..3c0f329 100644 --- a/Swiften/Elements/AuthSuccess.h +++ b/Swiften/Elements/AuthSuccess.h @@ -6,25 +6,25 @@ #pragma once +#include <vector> #include <boost/optional.hpp> -#include "Swiften/Elements/Element.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Elements/Element.h> namespace Swift { class AuthSuccess : public Element { public: AuthSuccess() {} - const boost::optional<ByteArray>& getValue() const { + const boost::optional<std::vector<unsigned char> >& getValue() const { return value; } - void setValue(const ByteArray& value) { - this->value = boost::optional<ByteArray>(value); + void setValue(const std::vector<unsigned char>& value) { + this->value = boost::optional<std::vector<unsigned char> >(value); } private: - boost::optional<ByteArray> value; + boost::optional<std::vector<unsigned char> > value; }; } diff --git a/Swiften/Elements/BlockListPayload.h b/Swiften/Elements/BlockListPayload.h new file mode 100644 index 0000000..25cb602 --- /dev/null +++ b/Swiften/Elements/BlockListPayload.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class BlockListPayload : public Payload { + public: + BlockListPayload() { + } + + void addItem(const JID& item) { + items.push_back(item); + } + + const std::vector<JID>& getItems() const { + return items; + } + + private: + std::vector<JID> items; + }; +} diff --git a/Swiften/Elements/BlockPayload.h b/Swiften/Elements/BlockPayload.h new file mode 100644 index 0000000..6dd5170 --- /dev/null +++ b/Swiften/Elements/BlockPayload.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class BlockPayload : public Payload { + public: + BlockPayload() { + } + + void addItem(const JID& jid) { + items.push_back(jid); + } + + const std::vector<JID>& getItems() const { + return items; + } + + private: + std::vector<JID> items; + }; +} diff --git a/Swiften/Elements/Body.h b/Swiften/Elements/Body.h index 2887390..a2497f7 100644 --- a/Swiften/Elements/Body.h +++ b/Swiften/Elements/Body.h @@ -6,14 +6,13 @@ #pragma once -#include "Swiften/Elements/Payload.h" #include <string> +#include <Swiften/Elements/Payload.h> + namespace Swift { class Body : public Payload { public: - typedef boost::shared_ptr<Body> ref; - Body(const std::string& text = "") : text_(text) { } diff --git a/Swiften/Elements/Bytestreams.h b/Swiften/Elements/Bytestreams.h index b493375..9724a54 100644 --- a/Swiften/Elements/Bytestreams.h +++ b/Swiften/Elements/Bytestreams.h @@ -9,10 +9,10 @@ #include <vector> #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> - -#include "Swiften/JID/JID.h" #include <string> -#include "Swiften/Elements/Payload.h" + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> namespace Swift { class Bytestreams : public Payload { diff --git a/Swiften/Elements/CapsInfo.h b/Swiften/Elements/CapsInfo.h index ccad278..c6d3b64 100644 --- a/Swiften/Elements/CapsInfo.h +++ b/Swiften/Elements/CapsInfo.h @@ -7,9 +7,9 @@ #pragma once #include <boost/shared_ptr.hpp> - #include <string> -#include "Swiften/Elements/Payload.h" + +#include <Swiften/Elements/Payload.h> namespace Swift { class CapsInfo : public Payload { diff --git a/Swiften/Elements/ChatState.h b/Swiften/Elements/ChatState.h index 2896877..477fd27 100644 --- a/Swiften/Elements/ChatState.h +++ b/Swiften/Elements/ChatState.h @@ -7,7 +7,8 @@ #pragma once #include <string> -#include "Swiften/Elements/Payload.h" + +#include <Swiften/Elements/Payload.h> namespace Swift { class ChatState : public Payload { @@ -17,7 +18,7 @@ namespace Swift { state_ = state; } - ChatStateType getChatState() { return state_; } + ChatStateType getChatState() const { return state_; } void setChatState(ChatStateType state) {state_ = state;} private: diff --git a/Swiften/Elements/Command.h b/Swiften/Elements/Command.h index f4059a8..91ae5a3 100644 --- a/Swiften/Elements/Command.h +++ b/Swiften/Elements/Command.h @@ -7,10 +7,10 @@ #pragma once #include <boost/shared_ptr.hpp> - #include <string> -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/Form.h" + +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Form.h> namespace Swift { /** diff --git a/Swiften/Elements/ComponentHandshake.h b/Swiften/Elements/ComponentHandshake.h index 6047eab..5992b8c 100644 --- a/Swiften/Elements/ComponentHandshake.h +++ b/Swiften/Elements/ComponentHandshake.h @@ -7,10 +7,10 @@ #pragma once #include <boost/shared_ptr.hpp> - -#include "Swiften/Elements/Element.h" #include <string> +#include <Swiften/Elements/Element.h> + namespace Swift { class ComponentHandshake : public Element { public: diff --git a/Swiften/Elements/CompressFailure.h b/Swiften/Elements/CompressFailure.h index c0d5847..7dd8867 100644 --- a/Swiften/Elements/CompressFailure.h +++ b/Swiften/Elements/CompressFailure.h @@ -4,10 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_CompressFailure_H -#define SWIFTEN_CompressFailure_H +#pragma once -#include "Swiften/Elements/Element.h" + +#include <Swiften/Elements/Element.h> namespace Swift { class CompressFailure : public Element { @@ -15,5 +15,3 @@ namespace Swift { CompressFailure() {} }; } - -#endif diff --git a/Swiften/Elements/CompressRequest.h b/Swiften/Elements/CompressRequest.h index 0eb302a..b6fcc64 100644 --- a/Swiften/Elements/CompressRequest.h +++ b/Swiften/Elements/CompressRequest.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_CompressRequest_H -#define SWIFTEN_CompressRequest_H +#pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { class CompressRequest : public Element @@ -27,5 +26,3 @@ namespace Swift { std::string method_; }; } - -#endif diff --git a/Swiften/Elements/Compressed.h b/Swiften/Elements/Compressed.h index e50c17e..2affec5 100644 --- a/Swiften/Elements/Compressed.h +++ b/Swiften/Elements/Compressed.h @@ -4,17 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_COMPRESSED_H -#define SWIFTEN_COMPRESSED_H +#pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { - class Compressed : public Element - { + class Compressed : public Element { public: Compressed() {} }; } - -#endif diff --git a/Swiften/Elements/Delay.h b/Swiften/Elements/Delay.h index 3213037..f7c4570 100644 --- a/Swiften/Elements/Delay.h +++ b/Swiften/Elements/Delay.h @@ -6,11 +6,11 @@ #pragma once -#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> #include <boost/optional.hpp> -#include "Swiften/Elements/Payload.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> namespace Swift { class Delay : public Payload { diff --git a/Swiften/Elements/DiscoInfo.cpp b/Swiften/Elements/DiscoInfo.cpp index f0e728e..35d4d04 100644 --- a/Swiften/Elements/DiscoInfo.cpp +++ b/Swiften/Elements/DiscoInfo.cpp @@ -4,7 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Elements/DiscoInfo.h> + +#include <algorithm> namespace Swift { @@ -12,6 +14,13 @@ const std::string DiscoInfo::ChatStatesFeature = std::string("http://jabber.org/ const std::string DiscoInfo::SecurityLabelsFeature = std::string("urn:xmpp:sec-label:0"); const std::string DiscoInfo::SecurityLabelsCatalogFeature = std::string("urn:xmpp:sec-label:catalog:2"); const std::string DiscoInfo::JabberSearchFeature = std::string("jabber:iq:search"); +const std::string DiscoInfo::CommandsFeature = std::string("http://jabber.org/protocol/commands"); +const std::string DiscoInfo::MessageCorrectionFeature = std::string("urn:xmpp:message-correct:0"); +const std::string DiscoInfo::JingleFeature = std::string("urn:xmpp:jingle:1"); +const std::string DiscoInfo::JingleFTFeature = std::string("urn:xmpp:jingle:apps:file-transfer:3"); +const std::string DiscoInfo::JingleTransportsIBBFeature = std::string("urn:xmpp:jingle:transports:ibb:1"); +const std::string DiscoInfo::JingleTransportsS5BFeature = std::string("urn:xmpp:jingle:transports:s5b:1"); +const std::string DiscoInfo::Bytestream = std::string("http://jabber.org/protocol/bytestreams"); bool DiscoInfo::Identity::operator<(const Identity& other) const { @@ -33,4 +42,8 @@ bool DiscoInfo::Identity::operator<(const Identity& other) const { } } +bool DiscoInfo::hasFeature(const std::string& feature) const { + return std::find(features_.begin(), features_.end(), feature) != features_.end(); +} + } diff --git a/Swiften/Elements/DiscoInfo.h b/Swiften/Elements/DiscoInfo.h index b73165e..6d6e722 100644 --- a/Swiften/Elements/DiscoInfo.h +++ b/Swiften/Elements/DiscoInfo.h @@ -7,12 +7,10 @@ #pragma once #include <vector> -#include <algorithm> - -#include "Swiften/Elements/Payload.h" #include <string> -#include "Swiften/Elements/Form.h" +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Form.h> namespace Swift { class DiscoInfo : public Payload { @@ -23,6 +21,13 @@ namespace Swift { static const std::string SecurityLabelsFeature; static const std::string SecurityLabelsCatalogFeature; static const std::string JabberSearchFeature; + static const std::string CommandsFeature; + static const std::string MessageCorrectionFeature; + static const std::string JingleFeature; + static const std::string JingleFTFeature; + static const std::string JingleTransportsIBBFeature; + static const std::string JingleTransportsS5BFeature; + static const std::string Bytestream; class Identity { public: @@ -82,9 +87,7 @@ namespace Swift { features_.push_back(feature); } - bool hasFeature(const std::string& feature) const { - return std::find(features_.begin(), features_.end(), feature) != features_.end(); - } + bool hasFeature(const std::string& feature) const; void addExtension(Form::ref form) { extensions_.push_back(form); diff --git a/Swiften/Elements/DiscoItems.h b/Swiften/Elements/DiscoItems.h index cc5a583..149e41c 100644 --- a/Swiften/Elements/DiscoItems.h +++ b/Swiften/Elements/DiscoItems.h @@ -7,11 +7,10 @@ #pragma once #include <vector> -#include <algorithm> - -#include "Swiften/Elements/Payload.h" #include <string> -#include "Swiften/JID/JID.h" + +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> namespace Swift { class DiscoItems : public Payload { diff --git a/Swiften/Elements/Element.cpp b/Swiften/Elements/Element.cpp index 5407e89..94829ba 100644 --- a/Swiften/Elements/Element.cpp +++ b/Swiften/Elements/Element.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { diff --git a/Swiften/Elements/Element.h b/Swiften/Elements/Element.h index aded528..1e6a9d0 100644 --- a/Swiften/Elements/Element.h +++ b/Swiften/Elements/Element.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ELEMENT_H -#define SWIFTEN_ELEMENT_H +#pragma once namespace Swift { class Element { @@ -13,5 +12,3 @@ namespace Swift { virtual ~Element(); }; } - -#endif diff --git a/Swiften/Elements/EnableStreamManagement.h b/Swiften/Elements/EnableStreamManagement.h index 807db84..15a091e 100644 --- a/Swiften/Elements/EnableStreamManagement.h +++ b/Swiften/Elements/EnableStreamManagement.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { diff --git a/Swiften/Elements/ErrorPayload.h b/Swiften/Elements/ErrorPayload.h index 12ad574..f21ba98 100644 --- a/Swiften/Elements/ErrorPayload.h +++ b/Swiften/Elements/ErrorPayload.h @@ -7,10 +7,10 @@ #pragma once #include <boost/shared_ptr.hpp> - -#include "Swiften/Elements/Payload.h" #include <string> +#include <Swiften/Elements/Payload.h> + namespace Swift { class ErrorPayload : public Payload { public: @@ -69,9 +69,18 @@ namespace Swift { return text_; } + void setPayload(boost::shared_ptr<Payload> payload) { + payload_ = payload; + } + + boost::shared_ptr<Payload> getPayload() const { + return payload_; + } + private: Type type_; Condition condition_; std::string text_; + boost::shared_ptr<Payload> payload_; }; } diff --git a/Swiften/Elements/Form.cpp b/Swiften/Elements/Form.cpp index 03fd1a4..c34b868 100644 --- a/Swiften/Elements/Form.cpp +++ b/Swiften/Elements/Form.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/Form.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Elements/Form.h> +#include <Swiften/Base/foreach.h> namespace Swift { diff --git a/Swiften/Elements/Form.h b/Swiften/Elements/Form.h index 1c50f0c..47ff7d4 100644 --- a/Swiften/Elements/Form.h +++ b/Swiften/Elements/Form.h @@ -7,12 +7,11 @@ #pragma once #include <vector> - -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/FormField.h" #include <string> -#include "Swiften/JID/JID.h" +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/FormField.h> +#include <Swiften/JID/JID.h> namespace Swift { /** @@ -32,12 +31,12 @@ namespace Swift { void addField(boost::shared_ptr<FormField> field) { fields_.push_back(field); } const std::vector<boost::shared_ptr<FormField> >& getFields() const { return fields_; } void setTitle(const std::string& title) { title_ = title; } - const std::string& getTitle() { return title_; } + const std::string& getTitle() const { return title_; } void setInstructions(const std::string& instructions) { instructions_ = instructions; } - const std::string& getInstructions() { return instructions_; } + const std::string& getInstructions() const { return instructions_; } - Type getType() { return type_; } + Type getType() const { return type_; } void setType(Type type) { type_ = type; } std::string getFormType() const; diff --git a/Swiften/Elements/FormField.h b/Swiften/Elements/FormField.h index 517369b..e8fe3a0 100644 --- a/Swiften/Elements/FormField.h +++ b/Swiften/Elements/FormField.h @@ -11,9 +11,9 @@ #include <vector> #include <boost/shared_ptr.hpp> - #include <string> -#include "Swiften/JID/JID.h" + +#include <Swiften/JID/JID.h> namespace Swift { class FormField { @@ -111,5 +111,4 @@ namespace Swift { SWIFTEN_DECLARE_FORM_FIELD(JIDSingle, JID); SWIFTEN_DECLARE_FORM_FIELD(JIDMulti, std::vector<JID>); SWIFTEN_DECLARE_FORM_FIELD(ListMulti, std::vector<std::string>); - SWIFTEN_DECLARE_FORM_FIELD(Untyped, std::vector<std::string>); } diff --git a/Swiften/Elements/IBB.h b/Swiften/Elements/IBB.h index 55f2c4f..64c9f14 100644 --- a/Swiften/Elements/IBB.h +++ b/Swiften/Elements/IBB.h @@ -6,11 +6,12 @@ #pragma once +#include <string> +#include <vector> #include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> -#include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class IBB : public Payload { @@ -31,20 +32,20 @@ namespace Swift { } static IBB::ref createIBBOpen(const std::string& streamID, int blockSize) { - IBB::ref result(new IBB(Open, streamID)); + IBB::ref result = boost::make_shared<IBB>(Open, streamID); result->setBlockSize(blockSize); return result; } - static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const ByteArray& data) { - IBB::ref result(new IBB(Data, streamID)); + static IBB::ref createIBBData(const std::string& streamID, int sequenceNumber, const std::vector<unsigned char>& data) { + IBB::ref result = boost::make_shared<IBB>(Data, streamID); result->setSequenceNumber(sequenceNumber); result->setData(data); return result; } static IBB::ref createIBBClose(const std::string& streamID) { - return IBB::ref(new IBB(Close, streamID)); + return boost::make_shared<IBB>(Close, streamID); } void setAction(Action action) { @@ -71,11 +72,11 @@ namespace Swift { return streamID; } - const ByteArray& getData() const { + const std::vector<unsigned char>& getData() const { return data; } - void setData(const ByteArray& data) { + void setData(const std::vector<unsigned char>& data) { this->data = data; } @@ -98,7 +99,7 @@ namespace Swift { private: Action action; std::string streamID; - ByteArray data; + std::vector<unsigned char> data; StanzaType stanzaType; int blockSize; int sequenceNumber; diff --git a/Swiften/Elements/IQ.cpp b/Swiften/Elements/IQ.cpp index eb62ee4..8e6d7cc 100644 --- a/Swiften/Elements/IQ.cpp +++ b/Swiften/Elements/IQ.cpp @@ -4,13 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/IQ.h" +#include <Swiften/Elements/IQ.h> + +#include <boost/smart_ptr/make_shared.hpp> namespace Swift { boost::shared_ptr<IQ> IQ::createRequest( Type type, const JID& to, const std::string& id, boost::shared_ptr<Payload> payload) { - boost::shared_ptr<IQ> iq(new IQ(type)); + boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(type); if (to.isValid()) { iq->setTo(to); } @@ -22,7 +24,7 @@ boost::shared_ptr<IQ> IQ::createRequest( } boost::shared_ptr<IQ> IQ::createResult(const JID& to, const std::string& id, boost::shared_ptr<Payload> payload) { - boost::shared_ptr<IQ> iq(new IQ(Result)); + boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(Result); iq->setTo(to); iq->setID(id); if (payload) { @@ -32,7 +34,7 @@ boost::shared_ptr<IQ> IQ::createResult(const JID& to, const std::string& id, boo } boost::shared_ptr<IQ> IQ::createResult(const JID& to, const JID& from, const std::string& id, boost::shared_ptr<Payload> payload) { - boost::shared_ptr<IQ> iq(new IQ(Result)); + boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(Result); iq->setTo(to); iq->setFrom(from); iq->setID(id); @@ -43,19 +45,19 @@ boost::shared_ptr<IQ> IQ::createResult(const JID& to, const JID& from, const std } boost::shared_ptr<IQ> IQ::createError(const JID& to, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { - boost::shared_ptr<IQ> iq(new IQ(IQ::Error)); + boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(IQ::Error); iq->setTo(to); iq->setID(id); - iq->addPayload(boost::shared_ptr<Swift::ErrorPayload>(new Swift::ErrorPayload(condition, type))); + iq->addPayload(boost::make_shared<Swift::ErrorPayload>(condition, type)); return iq; } boost::shared_ptr<IQ> IQ::createError(const JID& to, const JID& from, const std::string& id, ErrorPayload::Condition condition, ErrorPayload::Type type) { - boost::shared_ptr<IQ> iq(new IQ(IQ::Error)); + boost::shared_ptr<IQ> iq = boost::make_shared<IQ>(IQ::Error); iq->setTo(to); iq->setFrom(from); iq->setID(id); - iq->addPayload(boost::shared_ptr<Swift::ErrorPayload>(new Swift::ErrorPayload(condition, type))); + iq->addPayload(boost::make_shared<Swift::ErrorPayload>(condition, type)); return iq; } diff --git a/Swiften/Elements/IQ.h b/Swiften/Elements/IQ.h index 78a8bbd..05cd96a 100644 --- a/Swiften/Elements/IQ.h +++ b/Swiften/Elements/IQ.h @@ -8,8 +8,8 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { class IQ : public Stanza { diff --git a/Swiften/Elements/InBandRegistrationPayload.h b/Swiften/Elements/InBandRegistrationPayload.h index e4e1e6f..8f6a9f1 100644 --- a/Swiften/Elements/InBandRegistrationPayload.h +++ b/Swiften/Elements/InBandRegistrationPayload.h @@ -8,11 +8,11 @@ #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> - -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/Form.h" #include <string> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Form.h> + namespace Swift { class InBandRegistrationPayload : public Payload { public: diff --git a/Swiften/Elements/JingleContent.h b/Swiften/Elements/JingleContentPayload.h index 4ae908b..183b8eb 100644 --- a/Swiften/Elements/JingleContent.h +++ b/Swiften/Elements/JingleContentPayload.h @@ -8,20 +8,20 @@ #include <vector> #include <boost/optional.hpp> - #include <string> + #include <Swiften/JID/JID.h> #include <Swiften/Elements/Payload.h> #include <Swiften/Elements/JingleDescription.h> -#include <Swiften/Elements/JingleTransport.h> -#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/JingleTransportPayload.h> namespace Swift { - class JingleContent : public Payload { + class JingleContentPayload : public Payload { public: - typedef boost::shared_ptr<JingleContent> ref; + typedef boost::shared_ptr<JingleContentPayload> ref; enum Creator { + UnknownCreator, InitiatorCreator, ResponderCreator, }; @@ -33,10 +33,18 @@ namespace Swift { BothSenders, };*/ + Creator getCreator() const { + return creator; + } + void setCreator(Creator creator) { this->creator = creator; } + const std::string& getName() const { + return name; + } + void setName(const std::string& name) { this->name = name; } @@ -49,18 +57,18 @@ namespace Swift { descriptions.push_back(description); } - const std::vector<JingleTransport::ref>& getTransports() const { + const std::vector<boost::shared_ptr<JingleTransportPayload> >& getTransports() const { return transports; } - void addTransport(JingleTransport::ref transport) { + void addTransport(boost::shared_ptr<JingleTransportPayload> transport) { transports.push_back(transport); } template<typename T> boost::shared_ptr<T> getDescription() const { - foreach (JingleDescription::ref i, descriptions) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < descriptions.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(descriptions[i])); if (result) { return result; } @@ -70,8 +78,8 @@ namespace Swift { template<typename T> boost::shared_ptr<T> getTransport() const { - foreach (JingleTransport::ref i, transports) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < transports.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(transports[i])); if (result) { return result; } @@ -84,6 +92,6 @@ namespace Swift { std::string name; //Senders senders; std::vector<JingleDescription::ref> descriptions; - std::vector<JingleTransport::ref> transports; + std::vector<boost::shared_ptr<JingleTransportPayload> > transports; }; } diff --git a/Swiften/Elements/JingleFileTransferDescription.h b/Swiften/Elements/JingleFileTransferDescription.h index 19644bd..04f3f1f 100644 --- a/Swiften/Elements/JingleFileTransferDescription.h +++ b/Swiften/Elements/JingleFileTransferDescription.h @@ -7,7 +7,7 @@ #pragma once #include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> +#include <vector> #include <Swiften/Elements/JingleDescription.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> @@ -17,15 +17,25 @@ namespace Swift { public: typedef boost::shared_ptr<JingleFileTransferDescription> ref; - void setOffer(const StreamInitiationFileInfo& offer) { - this->offer = offer; + void addOffer(const StreamInitiationFileInfo& offer) { + offers.push_back(offer); } + - const boost::optional<StreamInitiationFileInfo>& getOffer() const { - return offer; + const std::vector<StreamInitiationFileInfo>& getOffers() const { + return offers; + } + + void addRequest(const StreamInitiationFileInfo& request) { + reqeusts.push_back(request); + } + + const std::vector<StreamInitiationFileInfo>& getRequests() const { + return reqeusts; } private: - boost::optional<StreamInitiationFileInfo> offer; + std::vector<StreamInitiationFileInfo> offers; + std::vector<StreamInitiationFileInfo> reqeusts; }; } diff --git a/Swiften/Elements/JingleFileTransferHash.h b/Swiften/Elements/JingleFileTransferHash.h new file mode 100644 index 0000000..5603531 --- /dev/null +++ b/Swiften/Elements/JingleFileTransferHash.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <map> +#include <string> + +#include <Swiften/Elements/JingleDescription.h> + +namespace Swift { + +class JingleFileTransferHash : public Payload { +public: + typedef std::map<std::string, std::string> HashesMap; +public: + typedef boost::shared_ptr<JingleFileTransferHash> ref; + + void setHash(const std::string& algo, const std::string& hash) { + hashes[algo] = hash; + } + + const HashesMap& getHashes() const { + return hashes; + } + +private: + HashesMap hashes; +}; + +} diff --git a/Swiften/Elements/JingleFileTransferReceived.h b/Swiften/Elements/JingleFileTransferReceived.h new file mode 100644 index 0000000..75c95d9 --- /dev/null +++ b/Swiften/Elements/JingleFileTransferReceived.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <vector> + +#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + +class JingleFileTransferReceived : public Payload { + public: + typedef boost::shared_ptr<JingleFileTransferReceived> ref; + + void setFileInfo(const StreamInitiationFileInfo& fileInfo) { + this->fileInfo = fileInfo; + } + + const StreamInitiationFileInfo& getFileInfo() const { + return this->fileInfo; + } + private: + StreamInitiationFileInfo fileInfo; + +}; + +} diff --git a/Swiften/Elements/JingleIBBTransport.h b/Swiften/Elements/JingleIBBTransportPayload.h index faa5af3..8c174f0 100644 --- a/Swiften/Elements/JingleIBBTransport.h +++ b/Swiften/Elements/JingleIBBTransportPayload.h @@ -6,12 +6,16 @@ #pragma once +#include <boost/shared_ptr.hpp> #include <string> -#include <Swiften/Elements/JingleTransport.h> + +#include <Swiften/Elements/JingleTransportPayload.h> namespace Swift { - class JingleIBBTransport : public JingleTransport { + class JingleIBBTransportPayload : public JingleTransportPayload { public: + typedef boost::shared_ptr<JingleIBBTransportPayload> ref; + enum StanzaType { IQStanza, MessageStanza, @@ -25,14 +29,6 @@ namespace Swift { return stanzaType; } - void setSessionID(const std::string& id) { - sessionID = id; - } - - const std::string& getSessionID() const { - return sessionID; - } - int getBlockSize() const { return blockSize; } @@ -42,7 +38,6 @@ namespace Swift { } private: - std::string sessionID; int blockSize; StanzaType stanzaType; }; diff --git a/Swiften/Elements/JinglePayload.h b/Swiften/Elements/JinglePayload.h index 59fba7b..31d4448 100644 --- a/Swiften/Elements/JinglePayload.h +++ b/Swiften/Elements/JinglePayload.h @@ -7,20 +7,23 @@ #pragma once #include <vector> +#include <boost/shared_ptr.hpp> #include <boost/optional.hpp> #include <string> #include <Swiften/JID/JID.h> #include <Swiften/Elements/Payload.h> -#include <Swiften/Elements/JingleContent.h> +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Base/Log.h> namespace Swift { class JinglePayload : public Payload { public: typedef boost::shared_ptr<JinglePayload> ref; - struct Reason { + struct Reason : public Payload { enum Type { + UnknownType, AlternativeSession, Busy, Cancel, @@ -39,13 +42,15 @@ namespace Swift { UnsupportedApplications, UnsupportedTransports }; - + Reason() : type(UnknownType), text("") {} Reason(Type type, const std::string& text = "") : type(type), text(text) {} + ~Reason() {} Type type; std::string text; }; enum Action { + UnknownAction, ContentAccept, ContentAdd, ContentModify, @@ -62,8 +67,11 @@ namespace Swift { TransportReject, TransportReplace }; - + JinglePayload() : action(SessionTerminate), sessionID("") { + } + JinglePayload(Action action, const std::string& sessionID) : action(action), sessionID(sessionID) { + } void setAction(Action action) { @@ -98,12 +106,47 @@ namespace Swift { return sessionID; } - void addContent(JingleContent::ref content) { - this->contents.push_back(content); + void addContent(JingleContentPayload::ref content) { + this->payloads.push_back(content); + } + + void addPayload(boost::shared_ptr<Payload> payload) { + this->payloads.push_back(payload); + } + + const std::vector<JingleContentPayload::ref> getContents() const { + return getPayloads<JingleContentPayload>(); + } + + const std::vector<boost::shared_ptr<Payload> > getPayloads() const { + return payloads; + } + + template<typename T> + const std::vector<boost::shared_ptr<T> > getPayloads() const { + std::vector<boost::shared_ptr<T> > matched_payloads; + for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) { + boost::shared_ptr<T> result = boost::dynamic_pointer_cast<T>(*i); + if (result) { + matched_payloads.push_back(result); + } + } + + return matched_payloads; + } - const std::vector<JingleContent::ref>& getContents() const { - return contents; + template<typename T> + const boost::shared_ptr<T> getPayload() const { + boost::shared_ptr<T> result; + for (std::vector<boost::shared_ptr<Payload> >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) { + result = boost::dynamic_pointer_cast<T>(*i); + if (result) { + return result; + } + } + + return result; } void setReason(const Reason& reason) { @@ -119,7 +162,7 @@ namespace Swift { JID initiator; JID responder; std::string sessionID; - std::vector<JingleContent::ref> contents; + std::vector<boost::shared_ptr<Payload> > payloads; boost::optional<Reason> reason; }; } diff --git a/Swiften/Elements/JingleS5BTransport.h b/Swiften/Elements/JingleS5BTransport.h deleted file mode 100644 index 4522417..0000000 --- a/Swiften/Elements/JingleS5BTransport.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <Swiften/Elements/JingleTransport.h> -#include <Swiften/Elements/Bytestreams.h> - -namespace Swift { - class JingleS5BTransport : public JingleTransport { - public: - const Bytestreams& getInfo() const { - return info; - } - - void setInfo(const Bytestreams& info) { - this->info = info; - } - - private: - Bytestreams info; - }; -} diff --git a/Swiften/Elements/JingleS5BTransportPayload.h b/Swiften/Elements/JingleS5BTransportPayload.h new file mode 100644 index 0000000..980af27 --- /dev/null +++ b/Swiften/Elements/JingleS5BTransportPayload.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/JingleTransportPayload.h> +#include <Swiften/Elements/Bytestreams.h> +#include <Swiften/Network/HostAddressPort.h> + + +namespace Swift { + class JingleS5BTransportPayload : public JingleTransportPayload { + public: + enum Mode { + TCPMode, // default case + UDPMode, + }; + + struct Candidate { + enum Type { + DirectType, // default case + AssistedType, + TunnelType, + ProxyType, + }; + + Candidate() : priority(0), type(DirectType) {} + + std::string cid; + JID jid; + HostAddressPort hostPort; + int priority; + Type type; + }; + + struct CompareCandidate { + bool operator() (const JingleS5BTransportPayload::Candidate& c1, const JingleS5BTransportPayload::Candidate& c2) const { + if (c1.priority < c2.priority) return true; + return false; + } + }; + + public: + JingleS5BTransportPayload() : mode(TCPMode), candidateError(false), proxyError(false) {} + + Mode getMode() const { + return mode; + } + + void setMode(Mode mode) { + this->mode = mode; + } + + const std::vector<Candidate>& getCandidates() { + return candidates; + } + + void addCandidate(const Candidate& candidate) { + candidates.push_back(candidate); + } + + void setCandidateUsed(const std::string& cid) { + candidateUsedCID = cid; + } + + const std::string& getCandidateUsed() const { + return candidateUsedCID; + } + + void setActivated(const std::string& cid) { + activatedCID = cid; + } + + const std::string& getActivated() const { + return activatedCID; + } + + void setCandidateError(bool hasError) { + candidateError = hasError; + } + + bool hasCandidateError() const { + return candidateError; + } + + void setProxyError(bool hasError) { + proxyError = hasError; + } + + bool hasProxyError() const { + return proxyError; + } + public: + typedef boost::shared_ptr<JingleS5BTransportPayload> ref; + + private: + Mode mode; + std::vector<Candidate> candidates; + + std::string candidateUsedCID; + std::string activatedCID; + bool candidateError; + bool proxyError; + }; +} diff --git a/Swiften/Elements/JingleTransportPayload.h b/Swiften/Elements/JingleTransportPayload.h new file mode 100644 index 0000000..b870be9 --- /dev/null +++ b/Swiften/Elements/JingleTransportPayload.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class JingleTransportPayload : public Payload { + public: + void setSessionID(const std::string& id) { + sessionID = id; + } + + const std::string& getSessionID() const { + return sessionID; + } + + public: + typedef boost::shared_ptr<JingleTransportPayload> ref; + + private: + std::string sessionID; + }; +} diff --git a/Swiften/Elements/Last.h b/Swiften/Elements/Last.h new file mode 100644 index 0000000..fe0323a --- /dev/null +++ b/Swiften/Elements/Last.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class Last : public Payload { + public: + Last(int seconds = 0) : seconds_(seconds) {}; + + int getSeconds() const {return seconds_;} + void setSeconds(int seconds) {seconds_ = seconds;} + + private: + int seconds_; + }; +} diff --git a/Swiften/Elements/MUCAdminPayload.h b/Swiften/Elements/MUCAdminPayload.h new file mode 100644 index 0000000..dc09a24 --- /dev/null +++ b/Swiften/Elements/MUCAdminPayload.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/Elements/MUCItem.h> + +namespace Swift { + class MUCAdminPayload : public Payload { + public: + typedef boost::shared_ptr<MUCAdminPayload> ref; + + + MUCAdminPayload() { + } + + void addItem(const MUCItem& item) {items_.push_back(item);} + + const std::vector<MUCItem>& getItems() const {return items_;} + + private: + std::vector<MUCItem> items_; + }; +} diff --git a/Swiften/Elements/MUCDestroyPayload.h b/Swiften/Elements/MUCDestroyPayload.h new file mode 100644 index 0000000..f743ad0 --- /dev/null +++ b/Swiften/Elements/MUCDestroyPayload.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class MUCDestroyPayload : public Payload { + public: + typedef boost::shared_ptr<MUCDestroyPayload> ref; + + MUCDestroyPayload() { + } + + void setNewVenue(const JID& jid) { + newVenue_ = jid; + } + + const JID& getNewVenue() const { + return newVenue_; + } + + void setReason(const std::string& reason) { + reason_ = reason; + } + + const std::string& getReason() const { + return reason_; + } + + private: + JID newVenue_; + std::string reason_; + }; +} diff --git a/Swiften/Elements/MUCItem.h b/Swiften/Elements/MUCItem.h new file mode 100644 index 0000000..86217ec --- /dev/null +++ b/Swiften/Elements/MUCItem.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/JID/JID.h> +namespace Swift { +struct MUCItem { + MUCItem() {} + boost::optional<JID> realJID; + boost::optional<std::string> nick; + boost::optional<MUCOccupant::Affiliation> affiliation; + boost::optional<MUCOccupant::Role> role; + boost::optional<JID> actor; + boost::optional<std::string> reason; +}; +} diff --git a/Swiften/Elements/MUCOccupant.cpp b/Swiften/Elements/MUCOccupant.cpp index a5d8f0e..57034ad 100644 --- a/Swiften/Elements/MUCOccupant.cpp +++ b/Swiften/Elements/MUCOccupant.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/MUCOccupant.h" +#include <Swiften/Elements/MUCOccupant.h> namespace Swift { diff --git a/Swiften/Elements/MUCOccupant.h b/Swiften/Elements/MUCOccupant.h index b3ae4aa..931f544 100644 --- a/Swiften/Elements/MUCOccupant.h +++ b/Swiften/Elements/MUCOccupant.h @@ -9,7 +9,7 @@ #include <boost/optional.hpp> #include <string> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> namespace Swift { class Client; diff --git a/Swiften/Elements/MUCOwnerPayload.h b/Swiften/Elements/MUCOwnerPayload.h index 6c3e5f0..5ccc755 100644 --- a/Swiften/Elements/MUCOwnerPayload.h +++ b/Swiften/Elements/MUCOwnerPayload.h @@ -8,7 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Form.h> namespace Swift { class MUCOwnerPayload : public Payload { @@ -26,6 +27,10 @@ namespace Swift { payload = p; } + Form::ref getForm() { + return boost::dynamic_pointer_cast<Form>(payload); + } + private: boost::shared_ptr<Payload> payload; }; diff --git a/Swiften/Elements/MUCPayload.h b/Swiften/Elements/MUCPayload.h index c372360..3b99111 100644 --- a/Swiften/Elements/MUCPayload.h +++ b/Swiften/Elements/MUCPayload.h @@ -7,11 +7,11 @@ #pragma once #include <boost/optional.hpp> -#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> #include <string> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class MUCPayload : public Payload { @@ -40,19 +40,19 @@ namespace Swift { since_ = since; } - int getMaxChars() { + int getMaxChars() const{ return maxChars_; } - int getMaxStanzas() { + int getMaxStanzas() const{ return maxStanzas_; } - int getSeconds() { + int getSeconds() const { return seconds_; } - boost::posix_time::ptime getSince() { + const boost::posix_time::ptime& getSince() const { return since_; } diff --git a/Swiften/Elements/MUCUserPayload.h b/Swiften/Elements/MUCUserPayload.h index 7460c35..c9ea62c 100644 --- a/Swiften/Elements/MUCUserPayload.h +++ b/Swiften/Elements/MUCUserPayload.h @@ -11,25 +11,19 @@ #include <string> #include <vector> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/MUCOccupant.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/Elements/MUCItem.h> namespace Swift { class MUCUserPayload : public Payload { public: typedef boost::shared_ptr<MUCUserPayload> ref; - struct Item { - Item(MUCOccupant::Affiliation affiliation = MUCOccupant::NoAffiliation, MUCOccupant::Role role = MUCOccupant::NoRole) : affiliation(affiliation), role(role) {} - boost::optional<JID> realJID; - boost::optional<std::string> nick; - MUCOccupant::Affiliation affiliation; - MUCOccupant::Role role; - }; - struct StatusCode { StatusCode() : code(0) {} + StatusCode(int code) : code(code) {} int code; }; @@ -48,16 +42,25 @@ namespace Swift { MUCUserPayload() { } - void addItem(Item item) {items_.push_back(item);} + void addItem(const MUCItem& item) {items_.push_back(item);} void addStatusCode(StatusCode code) {statusCodes_.push_back(code);} - const std::vector<Item>& getItems() const {return items_;} + const std::vector<MUCItem>& getItems() const {return items_;} const std::vector<StatusCode>& getStatusCodes() const {return statusCodes_;} + boost::shared_ptr<Payload> getPayload() const { + return payload_; + } + + void setPayload(boost::shared_ptr<Payload> p) { + payload_ = p; + } + private: - std::vector<Item> items_; + std::vector<MUCItem> items_; std::vector<StatusCode> statusCodes_; + boost::shared_ptr<Payload> payload_; }; } diff --git a/Swiften/Elements/Message.h b/Swiften/Elements/Message.h index a553eb3..3b9145c 100644 --- a/Swiften/Elements/Message.h +++ b/Swiften/Elements/Message.h @@ -8,12 +8,14 @@ #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> #include <string> -#include "Swiften/Elements/Body.h" -#include "Swiften/Elements/Subject.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/Elements/Stanza.h" +#include <Swiften/Elements/Body.h> +#include <Swiften/Elements/Subject.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/Replace.h> namespace Swift { class Message : public Stanza { @@ -33,7 +35,11 @@ namespace Swift { } void setSubject(const std::string& subject) { - updatePayload(boost::shared_ptr<Subject>(new Subject(subject))); + updatePayload(boost::make_shared<Subject>(subject)); + } + + bool hasSubject() { + return getPayload<Subject>(); } std::string getBody() const { @@ -45,7 +51,7 @@ namespace Swift { } void setBody(const std::string& body) { - updatePayload(boost::shared_ptr<Body>(new Body(body))); + updatePayload(boost::make_shared<Body>(body)); } bool isError() { diff --git a/Swiften/Elements/Nickname.h b/Swiften/Elements/Nickname.h index 540f6da..a244ce3 100644 --- a/Swiften/Elements/Nickname.h +++ b/Swiften/Elements/Nickname.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> #include <string> namespace Swift { diff --git a/Swiften/Elements/Payload.cpp b/Swiften/Elements/Payload.cpp index b66dcdb..b7c3ffe 100644 --- a/Swiften/Elements/Payload.cpp +++ b/Swiften/Elements/Payload.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { diff --git a/Swiften/Elements/Payload.h b/Swiften/Elements/Payload.h index c87b899..f994ebc 100644 --- a/Swiften/Elements/Payload.h +++ b/Swiften/Elements/Payload.h @@ -12,7 +12,7 @@ namespace Swift { class Payload { public: typedef boost::shared_ptr<Payload> ref; - + public: virtual ~Payload(); }; } diff --git a/Swiften/Elements/Presence.cpp b/Swiften/Elements/Presence.cpp new file mode 100644 index 0000000..38b8a4c --- /dev/null +++ b/Swiften/Elements/Presence.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/Presence.h> + +#include <Swiften/Elements/Priority.h> +#include <Swiften/Elements/Status.h> + +namespace Swift { + +Presence::Presence() : type_(Available) /*, showType_(Online)*/ { +} + +Presence::Presence(const std::string& status) : type_(Available) { + setStatus(status); +} + +Presence::~Presence() { +} + +int Presence::getPriority() const { + boost::shared_ptr<Priority> priority(getPayload<Priority>()); + return (priority ? priority->getPriority() : 0); +} + +void Presence::setPriority(int priority) { + updatePayload(boost::make_shared<Priority>(priority)); +} + +std::string Presence::getStatus() const { + boost::shared_ptr<Status> status(getPayload<Status>()); + if (status) { + return status->getText(); + } + return ""; +} + +void Presence::setStatus(const std::string& status) { + updatePayload(boost::make_shared<Status>(status)); +} + + +} diff --git a/Swiften/Elements/Presence.h b/Swiften/Elements/Presence.h index 7f957ba..28a9ee5 100644 --- a/Swiften/Elements/Presence.h +++ b/Swiften/Elements/Presence.h @@ -6,11 +6,10 @@ #pragma once +#include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Elements/Status.h" -#include "Swiften/Elements/StatusShow.h" -#include "Swiften/Elements/Priority.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/StatusShow.h> namespace Swift { class Presence : public Stanza { @@ -19,21 +18,20 @@ namespace Swift { enum Type { Available, Error, Probe, Subscribe, Subscribed, Unavailable, Unsubscribe, Unsubscribed }; - Presence() : type_(Available) /*, showType_(Online)*/ {} - Presence(const std::string& status) : type_(Available) { - setStatus(status); - } + Presence(); + Presence(const std::string& status); + virtual ~Presence(); static ref create() { - return ref(new Presence()); + return boost::make_shared<Presence>(); } static ref create(const std::string& status) { - return ref(new Presence(status)); + return boost::make_shared<Presence>(status); } static ref create(Presence::ref presence) { - return ref(new Presence(*presence)); + return boost::make_shared<Presence>(*presence); } Type getType() const { return type_; } @@ -48,32 +46,17 @@ namespace Swift { } void setShow(const StatusShow::Type &show) { - updatePayload(boost::shared_ptr<StatusShow>(new StatusShow(show))); - } - - std::string getStatus() const { - boost::shared_ptr<Status> status(getPayload<Status>()); - if (status) { - return status->getText(); - } - return ""; + updatePayload(boost::make_shared<StatusShow>(show)); } - void setStatus(const std::string& status) { - updatePayload(boost::shared_ptr<Status>(new Status(status))); - } - - int getPriority() const { - boost::shared_ptr<Priority> priority(getPayload<Priority>()); - return (priority ? priority->getPriority() : 0); - } + std::string getStatus() const; + void setStatus(const std::string& status); - void setPriority(int priority) { - updatePayload(boost::shared_ptr<Priority>(new Priority(priority))); - } + int getPriority() const; + void setPriority(int priority); boost::shared_ptr<Presence> clone() const { - return boost::shared_ptr<Presence>(new Presence(*this)); + return boost::make_shared<Presence>(*this); } bool isAvailable() const { diff --git a/Swiften/Elements/Priority.h b/Swiften/Elements/Priority.h index 12181d4..2c0cb9b 100644 --- a/Swiften/Elements/Priority.h +++ b/Swiften/Elements/Priority.h @@ -6,13 +6,11 @@ #pragma once -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class Priority : public Payload { public: - typedef boost::shared_ptr<Priority> ref; - Priority(int priority = 0) : priority_(priority) { } diff --git a/Swiften/Elements/PrivateStorage.h b/Swiften/Elements/PrivateStorage.h index 34d9185..a8e1b74 100644 --- a/Swiften/Elements/PrivateStorage.h +++ b/Swiften/Elements/PrivateStorage.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class PrivateStorage : public Payload { diff --git a/Swiften/Elements/Replace.h b/Swiften/Elements/Replace.h new file mode 100644 index 0000000..230bce7 --- /dev/null +++ b/Swiften/Elements/Replace.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <string> + +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class Replace : public Payload { + public: + typedef boost::shared_ptr<Replace> ref; + Replace(const std::string& id = std::string()) : replaceID_(id) {}; + const std::string& getID() const { + return replaceID_; + } + void setID(const std::string& id) { + replaceID_ = id; + } + private: + std::string replaceID_; + }; +} diff --git a/Swiften/Elements/ResourceBind.h b/Swiften/Elements/ResourceBind.h index 3569eb3..f67a995 100644 --- a/Swiften/Elements/ResourceBind.h +++ b/Swiften/Elements/ResourceBind.h @@ -4,16 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ResourceBind_H -#define SWIFTEN_ResourceBind_H +#pragma once #include <string> -#include "Swiften/Elements/Payload.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> namespace Swift { - class ResourceBind : public Payload - { + class ResourceBind : public Payload { public: ResourceBind() {} @@ -38,5 +36,3 @@ namespace Swift { std::string resource_; }; } - -#endif diff --git a/Swiften/Elements/RosterItemExchangePayload.cpp b/Swiften/Elements/RosterItemExchangePayload.cpp new file mode 100644 index 0000000..abd5296 --- /dev/null +++ b/Swiften/Elements/RosterItemExchangePayload.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Elements/RosterItemExchangePayload.h> +#include <Swiften/Base/foreach.h> + +namespace Swift { + +RosterItemExchangePayload::Item::Item(Action action) : action(action) { +} + +RosterItemExchangePayload::RosterItemExchangePayload() { +} + +} diff --git a/Swiften/Elements/RosterItemExchangePayload.h b/Swiften/Elements/RosterItemExchangePayload.h new file mode 100644 index 0000000..f9aa2c8 --- /dev/null +++ b/Swiften/Elements/RosterItemExchangePayload.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <string> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> + + +namespace Swift { + class RosterItemExchangePayload : public Payload { + public: + typedef boost::shared_ptr<RosterItemExchangePayload> ref; + + class Item { + public: + enum Action { Add, Modify, Delete }; + + Item(Action action = Add); + + Action getAction() const { + return action; + } + + void setAction(Action action) { + this->action = action; + } + + const JID& getJID() const { + return jid; + } + + void setJID(const JID& jid) { + this->jid = jid; + } + + const std::string& getName() const { + return name; + } + + void setName(const std::string& name) { + this->name = name; + } + + const std::vector<std::string>& getGroups() const { + return groups; + } + + void setGroups(const std::vector<std::string> &groups) { + this->groups = groups; + } + + void addGroup(const std::string& group) { + groups.push_back(group); + } + + private: + Action action; + JID jid; + std::string name; + std::vector<std::string> groups; + }; + + typedef std::vector<RosterItemExchangePayload::Item> RosterItemExchangePayloadItems; + + public: + RosterItemExchangePayload(); + + void addItem(const RosterItemExchangePayload::Item& item) { + items_.push_back(item); + } + + const RosterItemExchangePayloadItems& getItems() const { + return items_; + } + + private: + RosterItemExchangePayloadItems items_; + }; +} diff --git a/Swiften/Elements/RosterItemPayload.h b/Swiften/Elements/RosterItemPayload.h index b8a1b10..915ae31 100644 --- a/Swiften/Elements/RosterItemPayload.h +++ b/Swiften/Elements/RosterItemPayload.h @@ -4,22 +4,20 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterItemPayloadPayload_H -#define SWIFTEN_RosterItemPayloadPayload_H +#pragma once #include <vector> - -#include "Swiften/JID/JID.h" #include <string> +#include <Swiften/JID/JID.h> + namespace Swift { - class RosterItemPayload - { + class RosterItemPayload { public: enum Subscription { None, To, From, Both, Remove }; RosterItemPayload() : subscription_(None), ask_(false) {} - RosterItemPayload(const JID& jid, const std::string& name, Subscription subscription) : jid_(jid), name_(name), subscription_(subscription), ask_(false) { } + RosterItemPayload(const JID& jid, const std::string& name, Subscription subscription, const std::vector<std::string>& groups = std::vector<std::string>()) : jid_(jid), name_(name), subscription_(subscription), groups_(groups), ask_(false) { } void setJID(const JID& jid) { jid_ = jid; } const JID& getJID() const { return jid_; } @@ -51,5 +49,3 @@ namespace Swift { std::string unknownContent_; }; } - -#endif diff --git a/Swiften/Elements/RosterPayload.cpp b/Swiften/Elements/RosterPayload.cpp index 5453ae8..6071cbc 100644 --- a/Swiften/Elements/RosterPayload.cpp +++ b/Swiften/Elements/RosterPayload.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Base/foreach.h> namespace Swift { diff --git a/Swiften/Elements/RosterPayload.h b/Swiften/Elements/RosterPayload.h index b46b384..c4907cb 100644 --- a/Swiften/Elements/RosterPayload.h +++ b/Swiften/Elements/RosterPayload.h @@ -10,8 +10,8 @@ #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/RosterItemPayload.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/RosterItemPayload.h> +#include <Swiften/Elements/Payload.h> namespace Swift { @@ -33,7 +33,16 @@ namespace Swift { return items_; } + const boost::optional<std::string>& getVersion() const { + return version_; + } + + void setVersion(const std::string& version) { + version_ = version; + } + private: RosterItemPayloads items_; + boost::optional<std::string> version_; }; } diff --git a/Swiften/Elements/S5BProxyRequest.h b/Swiften/Elements/S5BProxyRequest.h new file mode 100644 index 0000000..fcd0cb2 --- /dev/null +++ b/Swiften/Elements/S5BProxyRequest.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +#include <boost/optional.hpp> + +#include <Swiften/Elements/Payload.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/HostAddressPort.h> + +namespace Swift { + +class S5BProxyRequest : public Payload { +public: + typedef boost::shared_ptr<S5BProxyRequest> ref; + +public: + struct StreamHost { + HostAddressPort addressPort; + JID jid; + }; + +public: + const boost::optional<StreamHost>& getStreamHost() const { + return streamHost; + } + + void setStreamHost(const StreamHost& streamHost) { + this->streamHost = boost::optional<StreamHost>(streamHost); + } + + const std::string& getSID() const { + return sid; + } + + void setSID(const std::string& sid) { + this->sid = sid; + } + + const boost::optional<JID>& getActivate() const { + return activate; + } + + void setActivate(const JID& activate) { + this->activate = activate; + } + +private: + boost::optional<StreamHost> streamHost; + + std::string sid; + boost::optional<JID> activate; +}; + +} diff --git a/Swiften/Elements/SearchPayload.h b/Swiften/Elements/SearchPayload.h index d6d7ed1..202007b 100644 --- a/Swiften/Elements/SearchPayload.h +++ b/Swiften/Elements/SearchPayload.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/Form.h" +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Form.h> #include <string> namespace Swift { diff --git a/Swiften/Elements/SecurityLabel.h b/Swiften/Elements/SecurityLabel.h index ca38e32..0487977 100644 --- a/Swiften/Elements/SecurityLabel.h +++ b/Swiften/Elements/SecurityLabel.h @@ -4,13 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabel_H -#define SWIFTEN_SecurityLabel_H +#pragma once #include <vector> #include <string> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class SecurityLabel : public Payload { @@ -59,5 +58,3 @@ namespace Swift { std::vector<std::string> equivalentLabels_; }; } - -#endif diff --git a/Swiften/Elements/SecurityLabelsCatalog.h b/Swiften/Elements/SecurityLabelsCatalog.h index 10ef459..0f40c13 100644 --- a/Swiften/Elements/SecurityLabelsCatalog.h +++ b/Swiften/Elements/SecurityLabelsCatalog.h @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelsCatalog_H -#define SWIFTEN_SecurityLabelsCatalog_H +#pragma once #include <vector> - -#include "Swiften/JID/JID.h" #include <string> -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/SecurityLabel.h" +#include <boost/shared_ptr.hpp> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/SecurityLabel.h> namespace Swift { class SecurityLabelsCatalog : public Payload { @@ -85,5 +85,3 @@ namespace Swift { std::vector<Item> items_; }; } - -#endif diff --git a/Swiften/Elements/SoftwareVersion.h b/Swiften/Elements/SoftwareVersion.h index 5863b38..c49b47b 100644 --- a/Swiften/Elements/SoftwareVersion.h +++ b/Swiften/Elements/SoftwareVersion.h @@ -6,8 +6,10 @@ #pragma once -#include "Swiften/Elements/Payload.h" #include <string> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Payload.h> namespace Swift { class SoftwareVersion : public Payload { diff --git a/Swiften/Elements/Stanza.cpp b/Swiften/Elements/Stanza.cpp index d15d778..23f2d89 100644 --- a/Swiften/Elements/Stanza.cpp +++ b/Swiften/Elements/Stanza.cpp @@ -4,13 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Elements/Delay.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/Delay.h> #include <typeinfo> +#include <Swiften/Base/foreach.h> + namespace Swift { +Stanza::Stanza() { +} + Stanza::~Stanza() { payloads_.clear(); } diff --git a/Swiften/Elements/Stanza.h b/Swiften/Elements/Stanza.h index 9b934e4..9e082cc 100644 --- a/Swiften/Elements/Stanza.h +++ b/Swiften/Elements/Stanza.h @@ -7,27 +7,28 @@ #pragma once #include <vector> +#include <string> #include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> -#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/optional/optional_fwd.hpp> +#include <boost/date_time/posix_time/ptime.hpp> -#include "Swiften/Elements/Element.h" -#include "Swiften/Elements/Payload.h" -#include <string> -#include "Swiften/Base/foreach.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/JID/JID.h> namespace Swift { + class Payload; + class Stanza : public Element { public: typedef boost::shared_ptr<Stanza> ref; + Stanza(); virtual ~Stanza(); template<typename T> boost::shared_ptr<T> getPayload() const { - foreach (const boost::shared_ptr<Payload>& i, payloads_) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < payloads_.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(payloads_[i])); if (result) { return result; } @@ -38,8 +39,8 @@ namespace Swift { template<typename T> std::vector< boost::shared_ptr<T> > getPayloads() const { std::vector< boost::shared_ptr<T> > results; - foreach (const boost::shared_ptr<Payload>& i, payloads_) { - boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(i)); + for (size_t i = 0; i < payloads_.size(); ++i) { + boost::shared_ptr<T> result(boost::dynamic_pointer_cast<T>(payloads_[i])); if (result) { results.push_back(result); } @@ -78,8 +79,6 @@ namespace Swift { std::string id_; JID from_; JID to_; - - typedef std::vector< boost::shared_ptr<Payload> > Payloads; - Payloads payloads_; + std::vector< boost::shared_ptr<Payload> > payloads_; }; } diff --git a/Swiften/Elements/StanzaAck.h b/Swiften/Elements/StanzaAck.h index 8a57442..3aa2dfd 100644 --- a/Swiften/Elements/StanzaAck.h +++ b/Swiften/Elements/StanzaAck.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { diff --git a/Swiften/Elements/StanzaAckRequest.h b/Swiften/Elements/StanzaAckRequest.h index 024ebc9..81b3871 100644 --- a/Swiften/Elements/StanzaAckRequest.h +++ b/Swiften/Elements/StanzaAckRequest.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { diff --git a/Swiften/Elements/StartSession.h b/Swiften/Elements/StartSession.h index 0586f40..7aeb611 100644 --- a/Swiften/Elements/StartSession.h +++ b/Swiften/Elements/StartSession.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartSession_H -#define SWIFTEN_StartSession_H +#pragma once #include <string> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class StartSession : public Payload { @@ -16,5 +15,3 @@ namespace Swift { StartSession() {} }; } - -#endif diff --git a/Swiften/Elements/StartTLSFailure.h b/Swiften/Elements/StartTLSFailure.h index bb70204..5e233fb 100644 --- a/Swiften/Elements/StartTLSFailure.h +++ b/Swiften/Elements/StartTLSFailure.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartTLSFailure_H -#define SWIFTEN_StartTLSFailure_H +#pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { class StartTLSFailure : public Element { @@ -15,5 +14,3 @@ namespace Swift { StartTLSFailure() {} }; } - -#endif diff --git a/Swiften/Elements/StartTLSRequest.h b/Swiften/Elements/StartTLSRequest.h index 8ce40ec..e284f75 100644 --- a/Swiften/Elements/StartTLSRequest.h +++ b/Swiften/Elements/StartTLSRequest.h @@ -4,17 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartTLSRequest_H -#define SWIFTEN_StartTLSRequest_H +#pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { - class StartTLSRequest : public Element - { + class StartTLSRequest : public Element { public: StartTLSRequest() {} }; } - -#endif diff --git a/Swiften/Elements/Status.h b/Swiften/Elements/Status.h index 3ef6401..956f33d 100644 --- a/Swiften/Elements/Status.h +++ b/Swiften/Elements/Status.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Status_H -#define SWIFTEN_Status_H +#pragma once -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> #include <string> namespace Swift { @@ -28,5 +27,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Elements/StatusShow.cpp b/Swiften/Elements/StatusShow.cpp new file mode 100644 index 0000000..656e5c4 --- /dev/null +++ b/Swiften/Elements/StatusShow.cpp @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StatusShow.h> + +using namespace Swift; + +StatusShow::StatusShow(const Type& type) : type_(type) { +} diff --git a/Swiften/Elements/StatusShow.h b/Swiften/Elements/StatusShow.h index a158239..cd3477e 100644 --- a/Swiften/Elements/StatusShow.h +++ b/Swiften/Elements/StatusShow.h @@ -4,19 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StatusShow_H -#define SWIFTEN_StatusShow_H +#pragma once -#include "Swiften/Elements/Payload.h" -#include <string> +#include <Swiften/Elements/Payload.h> namespace Swift { class StatusShow : public Payload { public: enum Type { Online, Away, FFC, XA, DND, None }; - StatusShow(const Type& type = Online) : type_(type) { - } + StatusShow(const Type& type = Online); void setType(const Type& type) { type_ = type; @@ -32,19 +29,17 @@ namespace Swift { */ static int typeToAvailabilityOrdering(Type type) { switch (type) { - case Online: return 4; - case FFC: return 5; - case Away: return 2; - case XA: return 1; - case DND: return 3; - case None: return 0; + case Online: return 4; + case FFC: return 5; + case Away: return 2; + case XA: return 1; + case DND: return 3; + case None: return 0; } - return -1; + return 0; } private: Type type_; }; } - -#endif diff --git a/Swiften/Elements/Storage.h b/Swiften/Elements/Storage.h index a2f244c..8118b3b 100644 --- a/Swiften/Elements/Storage.h +++ b/Swiften/Elements/Storage.h @@ -8,9 +8,9 @@ #include <vector> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> #include <string> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> namespace Swift { class Storage : public Payload { diff --git a/Swiften/Elements/StreamFeatures.cpp b/Swiften/Elements/StreamFeatures.cpp new file mode 100644 index 0000000..c6f6c04 --- /dev/null +++ b/Swiften/Elements/StreamFeatures.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamFeatures.h> + +#include <algorithm> + +namespace Swift { + +bool StreamFeatures::hasCompressionMethod(const std::string& mechanism) const { + return std::find(compressionMethods_.begin(), compressionMethods_.end(), mechanism) != compressionMethods_.end(); +} + +bool StreamFeatures::hasAuthenticationMechanism(const std::string& mechanism) const { + return std::find(authenticationMechanisms_.begin(), authenticationMechanisms_.end(), mechanism) != authenticationMechanisms_.end(); +} + +} diff --git a/Swiften/Elements/StreamFeatures.h b/Swiften/Elements/StreamFeatures.h index fbc0bb8..cae5532 100644 --- a/Swiften/Elements/StreamFeatures.h +++ b/Swiften/Elements/StreamFeatures.h @@ -7,17 +7,17 @@ #pragma once #include <vector> -#include <algorithm> - #include <string> -#include "Swiften/Elements/Element.h" +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/Element.h> namespace Swift { class StreamFeatures : public Element { public: typedef boost::shared_ptr<StreamFeatures> ref; - StreamFeatures() : hasStartTLS_(false), hasResourceBind_(false), hasSession_(false), hasStreamManagement_(false) {} + StreamFeatures() : hasStartTLS_(false), hasResourceBind_(false), hasSession_(false), hasStreamManagement_(false), hasRosterVersioning_(false) {} void setHasStartTLS() { hasStartTLS_ = true; @@ -51,9 +51,7 @@ namespace Swift { compressionMethods_.push_back(mechanism); } - bool hasCompressionMethod(const std::string& mechanism) const { - return std::find(compressionMethods_.begin(), compressionMethods_.end(), mechanism) != compressionMethods_.end(); - } + bool hasCompressionMethod(const std::string& mechanism) const; const std::vector<std::string>& getAuthenticationMechanisms() const { return authenticationMechanisms_; @@ -63,9 +61,7 @@ namespace Swift { authenticationMechanisms_.push_back(mechanism); } - bool hasAuthenticationMechanism(const std::string& mechanism) const { - return std::find(authenticationMechanisms_.begin(), authenticationMechanisms_.end(), mechanism) != authenticationMechanisms_.end(); - } + bool hasAuthenticationMechanism(const std::string& mechanism) const; bool hasAuthenticationMechanisms() const { return !authenticationMechanisms_.empty(); @@ -79,6 +75,14 @@ namespace Swift { hasStreamManagement_ = true; } + bool hasRosterVersioning() const { + return hasRosterVersioning_; + } + + void setHasRosterVersioning() { + hasRosterVersioning_ = true; + } + private: bool hasStartTLS_; std::vector<std::string> compressionMethods_; @@ -86,5 +90,6 @@ namespace Swift { bool hasResourceBind_; bool hasSession_; bool hasStreamManagement_; + bool hasRosterVersioning_; }; } diff --git a/Swiften/Elements/StreamInitiation.h b/Swiften/Elements/StreamInitiation.h index 6217cbb..c1f0b4d 100644 --- a/Swiften/Elements/StreamInitiation.h +++ b/Swiften/Elements/StreamInitiation.h @@ -11,7 +11,7 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> #include <Swiften/Elements/StreamInitiationFileInfo.h> namespace Swift { diff --git a/Swiften/Elements/StreamInitiationFileInfo.h b/Swiften/Elements/StreamInitiationFileInfo.h index 92b9824..9484bc0 100644 --- a/Swiften/Elements/StreamInitiationFileInfo.h +++ b/Swiften/Elements/StreamInitiationFileInfo.h @@ -6,14 +6,97 @@ #pragma once +#include <Swiften/Elements/Payload.h> +#include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> + #include <string> namespace Swift { - struct StreamInitiationFileInfo { - StreamInitiationFileInfo(const std::string& name = "", const std::string& description = "", int size = -1) : name(name), description(description), size(size) {} - std::string name; - std::string description; - int size; - }; +class StreamInitiationFileInfo : public Payload { +public: + typedef boost::shared_ptr<StreamInitiationFileInfo> ref; + +public: + StreamInitiationFileInfo(const std::string& name = "", const std::string& description = "", int size = 0, + const std::string& hash = "", const boost::posix_time::ptime &date = boost::posix_time::ptime(), const std::string& algo="md5") : + name(name), description(description), size(size), hash(hash), date(date), algo(algo), supportsRangeRequests(false), rangeOffset(0) {} + + void setName(const std::string& name) { + this->name = name;; + } + + const std::string& getName() const { + return this->name; + } + + void setDescription(const std::string& description) { + this->description = description; + } + + const std::string& getDescription() const { + return this->description; + } + + void setSize(const boost::uintmax_t size) { + this->size = size; + } + + boost::uintmax_t getSize() const { + return this->size; + } + + void setHash(const std::string& hash) { + this->hash = hash; + } + + const std::string& getHash() const { + return this->hash; + } + + void setDate(const boost::posix_time::ptime& date) { + this->date = date; + } + + const boost::posix_time::ptime& getDate() const { + return this->date; + } + + void setAlgo(const std::string& algo) { + this->algo = algo; + } + + const std::string& getAlgo() const { + return this->algo; + } + + void setSupportsRangeRequests(const bool supportsIt) { + supportsRangeRequests = supportsIt; + } + + bool getSupportsRangeRequests() const { + return supportsRangeRequests; + } + + void setRangeOffset(const int offset) { + supportsRangeRequests = offset >= 0 ? true : false; + rangeOffset = offset; + } + + int getRangeOffset() const { + return rangeOffset; + } + +private: + std::string name; + std::string description; + boost::uintmax_t size; + std::string hash; + boost::posix_time::ptime date; + std::string algo; + bool supportsRangeRequests; + boost::uintmax_t rangeOffset; +}; + } diff --git a/Swiften/Elements/StreamManagementEnabled.cpp b/Swiften/Elements/StreamManagementEnabled.cpp new file mode 100644 index 0000000..bab7516 --- /dev/null +++ b/Swiften/Elements/StreamManagementEnabled.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamManagementEnabled.h> + +using namespace Swift; + +StreamManagementEnabled::StreamManagementEnabled() { +} + +StreamManagementEnabled::~StreamManagementEnabled() { +} diff --git a/Swiften/Elements/StreamManagementEnabled.h b/Swiften/Elements/StreamManagementEnabled.h index 0c72b84..02e77f3 100644 --- a/Swiften/Elements/StreamManagementEnabled.h +++ b/Swiften/Elements/StreamManagementEnabled.h @@ -1,17 +1,39 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swiften/Elements/Element.h" +#include <string> +#include <Swiften/Elements/Element.h> namespace Swift { class StreamManagementEnabled : public Element { public: - StreamManagementEnabled() {} + StreamManagementEnabled(); + ~StreamManagementEnabled(); + + void setResumeSupported() { + resumeSupported = true; + } + + bool getResumeSupported() const { + return resumeSupported; + } + + void setResumeID(const std::string& id) { + resumeID = id; + } + + const std::string& getResumeID() const { + return resumeID; + } + + private: + bool resumeSupported; + std::string resumeID; }; } diff --git a/Swiften/Elements/StreamManagementFailed.h b/Swiften/Elements/StreamManagementFailed.h index 8302c94..7c6d1b7 100644 --- a/Swiften/Elements/StreamManagementFailed.h +++ b/Swiften/Elements/StreamManagementFailed.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { diff --git a/Swiften/Elements/StreamResume.cpp b/Swiften/Elements/StreamResume.cpp new file mode 100644 index 0000000..d55ef78 --- /dev/null +++ b/Swiften/Elements/StreamResume.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamResume.h> + +using namespace Swift; + +StreamResume::StreamResume() { +} + +StreamResume::~StreamResume() { +} diff --git a/Swiften/Elements/StreamResume.h b/Swiften/Elements/StreamResume.h new file mode 100644 index 0000000..aec0909 --- /dev/null +++ b/Swiften/Elements/StreamResume.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <boost/optional.hpp> + +#include <Swiften/Elements/Element.h> + +namespace Swift { + class StreamResume : public Element { + public: + StreamResume(); + ~StreamResume(); + + void setResumeID(const std::string& id) { + resumeID = id; + } + + const std::string& getResumeID() const { + return resumeID; + } + + const boost::optional<unsigned int> getHandledStanzasCount() const { + return handledStanzasCount; + } + + void setHandledStanzasCount(unsigned int i) { + handledStanzasCount = i; + } + + private: + std::string resumeID; + boost::optional<unsigned int> handledStanzasCount; + }; +} diff --git a/Swiften/Elements/StreamResumed.cpp b/Swiften/Elements/StreamResumed.cpp new file mode 100644 index 0000000..552e654 --- /dev/null +++ b/Swiften/Elements/StreamResumed.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Elements/StreamResumed.h> + +using namespace Swift; + +StreamResumed::StreamResumed() { +} + +StreamResumed::~StreamResumed() { +} diff --git a/Swiften/Elements/StreamResumed.h b/Swiften/Elements/StreamResumed.h new file mode 100644 index 0000000..cf9a755 --- /dev/null +++ b/Swiften/Elements/StreamResumed.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <boost/optional.hpp> + +#include <Swiften/Elements/Element.h> + +namespace Swift { + class StreamResumed : public Element { + public: + StreamResumed(); + ~StreamResumed(); + + void setResumeID(const std::string& id) { + resumeID = id; + } + + const std::string& getResumeID() const { + return resumeID; + } + + const boost::optional<unsigned int> getHandledStanzasCount() const { + return handledStanzasCount; + } + + void setHandledStanzasCount(unsigned int i) { + handledStanzasCount = i; + } + + private: + std::string resumeID; + boost::optional<unsigned int> handledStanzasCount; + }; +} diff --git a/Swiften/Elements/Subject.h b/Swiften/Elements/Subject.h index 6b5a916..bc757af 100644 --- a/Swiften/Elements/Subject.h +++ b/Swiften/Elements/Subject.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> #include <string> namespace Swift { diff --git a/Swiften/Elements/TLSProceed.h b/Swiften/Elements/TLSProceed.h index fbcab04..4bd790a 100644 --- a/Swiften/Elements/TLSProceed.h +++ b/Swiften/Elements/TLSProceed.h @@ -4,17 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_TLSProceed_H -#define SWIFTEN_TLSProceed_H +#pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { - class TLSProceed : public Element - { + class TLSProceed : public Element { public: TLSProceed() {} }; } - -#endif diff --git a/Swiften/Elements/UnblockPayload.h b/Swiften/Elements/UnblockPayload.h new file mode 100644 index 0000000..b6593ab --- /dev/null +++ b/Swiften/Elements/UnblockPayload.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + class UnblockPayload : public Payload { + public: + UnblockPayload() { + } + + void addItem(const JID& item) { + items.push_back(item); + } + + const std::vector<JID>& getItems() const { + return items; + } + + private: + std::vector<JID> items; + }; +} diff --git a/Swiften/Elements/UnitTest/FormTest.cpp b/Swiften/Elements/UnitTest/FormTest.cpp index de92d70..1134182 100644 --- a/Swiften/Elements/UnitTest/FormTest.cpp +++ b/Swiften/Elements/UnitTest/FormTest.cpp @@ -8,7 +8,7 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Form.h" +#include <Swiften/Elements/Form.h> using namespace Swift; diff --git a/Swiften/Elements/UnitTest/IQTest.cpp b/Swiften/Elements/UnitTest/IQTest.cpp index c170d61..23255b8 100644 --- a/Swiften/Elements/UnitTest/IQTest.cpp +++ b/Swiften/Elements/UnitTest/IQTest.cpp @@ -8,8 +8,8 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/SoftwareVersion.h" +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/SoftwareVersion.h> using namespace Swift; diff --git a/Swiften/Elements/UnitTest/StanzaTest.cpp b/Swiften/Elements/UnitTest/StanzaTest.cpp index 4020f8b..0319b52 100644 --- a/Swiften/Elements/UnitTest/StanzaTest.cpp +++ b/Swiften/Elements/UnitTest/StanzaTest.cpp @@ -7,11 +7,12 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/Delay.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Delay.h> using namespace Swift; diff --git a/Swiften/Elements/UnknownElement.h b/Swiften/Elements/UnknownElement.h index 549a922..100ba92 100644 --- a/Swiften/Elements/UnknownElement.h +++ b/Swiften/Elements/UnknownElement.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_UnknownElement_H -#define SWIFTEN_UnknownElement_H +#pragma once -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { class UnknownElement : public Element { @@ -15,5 +14,3 @@ namespace Swift { UnknownElement() {} }; } - -#endif diff --git a/Swiften/Elements/VCard.cpp b/Swiften/Elements/VCard.cpp index 8262e07..8bf3eb9 100644 --- a/Swiften/Elements/VCard.cpp +++ b/Swiften/Elements/VCard.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Elements/VCard.h" +#include <Swiften/Elements/VCard.h> -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/foreach.h> namespace Swift { @@ -16,7 +16,7 @@ VCard::EMailAddress VCard::getPreferredEMailAddress() const { return address; } } - if (emailAddresses_.size() > 0) { + if (!emailAddresses_.empty()) { return emailAddresses_[0]; } return EMailAddress(); diff --git a/Swiften/Elements/VCard.h b/Swiften/Elements/VCard.h index d2423e1..f9822c9 100644 --- a/Swiften/Elements/VCard.h +++ b/Swiften/Elements/VCard.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Elements/Payload.h> namespace Swift { class VCard : public Payload { @@ -60,10 +60,10 @@ namespace Swift { const std::string& getNickname() const { return nick_; } void setPhoto(const ByteArray& photo) { photo_ = photo; } - const ByteArray& getPhoto() { return photo_; } + const ByteArray& getPhoto() const { return photo_; } void setPhotoType(const std::string& photoType) { photoType_ = photoType; } - const std::string& getPhotoType() { return photoType_; } + const std::string& getPhotoType() const { return photoType_; } const std::string& getUnknownContent() const { return unknownContent_; } void addUnknownContent(const std::string& c) { diff --git a/Swiften/Elements/VCardUpdate.h b/Swiften/Elements/VCardUpdate.h index bbfd31e..782106c 100644 --- a/Swiften/Elements/VCardUpdate.h +++ b/Swiften/Elements/VCardUpdate.h @@ -7,7 +7,7 @@ #pragma once #include <string> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class VCardUpdate : public Payload { @@ -15,7 +15,7 @@ namespace Swift { VCardUpdate(const std::string& photoHash = "") : photoHash_(photoHash) {} void setPhotoHash(const std::string& photoHash) { photoHash_ = photoHash; } - const std::string& getPhotoHash() { return photoHash_; } + const std::string& getPhotoHash() const { return photoHash_; } private: std::string photoHash_; diff --git a/Swiften/Elements/Version.h b/Swiften/Elements/Version.h index 0a65573..350fd91 100644 --- a/Swiften/Elements/Version.h +++ b/Swiften/Elements/Version.h @@ -4,15 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_STANZAS_VERSION_H -#define SWIFTEN_STANZAS_VERSION_H +#pragma once #include <string> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { - class Version : public Payload - { + class Version : public Payload { public: Version(const std::string& name = "", const std::string& version = "", const std::string& os = "") : name_(name), version_(version), os_(os) { } @@ -26,5 +24,3 @@ namespace Swift { std::string os_; }; } - -#endif diff --git a/Swiften/Entity/Entity.cpp b/Swiften/Entity/Entity.cpp index da2ecaf..44f9fbf 100644 --- a/Swiften/Entity/Entity.cpp +++ b/Swiften/Entity/Entity.cpp @@ -4,28 +4,47 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Entity/Entity.h" +#include <Swiften/Entity/Entity.h> + +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> + namespace Swift { +Entity::Entity() { + payloadParserFactories = new FullPayloadParserFactoryCollection(); + payloadSerializers = new FullPayloadSerializerCollection(); +} + Entity::~Entity() { + delete payloadSerializers; + delete payloadParserFactories; } void Entity::addPayloadParserFactory(PayloadParserFactory* payloadParserFactory) { - payloadParserFactories.addFactory(payloadParserFactory); + payloadParserFactories->addFactory(payloadParserFactory); } void Entity::removePayloadParserFactory(PayloadParserFactory* payloadParserFactory) { - payloadParserFactories.removeFactory(payloadParserFactory); + payloadParserFactories->removeFactory(payloadParserFactory); } void Entity::addPayloadSerializer(PayloadSerializer* payloadSerializer) { - payloadSerializers.addSerializer(payloadSerializer); + payloadSerializers->addSerializer(payloadSerializer); } void Entity::removePayloadSerializer(PayloadSerializer* payloadSerializer) { - payloadSerializers.removeSerializer(payloadSerializer); + payloadSerializers->removeSerializer(payloadSerializer); +} + +PayloadParserFactoryCollection* Entity::getPayloadParserFactories() { + return payloadParserFactories; +} + +PayloadSerializerCollection* Entity::getPayloadSerializers() { + return payloadSerializers; } } diff --git a/Swiften/Entity/Entity.h b/Swiften/Entity/Entity.h index 20d02ba..65480d0 100644 --- a/Swiften/Entity/Entity.h +++ b/Swiften/Entity/Entity.h @@ -6,21 +6,20 @@ #pragma once -#include <Swiften/Base/boost_bsignals.h> -#include <boost/shared_ptr.hpp> - -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" - namespace Swift { class PayloadParserFactory; class PayloadSerializer; + class FullPayloadParserFactoryCollection; + class FullPayloadSerializerCollection; + class PayloadParserFactoryCollection; + class PayloadSerializerCollection; /** * The base class for XMPP entities (Clients, Components). */ class Entity { public: + Entity(); virtual ~Entity(); void addPayloadParserFactory(PayloadParserFactory* payloadParserFactory); @@ -30,16 +29,11 @@ namespace Swift { void removePayloadSerializer(PayloadSerializer* payloadSerializer); protected: - PayloadParserFactoryCollection* getPayloadParserFactories() { - return &payloadParserFactories; - } - - PayloadSerializerCollection* getPayloadSerializers() { - return &payloadSerializers; - } + PayloadParserFactoryCollection* getPayloadParserFactories(); + PayloadSerializerCollection* getPayloadSerializers(); private: - FullPayloadParserFactoryCollection payloadParserFactories; - FullPayloadSerializerCollection payloadSerializers; + FullPayloadParserFactoryCollection* payloadParserFactories; + FullPayloadSerializerCollection* payloadSerializers; }; } diff --git a/Swiften/Entity/GenericPayloadPersister.h b/Swiften/Entity/GenericPayloadPersister.h new file mode 100644 index 0000000..63553de --- /dev/null +++ b/Swiften/Entity/GenericPayloadPersister.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Entity/PayloadPersister.h> +#include <Swiften/Parser/GenericPayloadParserFactory.h> + +namespace Swift { + template<typename PAYLOAD, typename PARSER, typename SERIALIZER> + class GenericPayloadPersister : public PayloadPersister { + public: + GenericPayloadPersister() { + } + + public: + boost::shared_ptr<PAYLOAD> loadPayloadGeneric(const boost::filesystem::path& path) { + return boost::dynamic_pointer_cast<PAYLOAD>(loadPayload(path)); + } + + protected: + virtual const PayloadSerializer* getSerializer() const { + return &serializer; + } + + virtual PayloadParser* createParser() const { + return new PARSER(); + } + + private: + SERIALIZER serializer; + }; +} diff --git a/Swiften/Entity/PayloadPersister.cpp b/Swiften/Entity/PayloadPersister.cpp new file mode 100644 index 0000000..729d36a --- /dev/null +++ b/Swiften/Entity/PayloadPersister.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Entity/PayloadPersister.h> + +#include <boost/filesystem/fstream.hpp> +#include <boost/filesystem.hpp> +#include <iostream> + +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Parser/PayloadParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Serializer/PayloadSerializer.h> + +using namespace Swift; + +PayloadPersister::PayloadPersister() { +} + +PayloadPersister::~PayloadPersister() { +} + +void PayloadPersister::savePayload(boost::shared_ptr<Payload> payload, const boost::filesystem::path& path) { + try { + if (!boost::filesystem::exists(path.parent_path())) { + boost::filesystem::create_directories(path.parent_path()); + } + boost::filesystem::ofstream file(path); + file << getSerializer()->serialize(payload); + file.close(); + } + catch (const boost::filesystem::filesystem_error& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + } +} + +boost::shared_ptr<Payload> PayloadPersister::loadPayload(const boost::filesystem::path& path) { + try { + if (boost::filesystem::exists(path)) { + ByteArray data; + readByteArrayFromFile(data, path.string()); + boost::shared_ptr<PayloadParser> parser(createParser()); + PayloadParserTester tester(parser.get()); + tester.parse(byteArrayToString(data)); + return parser->getPayload(); + } + } + catch (const boost::filesystem::filesystem_error& e) { + std::cerr << "ERROR: " << e.what() << std::endl; + } + return boost::shared_ptr<Payload>(); +} diff --git a/Swiften/Entity/PayloadPersister.h b/Swiften/Entity/PayloadPersister.h new file mode 100644 index 0000000..ea7c74c --- /dev/null +++ b/Swiften/Entity/PayloadPersister.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/filesystem/path.hpp> + +namespace Swift { + class Payload; + class PayloadSerializer; + class PayloadParser; + + class PayloadPersister { + public: + PayloadPersister(); + virtual ~PayloadPersister(); + + void savePayload(boost::shared_ptr<Payload>, const boost::filesystem::path&); + boost::shared_ptr<Payload> loadPayload(const boost::filesystem::path&); + + protected: + + virtual const PayloadSerializer* getSerializer() const = 0; + virtual PayloadParser* createParser() const = 0; + }; +} diff --git a/Swiften/EventLoop/Cocoa/CocoaEvent.mm b/Swiften/EventLoop/Cocoa/CocoaEvent.mm index 8a90983..049e3b6 100644 --- a/Swiften/EventLoop/Cocoa/CocoaEvent.mm +++ b/Swiften/EventLoop/Cocoa/CocoaEvent.mm @@ -1,6 +1,6 @@ -#include "Swiften/EventLoop/Cocoa/CocoaEvent.h" -#include "Swiften/EventLoop/Event.h" -#include "Swiften/EventLoop/Cocoa/CocoaEventLoop.h" +#include <Swiften/EventLoop/Cocoa/CocoaEvent.h> +#include <Swiften/EventLoop/Event.h> +#include <Swiften/EventLoop/Cocoa/CocoaEventLoop.h> @implementation CocoaEvent diff --git a/Swiften/EventLoop/Cocoa/CocoaEventLoop.h b/Swiften/EventLoop/Cocoa/CocoaEventLoop.h index 2b60741..60ef32b 100644 --- a/Swiften/EventLoop/Cocoa/CocoaEventLoop.h +++ b/Swiften/EventLoop/Cocoa/CocoaEventLoop.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class CocoaEventLoop : public EventLoop { diff --git a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm index b90f3c6..ba73884 100644 --- a/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm +++ b/Swiften/EventLoop/Cocoa/CocoaEventLoop.mm @@ -1,5 +1,5 @@ -#include "Swiften/EventLoop/Cocoa/CocoaEventLoop.h" -#include "Swiften/EventLoop/Cocoa/CocoaEvent.h" +#include <Swiften/EventLoop/Cocoa/CocoaEventLoop.h> +#include <Swiften/EventLoop/Cocoa/CocoaEvent.h> #pragma GCC diagnostic ignored "-Wold-style-cast" diff --git a/Swiften/EventLoop/DummyEventLoop.cpp b/Swiften/EventLoop/DummyEventLoop.cpp new file mode 100644 index 0000000..3741eec --- /dev/null +++ b/Swiften/EventLoop/DummyEventLoop.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/EventLoop/DummyEventLoop.h> + +#include <iostream> + +namespace Swift { + +DummyEventLoop::DummyEventLoop() { +} + +DummyEventLoop::~DummyEventLoop() { + if (!events_.empty()) { + std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl; + } + events_.clear(); +} + + +} diff --git a/Swiften/EventLoop/DummyEventLoop.h b/Swiften/EventLoop/DummyEventLoop.h index b7ef516..4c01c16 100644 --- a/Swiften/EventLoop/DummyEventLoop.h +++ b/Swiften/EventLoop/DummyEventLoop.h @@ -7,24 +7,14 @@ #pragma once #include <deque> -#include <iostream> -#include <boost/function.hpp> -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class DummyEventLoop : public EventLoop { public: - DummyEventLoop() { - } - - ~DummyEventLoop() { - if (!events_.empty()) { - std::cerr << "DummyEventLoop: Unhandled events at destruction time" << std::endl; - } - events_.clear(); - } + DummyEventLoop(); + ~DummyEventLoop(); void processEvents() { while (!events_.empty()) { @@ -34,7 +24,7 @@ namespace Swift { } bool hasEvents() { - return events_.size() > 0; + return !events_.empty(); } virtual void post(const Event& event) { diff --git a/Swiften/EventLoop/Event.h b/Swiften/EventLoop/Event.h index 6f5a9e5..b1d7cac 100644 --- a/Swiften/EventLoop/Event.h +++ b/Swiften/EventLoop/Event.h @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> #include <boost/function.hpp> -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { class Event { diff --git a/Swiften/EventLoop/EventLoop.cpp b/Swiften/EventLoop/EventLoop.cpp index 56bb6ac..2b8f00d 100644 --- a/Swiften/EventLoop/EventLoop.cpp +++ b/Swiften/EventLoop/EventLoop.cpp @@ -4,11 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/EventLoop/EventLoop.h> #include <algorithm> #include <boost/bind.hpp> #include <iostream> +#include <cassert> #include <Swiften/Base/Log.h> @@ -17,6 +18,7 @@ namespace Swift { inline void invokeCallback(const Event& event) { try { + assert(!event.callback.empty()); event.callback(); } catch (const std::exception& e) { diff --git a/Swiften/EventLoop/EventLoop.h b/Swiften/EventLoop/EventLoop.h index ab58ffc..9e47112 100644 --- a/Swiften/EventLoop/EventLoop.h +++ b/Swiften/EventLoop/EventLoop.h @@ -11,7 +11,7 @@ #include <list> #include <deque> -#include "Swiften/EventLoop/Event.h" +#include <Swiften/EventLoop/Event.h> namespace Swift { class EventOwner; @@ -35,7 +35,7 @@ namespace Swift { private: struct HasOwner { HasOwner(boost::shared_ptr<EventOwner> owner) : owner(owner) {} - bool operator()(const Event& event) { return event.owner == owner; } + bool operator()(const Event& event) const { return event.owner == owner; } boost::shared_ptr<EventOwner> owner; }; boost::mutex eventsMutex_; diff --git a/Swiften/EventLoop/EventOwner.cpp b/Swiften/EventLoop/EventOwner.cpp index 275f1d1..9970499 100644 --- a/Swiften/EventLoop/EventOwner.cpp +++ b/Swiften/EventLoop/EventOwner.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { diff --git a/Swiften/EventLoop/Qt/QtEventLoop.h b/Swiften/EventLoop/Qt/QtEventLoop.h index 8f6c709..0097cf9 100644 --- a/Swiften/EventLoop/Qt/QtEventLoop.h +++ b/Swiften/EventLoop/Qt/QtEventLoop.h @@ -10,7 +10,7 @@ #include <QEvent> #include <QCoreApplication> -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class QtEventLoop : public QObject, public EventLoop { diff --git a/Swiften/EventLoop/SConscript b/Swiften/EventLoop/SConscript index 21ae8b9..e448f43 100644 --- a/Swiften/EventLoop/SConscript +++ b/Swiften/EventLoop/SConscript @@ -5,6 +5,7 @@ sources = [ "EventOwner.cpp", "Event.cpp", "SimpleEventLoop.cpp", + "DummyEventLoop.cpp", ] objects = swiften_env.SwiftenObject(sources) diff --git a/Swiften/EventLoop/SimpleEventLoop.cpp b/Swiften/EventLoop/SimpleEventLoop.cpp index b77639c..63b8ba5 100644 --- a/Swiften/EventLoop/SimpleEventLoop.cpp +++ b/Swiften/EventLoop/SimpleEventLoop.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/EventLoop/SimpleEventLoop.h" +#include <Swiften/EventLoop/SimpleEventLoop.h> #include <boost/bind.hpp> #include <iostream> -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/foreach.h> namespace Swift { @@ -30,7 +30,7 @@ void SimpleEventLoop::doRun(bool breakAfterEvents) { std::vector<Event> events; { boost::unique_lock<boost::mutex> lock(eventsMutex_); - while (events_.size() == 0) { + while (events_.empty()) { eventsAvailable_.wait(lock); } events.swap(events_); diff --git a/Swiften/EventLoop/SimpleEventLoop.h b/Swiften/EventLoop/SimpleEventLoop.h index 6fb3f53..72bd6a6 100644 --- a/Swiften/EventLoop/SimpleEventLoop.h +++ b/Swiften/EventLoop/SimpleEventLoop.h @@ -11,7 +11,7 @@ #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class SimpleEventLoop : public EventLoop { diff --git a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp index b777c1b..58396e6 100644 --- a/Swiften/EventLoop/UnitTest/EventLoopTest.cpp +++ b/Swiften/EventLoop/UnitTest/EventLoopTest.cpp @@ -9,10 +9,10 @@ #include <boost/thread.hpp> #include <boost/bind.hpp> -#include "Swiften/EventLoop/EventOwner.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/EventLoop/DummyEventLoop.h" -#include "Swiften/Base/sleep.h" +#include <Swiften/EventLoop/EventOwner.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Base/sleep.h> using namespace Swift; diff --git a/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp b/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp index b779bed..475b6b5 100644 --- a/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp +++ b/Swiften/EventLoop/UnitTest/SimpleEventLoopTest.cpp @@ -9,8 +9,8 @@ #include <boost/thread.hpp> #include <boost/bind.hpp> -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/Base/sleep.h" +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Base/sleep.h> using namespace Swift; diff --git a/Swiften/Examples/BenchTool/BenchTool.cpp b/Swiften/Examples/BenchTool/BenchTool.cpp index 9e54ed9..ba6cf84 100644 --- a/Swiften/Examples/BenchTool/BenchTool.cpp +++ b/Swiften/Examples/BenchTool/BenchTool.cpp @@ -6,14 +6,15 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> -#include "Swiften/Client/Client.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/BoostNetworkFactories.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/Roster/GetRosterRequest.h" -#include "Swiften/Client/ClientXMLTracer.h" +#include <Swiften/Client/Client.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/BoostNetworkFactories.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Roster/GetRosterRequest.h> +#include <Swiften/Client/ClientXMLTracer.h> #include <Swiften/Base/sleep.h> #include <Swiften/TLS/BlindCertificateTrustChecker.h> @@ -45,7 +46,7 @@ int main(int, char**) { BlindCertificateTrustChecker trustChecker; std::vector<CoreClient*> clients; for (int i = 0; i < numberOfInstances; ++i) { - CoreClient* client = new Swift::CoreClient(JID(jid), std::string(pass), &networkFactories); + CoreClient* client = new Swift::CoreClient(JID(jid), createSafeByteArray(std::string(pass)), &networkFactories); client->setCertificateTrustChecker(&trustChecker); client->onConnected.connect(&handleConnected); clients.push_back(client); diff --git a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp index fda203a..c957481 100644 --- a/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp +++ b/Swiften/Examples/ConnectivityTest/ConnectivityTest.cpp @@ -6,15 +6,16 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> -#include "Swiften/Client/Client.h" -#include "Swiften/Network/Timer.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/BoostNetworkFactories.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Client/ClientXMLTracer.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/Disco/GetDiscoInfoRequest.h" +#include <Swiften/Client/Client.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/BoostNetworkFactories.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Disco/GetDiscoInfoRequest.h> using namespace Swift; @@ -43,7 +44,7 @@ void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> /*info*/, ErrorP void handleConnected() { exitCode = NO_RESPONSE; GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(), client->getIQRouter()); - discoInfoRequest->onResponse.connect(handleServerDiscoInfoResponse); + discoInfoRequest->onResponse.connect(&handleServerDiscoInfoResponse); discoInfoRequest->send(); } diff --git a/Swiften/Examples/ConnectivityTest/SConscript b/Swiften/Examples/ConnectivityTest/SConscript index f66c57f..7bc3892 100644 --- a/Swiften/Examples/ConnectivityTest/SConscript +++ b/Swiften/Examples/ConnectivityTest/SConscript @@ -2,12 +2,6 @@ Import("env") myenv = env.Clone() myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) -myenv.MergeFlags(myenv["BOOST_FLAGS"]) -myenv.MergeFlags(myenv.get("SQLITE_FLAGS", {})) -myenv.MergeFlags(myenv["ZLIB_FLAGS"]) -myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) -myenv.MergeFlags(myenv.get("LIBXML_FLAGS", "")) -myenv.MergeFlags(myenv.get("EXPAT_FLAGS", "")) -myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) +myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) + tester = myenv.Program("ConnectivityTest", ["ConnectivityTest.cpp"]) diff --git a/Swiften/Examples/LinkLocalTool/main.cpp b/Swiften/Examples/LinkLocalTool/main.cpp index d63ef53..18e282b 100644 --- a/Swiften/Examples/LinkLocalTool/main.cpp +++ b/Swiften/Examples/LinkLocalTool/main.cpp @@ -8,11 +8,11 @@ #include <iostream> -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> using namespace Swift; diff --git a/Swiften/Examples/NetworkTool/.gitignore b/Swiften/Examples/NetworkTool/.gitignore new file mode 100644 index 0000000..ab9c4e7 --- /dev/null +++ b/Swiften/Examples/NetworkTool/.gitignore @@ -0,0 +1 @@ +NetworkTool diff --git a/Swiften/Examples/NetworkTool/SConscript b/Swiften/Examples/NetworkTool/SConscript new file mode 100644 index 0000000..38622ff --- /dev/null +++ b/Swiften/Examples/NetworkTool/SConscript @@ -0,0 +1,10 @@ +Import("env") + +if env["experimental"] : + myenv = env.Clone() + myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) + myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) + + linkLocalTool = myenv.Program("NetworkTool", [ + "main.cpp" + ]) diff --git a/Swiften/Examples/NetworkTool/main.cpp b/Swiften/Examples/NetworkTool/main.cpp new file mode 100644 index 0000000..ace38fd --- /dev/null +++ b/Swiften/Examples/NetworkTool/main.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <iostream> +#include <boost/lexical_cast.hpp> + +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Network/PlatformNATTraversalWorker.h> +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> +#include <Swiften/Network/NATTraversalForwardPortRequest.h> +#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> +#include <Swiften/Network/PlatformNetworkEnvironment.h> + +using namespace Swift; + +SimpleEventLoop eventLoop; + +void handleGetPublicIPRequestResponse(const boost::optional<HostAddress>& result) { + if (result) { + std::cerr << "Result: " << result->toString() << std::endl;; + } + else { + std::cerr << "No result" << std::endl; + } + eventLoop.stop(); +} + +void handleGetForwardPortRequestResponse(const boost::optional<NATPortMapping>& result) { + if (result) { + std::cerr << "Result: " << result->publicPort << " -> " << result->localPort << std::endl;; + } + else { + std::cerr << "No result" << std::endl; + } + eventLoop.stop(); +} + +void handleRemovePortForwardingRequestResponse(bool result) { + if (result) { + std::cerr << "Result: OK" << std::endl; + } + else { + std::cerr << "Result: ERROR" << std::endl; + } + eventLoop.stop(); +} + +int main(int argc, char* argv[]) { + if (argc < 2) { + std::cerr << "Invalid parameters" << std::endl; + return -1; + } + + PlatformNATTraversalWorker natTraverser(&eventLoop); + if (std::string(argv[1]) == "get-public-ip") { + boost::shared_ptr<NATTraversalGetPublicIPRequest> query = natTraverser.createGetPublicIPRequest(); + query->onResult.connect(boost::bind(&handleGetPublicIPRequestResponse, _1)); + query->run(); + eventLoop.run(); + } + else if (std::string(argv[1]) == "add-port-forward") { + if (argc < 4) { + std::cerr << "Invalid parameters" << std::endl; + } + boost::shared_ptr<NATTraversalForwardPortRequest> query = natTraverser.createForwardPortRequest(boost::lexical_cast<int>(argv[2]), boost::lexical_cast<int>(argv[3])); + query->onResult.connect(boost::bind(&handleGetForwardPortRequestResponse, _1)); + query->run(); + eventLoop.run(); + } + else if (std::string(argv[1]) == "remove-port-forward") { + if (argc < 4) { + std::cerr << "Invalid parameters" << std::endl; + } + boost::shared_ptr<NATTraversalRemovePortForwardingRequest> query = natTraverser.createRemovePortForwardingRequest(boost::lexical_cast<int>(argv[2]), boost::lexical_cast<int>(argv[3])); + query->onResult.connect(boost::bind(&handleRemovePortForwardingRequestResponse, _1)); + query->run(); + eventLoop.run(); + } + else if (std::string(argv[1]) == "get-local-ip") { + std::cout << PlatformNetworkEnvironment().getLocalAddress().toString() << std::endl; + } +} diff --git a/Swiften/Examples/ParserTester/ParserTester.cpp b/Swiften/Examples/ParserTester/ParserTester.cpp index 61c0eae..211d44f 100644 --- a/Swiften/Examples/ParserTester/ParserTester.cpp +++ b/Swiften/Examples/ParserTester/ParserTester.cpp @@ -8,10 +8,10 @@ #include <fstream> #include <typeinfo> -#include "Swiften/Parser/UnitTest/ParserTester.h" -#include "Swiften/Parser/XMPPParser.h" -#include "Swiften/Parser/XMPPParserClient.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include <Swiften/Parser/UnitTest/ParserTester.h> +#include <Swiften/Parser/XMPPParser.h> +#include <Swiften/Parser/XMPPParserClient.h> +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> using namespace Swift; diff --git a/Swiften/Examples/SConscript b/Swiften/Examples/SConscript index 9b9a35a..fb568fc 100644 --- a/Swiften/Examples/SConscript +++ b/Swiften/Examples/SConscript @@ -7,6 +7,7 @@ SConscript(dirs = [ "SendFile", "ConnectivityTest", "LinkLocalTool", + "NetworkTool", "ParserTester", "BenchTool", ]) diff --git a/Swiften/Examples/SendFile/ReceiveFile.cpp b/Swiften/Examples/SendFile/ReceiveFile.cpp index b46d790..f80f03a 100644 --- a/Swiften/Examples/SendFile/ReceiveFile.cpp +++ b/Swiften/Examples/SendFile/ReceiveFile.cpp @@ -7,14 +7,23 @@ #include <boost/bind.hpp> #include <boost/filesystem.hpp> #include <boost/smart_ptr/make_shared.hpp> +#include <iostream> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Base/foreach.h> #include <Swiften/Client/Client.h> +#include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Network/BoostNetworkFactories.h> #include <Swiften/EventLoop/SimpleEventLoop.h> #include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/Disco/ClientDiscoManager.h> #include <Swiften/FileTransfer/IncomingFileTransferManager.h> #include <Swiften/FileTransfer/FileWriteBytestream.h> #include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/FileTransferManager.h> using namespace Swift; @@ -23,19 +32,20 @@ BoostNetworkFactories networkFactories(&eventLoop); int exitCode = 2; +static const std::string CLIENT_NAME = "Swiften FT Test"; +static const std::string CLIENT_NODE = "http://swift.im"; + class FileReceiver { public: FileReceiver(const JID& jid, const std::string& password) : jid(jid), password(password), jingleSessionManager(NULL), incomingFileTransferManager(NULL) { client = new Swift::Client(jid, password, &networkFactories); client->onConnected.connect(boost::bind(&FileReceiver::handleConnected, this)); client->onDisconnected.connect(boost::bind(&FileReceiver::handleDisconnected, this, _1)); - //tracer = new ClientXMLTracer(client); + tracer = new ClientXMLTracer(client); } ~FileReceiver() { - delete incomingFileTransferManager; - delete jingleSessionManager; - //delete tracer; + delete tracer; client->onDisconnected.disconnect(boost::bind(&FileReceiver::handleDisconnected, this, _1)); client->onConnected.disconnect(boost::bind(&FileReceiver::handleConnected, this)); delete client; @@ -54,13 +64,24 @@ class FileReceiver { private: void handleConnected() { - client->sendPresence(Presence::create()); - jingleSessionManager = new JingleSessionManager(client->getIQRouter()); - incomingFileTransferManager = new IncomingFileTransferManager(jingleSessionManager, client->getIQRouter()); - incomingFileTransferManager->onIncomingFileTransfer.connect(boost::bind(&FileReceiver::handleIncomingFileTransfer, this, _1)); + Swift::logging = true; + client->getFileTransferManager()->startListeningOnPort(9999); + client->getFileTransferManager()->onIncomingFileTransfer.connect(boost::bind(&FileReceiver::handleIncomingFileTransfer, this, _1)); + + DiscoInfo discoInfo; + discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); + discoInfo.addFeature(DiscoInfo::JingleFeature); + discoInfo.addFeature(DiscoInfo::JingleFTFeature); + discoInfo.addFeature(DiscoInfo::Bytestream); + discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature); + discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature); + client->getDiscoManager()->setCapsNode(CLIENT_NODE); + client->getDiscoManager()->setDiscoInfo(discoInfo); + client->getPresenceSender()->sendPresence(Presence::create()); } void handleIncomingFileTransfer(IncomingFileTransfer::ref transfer) { + SWIFT_LOG(debug) << "foo" << std::endl; incomingFileTransfers.push_back(transfer); transfer->accept(boost::make_shared<FileWriteBytestream>("out")); //transfer->onFinished.connect(boost::bind(&FileReceiver::handleFileTransferFinished, this, _1)); @@ -97,6 +118,9 @@ class FileReceiver { JingleSessionManager* jingleSessionManager; IncomingFileTransferManager* incomingFileTransferManager; std::vector<IncomingFileTransfer::ref> incomingFileTransfers; + DefaultLocalJingleTransportCandidateGeneratorFactory *localFactory; + DefaultRemoteJingleTransportCandidateSelectorFactory *remoteFactory; + SOCKS5BytestreamRegistry* bytestreamRegistry; }; diff --git a/Swiften/Examples/SendFile/SConscript b/Swiften/Examples/SendFile/SConscript index 6986f22..d335513 100644 --- a/Swiften/Examples/SendFile/SConscript +++ b/Swiften/Examples/SendFile/SConscript @@ -2,14 +2,7 @@ Import("env") myenv = env.Clone() myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) -myenv.MergeFlags(myenv["BOOST_FLAGS"]) -myenv.MergeFlags(myenv["ZLIB_FLAGS"]) -myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) -myenv.MergeFlags(myenv.get("SQLITE_FLAGS", {})) -myenv.MergeFlags(myenv.get("LIBXML_FLAGS", "")) -myenv.MergeFlags(myenv.get("EXPAT_FLAGS", "")) -myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) +myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) myenv.Program("SendFile", ["SendFile.cpp"]) myenv.Program("ReceiveFile", ["ReceiveFile.cpp"]) diff --git a/Swiften/Examples/SendFile/SendFile.cpp b/Swiften/Examples/SendFile/SendFile.cpp index 5ec00a9..9b2105b 100644 --- a/Swiften/Examples/SendFile/SendFile.cpp +++ b/Swiften/Examples/SendFile/SendFile.cpp @@ -4,20 +4,34 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/bind.hpp> #include <boost/filesystem.hpp> - -#include "Swiften/Client/Client.h" -#include "Swiften/Network/BoostTimer.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/BoostNetworkFactories.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Client/ClientXMLTracer.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/FileTransfer/OutgoingFileTransfer.h" -#include "Swiften/FileTransfer/FileReadBytestream.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" -#include "Swiften/Network/BoostConnectionServer.h" +#include <iostream> + +#include <Swiften/Client/Client.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Network/BoostTimer.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/BoostNetworkFactories.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/FileTransfer/OutgoingSIFileTransfer.h> +#include <Swiften/FileTransfer/FileReadBytestream.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/Network/BoostConnectionServer.h> +#include <Swiften/FileTransfer/OutgoingFileTransferManager.h> +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> +#include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/StringCodecs/MD5.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/FileTransfer/FileTransferManager.h> using namespace Swift; @@ -28,45 +42,65 @@ int exitCode = 2; class FileSender { public: - FileSender(const JID& jid, const std::string& password, const JID& recipient, const boost::filesystem::path& file, int port) : jid(jid), password(password), recipient(recipient), file(file), transfer(NULL) { - connectionServer = BoostConnectionServer::create(port, networkFactories.getIOServiceThread()->getIOService(), &eventLoop); - socksBytestreamServer = new SOCKS5BytestreamServer(connectionServer); + FileSender(const JID& jid, const std::string& password, const JID& recipient, const boost::filesystem::path& file) : jid(jid), password(password), recipient(recipient), file(file) { client = new Swift::Client(jid, password, &networkFactories); client->onConnected.connect(boost::bind(&FileSender::handleConnected, this)); client->onDisconnected.connect(boost::bind(&FileSender::handleDisconnected, this, _1)); - //tracer = new ClientXMLTracer(client); + tracer = new ClientXMLTracer(client); + client->getEntityCapsProvider()->onCapsChanged.connect(boost::bind(&FileSender::handleCapsChanged, this, _1)); } ~FileSender() { - //delete tracer; + delete tracer; client->onDisconnected.disconnect(boost::bind(&FileSender::handleDisconnected, this, _1)); client->onConnected.disconnect(boost::bind(&FileSender::handleConnected, this)); delete client; - delete socksBytestreamServer; } - + void start() { - connectionServer->start(); - socksBytestreamServer->start(); client->connect(); } - void stop() { - if (transfer) { - transfer->stop(); - } - client->disconnect(); - socksBytestreamServer->stop(); - connectionServer->stop(); - } - private: void handleConnected() { client->sendPresence(Presence::create()); - transfer = new OutgoingFileTransfer("myid", client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer); + + client->getFileTransferManager()->startListeningOnPort(19999); + //ByteArray fileData; + //readByteArrayFromFile(fileData, file.string()); + + // gather file information + /*StreamInitiationFileInfo fileInfo; + + fileInfo.setName(file.filename()); + fileInfo.setSize(boost::filesystem::file_size(file)); + fileInfo.setDescription("Some file!"); + fileInfo.setDate(boost::posix_time::from_time_t(boost::filesystem::last_write_time(file)));*/ + //fileInfo.setHash(Hexify::hexify(MD5::getHash(fileData))); + /* + transfer = new OutgoingSIFileTransfer("myid", client->getJID(), recipient, file.filename(), boost::filesystem::file_size(file), "A file", boost::shared_ptr<FileReadBytestream>(new FileReadBytestream(file)), client->getIQRouter(), socksBytestreamServer); transfer->onFinished.connect(boost::bind(&FileSender::handleFileTransferFinished, this, _1)); transfer->start(); + */ + } + + void handleCapsChanged(JID jid) { + if (jid.toBare() == recipient) { + // create ReadBytestream from file + boost::shared_ptr<FileReadBytestream> fileStream = boost::make_shared<FileReadBytestream>(file); + + outgoingFileTransfer = client->getFileTransferManager()->createOutgoingFileTransfer(recipient, file, "Some File!", fileStream); + + if (outgoingFileTransfer) { + std::cout << "started FT" << std::endl; + outgoingFileTransfer->start(); + // TODO: getting notified about FT status and end + } else { + std::cout << "[ ERROR ] " << recipient << " doesn't support any kind of file transfer!" << std::endl; + //client->disconnect(); + } + } } void handleDisconnected(const boost::optional<ClientError>&) { @@ -83,23 +117,23 @@ class FileSender { exit(0); } } - + void exit(int code) { exitCode = code; - stop(); eventLoop.stop(); } private: BoostConnectionServer::ref connectionServer; SOCKS5BytestreamServer* socksBytestreamServer; + SOCKS5BytestreamRegistry* registry; + OutgoingFileTransfer::ref outgoingFileTransfer; JID jid; std::string password; JID recipient; boost::filesystem::path file; Client* client; ClientXMLTracer* tracer; - OutgoingFileTransfer* transfer; }; @@ -111,9 +145,9 @@ int main(int argc, char* argv[]) { JID sender(argv[1]); JID recipient(argv[3]); - FileSender fileSender(sender, std::string(argv[2]), recipient, boost::filesystem::path(argv[4]), 8888); + Swift::logging = true; + FileSender fileSender(sender, std::string(argv[2]), recipient, boost::filesystem::path(argv[4])); fileSender.start(); - { /*BoostTimer::ref timer(BoostTimer::create(30000, &MainBoostIOServiceThread::getInstance().getIOService())); timer->onTick.connect(boost::bind(&SimpleEventLoop::stop, &eventLoop)); diff --git a/Swiften/Examples/SendMessage/SConscript b/Swiften/Examples/SendMessage/SConscript index 05ab4c3..8907d25 100644 --- a/Swiften/Examples/SendMessage/SConscript +++ b/Swiften/Examples/SendMessage/SConscript @@ -2,12 +2,6 @@ Import("env") myenv = env.Clone() myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) -myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) -myenv.MergeFlags(myenv["BOOST_FLAGS"]) -myenv.MergeFlags(myenv["ZLIB_FLAGS"]) -myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) -myenv.MergeFlags(myenv.get("SQLITE_FLAGS", {})) -myenv.MergeFlags(myenv.get("LIBXML_FLAGS", "")) -myenv.MergeFlags(myenv.get("EXPAT_FLAGS", "")) -myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) +myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) + tester = myenv.Program("SendMessage", ["SendMessage.cpp"]) diff --git a/Swiften/Examples/SendMessage/SendMessage.cpp b/Swiften/Examples/SendMessage/SendMessage.cpp index d7f7333..f4dbf53 100644 --- a/Swiften/Examples/SendMessage/SendMessage.cpp +++ b/Swiften/Examples/SendMessage/SendMessage.cpp @@ -6,13 +6,15 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> - -#include "Swiften/Client/Client.h" -#include "Swiften/Network/BoostNetworkFactories.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Client/ClientXMLTracer.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" +#include <iostream> + +#include <Swiften/Client/Client.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Network/BoostNetworkFactories.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> using namespace Swift; diff --git a/Swiften/FileTransfer/ByteArrayReadBytestream.h b/Swiften/FileTransfer/ByteArrayReadBytestream.h index d459658..9311099 100644 --- a/Swiften/FileTransfer/ByteArrayReadBytestream.h +++ b/Swiften/FileTransfer/ByteArrayReadBytestream.h @@ -6,31 +6,47 @@ #pragma once -#include "Swiften/FileTransfer/ReadBytestream.h" -#include "Swiften/Base/ByteArray.h" +#include <vector> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Algorithm.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class ByteArrayReadBytestream : public ReadBytestream { public: - ByteArrayReadBytestream(const ByteArray& data) : data(data), position(0) { + ByteArrayReadBytestream(const std::vector<unsigned char>& data) : data(data), position(0), dataComplete(true) { } - virtual ByteArray read(size_t size) { + virtual boost::shared_ptr<ByteArray> read(size_t size) { size_t readSize = size; - if (position + readSize > data.getSize()) { - readSize = data.getSize() - position; + if (position + readSize > data.size()) { + readSize = data.size() - position; } - ByteArray result(data.getData() + position, readSize); + boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>(data.begin() + position, data.begin() + position + readSize); + + onRead(*result); position += readSize; return result; } virtual bool isFinished() const { - return position >= data.getSize(); + return position >= data.size() && dataComplete; + } + + virtual void setDataComplete(bool b) { + dataComplete = b; + } + + void addData(const std::vector<unsigned char>& moreData) { + append(data, moreData); + onDataAvailable(); } private: - ByteArray data; + std::vector<unsigned char> data; size_t position; + bool dataComplete; }; } diff --git a/Swiften/FileTransfer/ByteArrayWriteBytestream.h b/Swiften/FileTransfer/ByteArrayWriteBytestream.h new file mode 100644 index 0000000..ef97ed9 --- /dev/null +++ b/Swiften/FileTransfer/ByteArrayWriteBytestream.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/FileTransfer/WriteBytestream.h> + +namespace Swift { + class ByteArrayWriteBytestream : public WriteBytestream { + public: + ByteArrayWriteBytestream() { + } + + virtual void write(const std::vector<unsigned char>& bytes) { + data.insert(data.end(), bytes.begin(), bytes.end()); + onWrite(bytes); + } + + const std::vector<unsigned char>& getData() const { + return data; + } + + private: + std::vector<unsigned char> data; + }; +} diff --git a/Swiften/FileTransfer/BytestreamsRequest.h b/Swiften/FileTransfer/BytestreamsRequest.h index 9757bfa..fee09ee 100644 --- a/Swiften/FileTransfer/BytestreamsRequest.h +++ b/Swiften/FileTransfer/BytestreamsRequest.h @@ -8,8 +8,8 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/Bytestreams.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/Bytestreams.h> namespace Swift { class BytestreamsRequest : public GenericRequest<Bytestreams> { @@ -20,8 +20,15 @@ namespace Swift { return ref(new BytestreamsRequest(jid, payload, router)); } + static ref create(const JID& from, const JID& to, boost::shared_ptr<Bytestreams> payload, IQRouter* router) { + return ref(new BytestreamsRequest(from, to, payload, router)); + } + private: BytestreamsRequest(const JID& jid, boost::shared_ptr<Bytestreams> payload, IQRouter* router) : GenericRequest<Bytestreams>(IQ::Set, jid, payload, router) { } + + BytestreamsRequest(const JID& from, const JID& to, boost::shared_ptr<Bytestreams> payload, IQRouter* router) : GenericRequest<Bytestreams>(IQ::Set, from, to, payload, router) { + } }; } diff --git a/Swiften/FileTransfer/ConnectivityManager.cpp b/Swiften/FileTransfer/ConnectivityManager.cpp new file mode 100644 index 0000000..7d25991 --- /dev/null +++ b/Swiften/FileTransfer/ConnectivityManager.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "ConnectivityManager.h" + +#include <boost/bind.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Network/NetworkInterface.h> +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> +#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> +#include <Swiften/Network/NATTraverser.h> +#include <Swiften/Network/PlatformNetworkEnvironment.h> + +namespace Swift { + +ConnectivityManager::ConnectivityManager(NATTraverser* worker) : natTraversalWorker(worker) { + +} + +ConnectivityManager::~ConnectivityManager() { + std::set<int> leftOpenPorts = ports; + foreach(int port, leftOpenPorts) { + removeListeningPort(port); + } +} + +void ConnectivityManager::addListeningPort(int port) { + ports.insert(port); + boost::shared_ptr<NATTraversalGetPublicIPRequest> getIPRequest = natTraversalWorker->createGetPublicIPRequest(); + if (getIPRequest) { + getIPRequest->onResult.connect(boost::bind(&ConnectivityManager::natTraversalGetPublicIPResult, this, _1)); + getIPRequest->run(); + } + + boost::shared_ptr<NATTraversalForwardPortRequest> forwardPortRequest = natTraversalWorker->createForwardPortRequest(port, port); + if (forwardPortRequest) { + forwardPortRequest->onResult.connect(boost::bind(&ConnectivityManager::natTraversalForwardPortResult, this, _1)); + forwardPortRequest->run(); + } +} + +void ConnectivityManager::removeListeningPort(int port) { + SWIFT_LOG(debug) << "remove listening port " << port << std::endl; + ports.erase(port); + boost::shared_ptr<NATTraversalRemovePortForwardingRequest> removePortForwardingRequest = natTraversalWorker->createRemovePortForwardingRequest(port, port); + if (removePortForwardingRequest) { + removePortForwardingRequest->run(); + } +} + +std::vector<HostAddressPort> ConnectivityManager::getHostAddressPorts() const { + PlatformNetworkEnvironment env; + std::vector<HostAddressPort> results; + + std::vector<HostAddress> addresses; + + std::vector<NetworkInterface> networkInterfaces; + foreach (const NetworkInterface& iface, networkInterfaces) { + foreach (const HostAddress& address, iface.getAddresses()) { + foreach (int port, ports) { + results.push_back(HostAddressPort(address, port)); + } + } + } + + return results; +} + +std::vector<HostAddressPort> ConnectivityManager::getAssistedHostAddressPorts() const { + std::vector<HostAddressPort> results; + + if (publicAddress) { + foreach (int port, ports) { + results.push_back(HostAddressPort(publicAddress.get(), port)); + } + } + + return results; +} + +void ConnectivityManager::natTraversalGetPublicIPResult(boost::optional<HostAddress> address) { + if (address) { + publicAddress = address; + SWIFT_LOG(debug) << "Public IP discovered as " << publicAddress.get().toString() << "." << std::endl; + } else { + SWIFT_LOG(debug) << "No public IP discoverable." << std::endl; + } +} + +void ConnectivityManager::natTraversalForwardPortResult(boost::optional<NATPortMapping> mapping) { + if (mapping) { + SWIFT_LOG(debug) << "Mapping port was successful." << std::endl; + } else { + SWIFT_LOG(debug) << "Mapping port has failed." << std::endl; + } +} + + +} diff --git a/Swiften/FileTransfer/ConnectivityManager.h b/Swiften/FileTransfer/ConnectivityManager.h new file mode 100644 index 0000000..c094c02 --- /dev/null +++ b/Swiften/FileTransfer/ConnectivityManager.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <set> + +#include <boost/optional.hpp> + +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/NATTraverser.h> +#include <Swiften/Network/NATTraversalForwardPortRequest.h> +#include <Swiften/Network/NATPortMapping.h> + +namespace Swift { + +class NATTraverser; + +class ConnectivityManager { +public: + ConnectivityManager(NATTraverser*); + ~ConnectivityManager(); +public: + void addListeningPort(int port); + void removeListeningPort(int port); + + std::vector<HostAddressPort> getHostAddressPorts() const; + std::vector<HostAddressPort> getAssistedHostAddressPorts() const; + +private: + void natTraversalGetPublicIPResult(boost::optional<HostAddress> address); + void natTraversalForwardPortResult(boost::optional<NATPortMapping> mapping); + +private: + NATTraverser* natTraversalWorker; + + std::set<int> ports; + boost::optional<HostAddress> publicAddress; +}; + +} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp new file mode 100644 index 0000000..4b205cb --- /dev/null +++ b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "DefaultLocalJingleTransportCandidateGenerator.h" + +#include <vector> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/ConnectivityManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> + +namespace Swift { + +DefaultLocalJingleTransportCandidateGenerator::DefaultLocalJingleTransportCandidateGenerator(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, JID& ownJID) : connectivityManager(connectivityManager), s5bRegistry(s5bRegistry), s5bProxy(s5bProxy), ownJID(ownJID) { +} + +DefaultLocalJingleTransportCandidateGenerator::~DefaultLocalJingleTransportCandidateGenerator() { +} + +void DefaultLocalJingleTransportCandidateGenerator::generateLocalTransportCandidates(JingleTransportPayload::ref transportPayload) { + if (boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload)) { + JingleTransportPayload::ref payL = boost::make_shared<JingleTransportPayload>(); + payL->setSessionID(transportPayload->getSessionID()); + onLocalTransportCandidatesGenerated(payL); + } + if (boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload)) { + JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); + payL->setSessionID(transportPayload->getSessionID()); + payL->setMode(JingleS5BTransportPayload::TCPMode); + + const unsigned long localPreference = 0; + + // get direct candidates + std::vector<HostAddressPort> directCandidates = connectivityManager->getHostAddressPorts(); + foreach(HostAddressPort addressPort, directCandidates) { + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::DirectType; + candidate.jid = ownJID; + candidate.hostPort = addressPort; + candidate.priority = 65536 * 126 + localPreference; + candidate.cid = idGenerator.generateID(); + payL->addCandidate(candidate); + } + + // get assissted candidates + std::vector<HostAddressPort> assisstedCandidates = connectivityManager->getAssistedHostAddressPorts(); + foreach(HostAddressPort addressPort, assisstedCandidates) { + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::AssistedType; + candidate.jid = ownJID; + candidate.hostPort = addressPort; + candidate.priority = 65536 * 120 + localPreference; + candidate.cid = idGenerator.generateID(); + payL->addCandidate(candidate); + } + + // get proxy candidates + std::vector<S5BProxyRequest::ref> proxyCandidates = s5bProxy->getS5BProxies(); + foreach(S5BProxyRequest::ref proxy, proxyCandidates) { + if (proxy->getStreamHost()) { // FIXME: Added this test, because there were cases where this wasn't initialized. Investigate this. (Remko) + JingleS5BTransportPayload::Candidate candidate; + candidate.type = JingleS5BTransportPayload::Candidate::ProxyType; + candidate.jid = (*proxy->getStreamHost()).jid; + candidate.hostPort = (*proxy->getStreamHost()).addressPort; + candidate.priority = 65536 * 10 + localPreference; + candidate.cid = idGenerator.generateID(); + payL->addCandidate(candidate); + } + } + + onLocalTransportCandidatesGenerated(payL); + } + +} + +bool DefaultLocalJingleTransportCandidateGenerator::isActualCandidate(JingleTransportPayload::ref transportPayload) { + if (!transportPayload.get()) return false; + return false; +} + +int DefaultLocalJingleTransportCandidateGenerator::getPriority(JingleTransportPayload::ref /* transportPayload */) { + return 0; +} + +JingleTransport::ref DefaultLocalJingleTransportCandidateGenerator::selectTransport(JingleTransportPayload::ref /* transportPayload */) { + return JingleTransport::ref(); +} + +} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h new file mode 100644 index 0000000..7d45491 --- /dev/null +++ b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> + +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + +class SOCKS5BytestreamRegistry; +class SOCKS5BytestreamProxy; +class ConnectivityManager; + +class DefaultLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { +public: + DefaultLocalJingleTransportCandidateGenerator(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, JID& ownJID); + virtual ~DefaultLocalJingleTransportCandidateGenerator(); + + virtual void generateLocalTransportCandidates(JingleTransportPayload::ref); + + virtual bool isActualCandidate(JingleTransportPayload::ref); + virtual int getPriority(JingleTransportPayload::ref); + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref); + +private: + IDGenerator idGenerator; + ConnectivityManager* connectivityManager; + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamProxy* s5bProxy; + JID ownJID; +}; + +} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp new file mode 100644 index 0000000..ed0386e --- /dev/null +++ b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "DefaultLocalJingleTransportCandidateGeneratorFactory.h" + +#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGenerator.h> +#include <Swiften/Base/Log.h> + +namespace Swift { + +DefaultLocalJingleTransportCandidateGeneratorFactory::DefaultLocalJingleTransportCandidateGeneratorFactory(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, const JID& ownJID) : connectivityManager(connectivityManager), s5bRegistry(s5bRegistry), s5bProxy(s5bProxy), ownJID(ownJID) { +} + +DefaultLocalJingleTransportCandidateGeneratorFactory::~DefaultLocalJingleTransportCandidateGeneratorFactory() { +} + +LocalJingleTransportCandidateGenerator* DefaultLocalJingleTransportCandidateGeneratorFactory::createCandidateGenerator() { + return new DefaultLocalJingleTransportCandidateGenerator(connectivityManager, s5bRegistry, s5bProxy, ownJID); +} + + +} diff --git a/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h new file mode 100644 index 0000000..511d0a1 --- /dev/null +++ b/Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> + +#include <Swiften/JID/JID.h> + +namespace Swift { + +class ConnectivityManager; +class SOCKS5BytestreamRegistry; +class SOCKS5BytestreamProxy; + +class DefaultLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory{ +public: + DefaultLocalJingleTransportCandidateGeneratorFactory(ConnectivityManager* connectivityManager, SOCKS5BytestreamRegistry* s5bRegistry, SOCKS5BytestreamProxy* s5bProxy, const JID& ownJID); + virtual ~DefaultLocalJingleTransportCandidateGeneratorFactory(); + + LocalJingleTransportCandidateGenerator* createCandidateGenerator(); + +private: + ConnectivityManager* connectivityManager; + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamProxy* s5bProxy; + JID ownJID; +}; + +} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp new file mode 100644 index 0000000..32b4df8 --- /dev/null +++ b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "DefaultRemoteJingleTransportCandidateSelector.h" + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> + +namespace Swift { + +DefaultRemoteJingleTransportCandidateSelector::DefaultRemoteJingleTransportCandidateSelector(ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : connectionFactory(connectionFactory), timerFactory(timerFactory) { +} + +DefaultRemoteJingleTransportCandidateSelector::~DefaultRemoteJingleTransportCandidateSelector() { +} + +void DefaultRemoteJingleTransportCandidateSelector::addRemoteTransportCandidates(JingleTransportPayload::ref transportPayload) { + JingleS5BTransportPayload::ref s5bPayload; + transportSID = transportPayload->getSessionID(); + if ((s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload))) { + foreach(JingleS5BTransportPayload::Candidate c, s5bPayload->getCandidates()) { + candidates.push(c); + } + } +} + +void DefaultRemoteJingleTransportCandidateSelector::selectCandidate() { + tryNextCandidate(true); +} + +void DefaultRemoteJingleTransportCandidateSelector::tryNextCandidate(bool error) { + if (error) { + if (s5bSession) { + SWIFT_LOG(debug) << "failed to connect" << std::endl; + } + if (candidates.empty()) { + // failed to connect to any of the candidates + // issue an error + SWIFT_LOG(debug) << "out of candidates )=" << std::endl; + JingleS5BTransportPayload::ref failed = boost::make_shared<JingleS5BTransportPayload>(); + failed->setCandidateError(true); + failed->setSessionID(transportSID); + onRemoteTransportCandidateSelectFinished(failed); + } else { + lastCandidate = candidates.top(); + // only try direct or assisted for now + if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType || + lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType || lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType ) { + // create connection + connection = connectionFactory->createConnection(); + s5bSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, lastCandidate.hostPort, SOCKS5BytestreamRegistry::getHostname(transportSID, requester, target), timerFactory); + + // bind onReady to this method + s5bSession->onSessionReady.connect(boost::bind(&DefaultRemoteJingleTransportCandidateSelector::tryNextCandidate, this, _1)); + + std::string candidateType; + if (lastCandidate.type == JingleS5BTransportPayload::Candidate::DirectType) { + candidateType = "direct"; + } else if (lastCandidate.type == JingleS5BTransportPayload::Candidate::AssistedType) { + candidateType = "assisted"; + } else if (lastCandidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { + candidateType = "proxy"; + } + + // initiate connect + SWIFT_LOG(debug) << "try to connect to candidate of type " << candidateType << " : " << lastCandidate.hostPort.toString() << std::endl; + s5bSession->start(); + + // that's it. we're gonna be called back + candidates.pop(); + } else { + s5bSession.reset(); + candidates.pop(); + tryNextCandidate(true); + } + } + } else { + // we have a working connection, hooray + JingleS5BTransportPayload::ref success = boost::make_shared<JingleS5BTransportPayload>(); + success->setCandidateUsed(lastCandidate.cid); + success->setSessionID(transportSID); + onRemoteTransportCandidateSelectFinished(success); + } +} + +void DefaultRemoteJingleTransportCandidateSelector::setMinimumPriority(int priority) { + SWIFT_LOG(debug) << "priority: " << priority << std::endl; +} + +void DefaultRemoteJingleTransportCandidateSelector::setRequesterTargtet(const JID& requester, const JID& target) { + this->requester = requester; + this->target = target; +} + +SOCKS5BytestreamClientSession::ref DefaultRemoteJingleTransportCandidateSelector::getS5BSession() { + return s5bSession; +} + +bool DefaultRemoteJingleTransportCandidateSelector::isActualCandidate(JingleTransportPayload::ref /* transportPayload */) { + return false; +} + +int DefaultRemoteJingleTransportCandidateSelector::getPriority(JingleTransportPayload::ref /* transportPayload */) { + return 0; +} + +JingleTransport::ref DefaultRemoteJingleTransportCandidateSelector::selectTransport(JingleTransportPayload::ref /* transportPayload */) { + return JingleTransport::ref(); +} + +} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h new file mode 100644 index 0000000..255acd9 --- /dev/null +++ b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <queue> +#include <vector> + +#include <boost/shared_ptr.hpp> + +#include <Swiften/JID/JID.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> + + +namespace Swift { + +class ConnectionFactory; +class TimerFactory; + +class DefaultRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { +public: + DefaultRemoteJingleTransportCandidateSelector(ConnectionFactory*, TimerFactory*); + virtual ~DefaultRemoteJingleTransportCandidateSelector(); + + virtual void addRemoteTransportCandidates(JingleTransportPayload::ref); + virtual void selectCandidate(); + virtual void setMinimumPriority(int); + void setRequesterTargtet(const JID& requester, const JID& target); + virtual SOCKS5BytestreamClientSession::ref getS5BSession(); + + virtual bool isActualCandidate(JingleTransportPayload::ref); + virtual int getPriority(JingleTransportPayload::ref); + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref); + +private: + void tryNextCandidate(bool error); + +private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; + + std::priority_queue<JingleS5BTransportPayload::Candidate, std::vector<JingleS5BTransportPayload::Candidate>, JingleS5BTransportPayload::CompareCandidate> candidates; + + std::string transportSID; + boost::shared_ptr<Connection> connection; + boost::shared_ptr<SOCKS5BytestreamClientSession> s5bSession; + JingleS5BTransportPayload::Candidate lastCandidate; + JID requester; + JID target; +}; + +} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp new file mode 100644 index 0000000..8ebbf46 --- /dev/null +++ b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "DefaultRemoteJingleTransportCandidateSelectorFactory.h" + +#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelector.h> + +#include <Swiften/Base/Log.h> + +namespace Swift { + +DefaultRemoteJingleTransportCandidateSelectorFactory::DefaultRemoteJingleTransportCandidateSelectorFactory(ConnectionFactory* connectionFactory, TimerFactory* timerFactory) : connectionFactory(connectionFactory), timerFactory(timerFactory) { +} + +DefaultRemoteJingleTransportCandidateSelectorFactory::~DefaultRemoteJingleTransportCandidateSelectorFactory() { +} + +RemoteJingleTransportCandidateSelector* DefaultRemoteJingleTransportCandidateSelectorFactory::createCandidateSelector() { + return new DefaultRemoteJingleTransportCandidateSelector(connectionFactory, timerFactory); +} + +} diff --git a/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h new file mode 100644 index 0000000..ca29e1f --- /dev/null +++ b/Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> + +namespace Swift { + +class ConnectionFactory; +class TimerFactory; + +class DefaultRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { +public: + DefaultRemoteJingleTransportCandidateSelectorFactory(ConnectionFactory*, TimerFactory*); + virtual ~DefaultRemoteJingleTransportCandidateSelectorFactory(); + + RemoteJingleTransportCandidateSelector* createCandidateSelector(); + +private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; +}; + +} diff --git a/Swiften/FileTransfer/FileReadBytestream.cpp b/Swiften/FileTransfer/FileReadBytestream.cpp index c08747b..a8946a0 100644 --- a/Swiften/FileTransfer/FileReadBytestream.cpp +++ b/Swiften/FileTransfer/FileReadBytestream.cpp @@ -6,8 +6,10 @@ #include <boost/filesystem/fstream.hpp> #include <cassert> +#include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/FileTransfer/FileReadBytestream.h" +#include <Swiften/FileTransfer/FileReadBytestream.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { @@ -21,15 +23,16 @@ FileReadBytestream::~FileReadBytestream() { } } -ByteArray FileReadBytestream::read(size_t size) { +boost::shared_ptr<ByteArray> FileReadBytestream::read(size_t size) { if (!stream) { stream = new boost::filesystem::ifstream(file, std::ios_base::in|std::ios_base::binary); } - ByteArray result; - result.resize(size); + boost::shared_ptr<ByteArray> result = boost::make_shared<ByteArray>(); + result->resize(size); assert(stream->good()); - stream->read(reinterpret_cast<char*>(result.getData()), size); - result.resize(stream->gcount()); + stream->read(reinterpret_cast<char*>(vecptr(*result)), size); + result->resize(stream->gcount()); + onRead(*result); return result; } diff --git a/Swiften/FileTransfer/FileReadBytestream.h b/Swiften/FileTransfer/FileReadBytestream.h index 055e194..e9db2a4 100644 --- a/Swiften/FileTransfer/FileReadBytestream.h +++ b/Swiften/FileTransfer/FileReadBytestream.h @@ -6,10 +6,10 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/filesystem/fstream.hpp> -#include "Swiften/FileTransfer/ReadBytestream.h" +#include <Swiften/FileTransfer/ReadBytestream.h> namespace Swift { class FileReadBytestream : public ReadBytestream { @@ -17,7 +17,7 @@ namespace Swift { FileReadBytestream(const boost::filesystem::path& file); ~FileReadBytestream(); - virtual ByteArray read(size_t size) ; + virtual boost::shared_ptr< std::vector<unsigned char> > read(size_t size); virtual bool isFinished() const; private: diff --git a/Swiften/FileTransfer/FileTransfer.h b/Swiften/FileTransfer/FileTransfer.h new file mode 100644 index 0000000..336c51c --- /dev/null +++ b/Swiften/FileTransfer/FileTransfer.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/cstdint.hpp> +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/FileTransferError.h> + +namespace Swift { + +class FileTransfer { +public: + struct State { + enum FTState { + Canceled, + Failed, + Finished, + Negotiating, + Transferring, + WaitingForStart, + WaitingForAccept, + }; + + FTState state; + std::string message; + + State(FTState state) : state(state), message("") {} + State(FTState state, std::string message) : state(state), message(message) {} + }; + +public: + typedef boost::shared_ptr<FileTransfer> ref; + +public: + boost::uintmax_t fileSizeInBytes; + std::string filename; + std::string algo; + std::string hash; + +public: + virtual void cancel() = 0; + +public: + boost::signal<void (int /* proccessedBytes */)> onProcessedBytes; + boost::signal<void (State)> onStateChange; + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + +public: + virtual ~FileTransfer() {} +}; + +} diff --git a/Swiften/FileTransfer/FileTransferManager.cpp b/Swiften/FileTransfer/FileTransferManager.cpp new file mode 100644 index 0000000..69be852 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferManager.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/FileTransfer/FileTransferManager.h> + +namespace Swift { + +FileTransferManager::~FileTransferManager() { +} + +} diff --git a/Swiften/FileTransfer/FileTransferManager.h b/Swiften/FileTransfer/FileTransferManager.h new file mode 100644 index 0000000..d59f029 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferManager.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> +#include <boost/filesystem.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> +#include <Swiften/FileTransfer/IncomingFileTransfer.h> + +namespace Swift { + class ReadBytestream; + class S5BProxyRequest; + + class FileTransferManager { + public: + virtual ~FileTransferManager(); + + virtual void startListeningOnPort(int port) = 0; + + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream) = 0; + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream) = 0; + + boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer; + }; +} diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp new file mode 100644 index 0000000..83320b2 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/FileTransfer/FileTransferManagerImpl.h> + +#include <boost/bind.hpp> +#include <boost/cstdint.hpp> + +#include <Swiften/Base/foreach.h> +#include "Swiften/Disco/EntityCapsProvider.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> +#include <Swiften/FileTransfer/ConnectivityManager.h> +#include <Swiften/FileTransfer/OutgoingFileTransferManager.h> +#include <Swiften/FileTransfer/IncomingFileTransferManager.h> +#include <Swiften/FileTransfer/DefaultLocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/DefaultRemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/Presence/PresenceOracle.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/ConnectionServerFactory.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/NATTraverser.h> + +namespace Swift { + +FileTransferManagerImpl::FileTransferManagerImpl(const JID& ownFullJID, JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, PresenceOracle* presOracle, ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, NATTraverser* natTraverser) : ownJID(ownFullJID), jingleSM(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), presenceOracle(presOracle), timerFactory(timerFactory), connectionFactory(connectionFactory), connectionServerFactory(connectionServerFactory), natTraverser(natTraverser), bytestreamServer(NULL), s5bProxyFinder(NULL) { + assert(!ownFullJID.isBare()); + + connectivityManager = new ConnectivityManager(natTraverser); + bytestreamRegistry = new SOCKS5BytestreamRegistry(); + bytestreamProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + + localCandidateGeneratorFactory = new DefaultLocalJingleTransportCandidateGeneratorFactory(connectivityManager, bytestreamRegistry, bytestreamProxy, ownFullJID); + remoteCandidateSelectorFactory = new DefaultRemoteJingleTransportCandidateSelectorFactory(connectionFactory, timerFactory); + outgoingFTManager = new OutgoingFileTransferManager(jingleSM, iqRouter, capsProvider, remoteCandidateSelectorFactory, localCandidateGeneratorFactory, bytestreamRegistry, bytestreamProxy); + incomingFTManager = new IncomingFileTransferManager(jingleSM, iqRouter, remoteCandidateSelectorFactory, localCandidateGeneratorFactory, bytestreamRegistry, bytestreamProxy, timerFactory); + incomingFTManager->onIncomingFileTransfer.connect(onIncomingFileTransfer); +} + +FileTransferManagerImpl::~FileTransferManagerImpl() { + if (s5bProxyFinder) { + s5bProxyFinder->stop(); + delete s5bProxyFinder; + } + if (bytestreamServer) { + bytestreamServer->stop(); + delete bytestreamServer; + } + delete incomingFTManager; + delete outgoingFTManager; + delete remoteCandidateSelectorFactory; + delete localCandidateGeneratorFactory; + delete connectivityManager; +} + +void FileTransferManagerImpl::startListeningOnPort(int port) { + // TODO: create a server for each interface we're on + SWIFT_LOG(debug) << "Start listening on port " << port << " and hope it's not in use." << std::endl; + boost::shared_ptr<ConnectionServer> server = connectionServerFactory->createConnectionServer(HostAddress("0.0.0.0"), port); + server->start(); + bytestreamServer = new SOCKS5BytestreamServer(server, bytestreamRegistry); + bytestreamServer->start(); + connectivityManager->addListeningPort(port); + + s5bProxyFinder = new SOCKS5BytestreamProxyFinder(ownJID.getDomain(), iqRouter); + s5bProxyFinder->onProxyFound.connect(boost::bind(&FileTransferManagerImpl::addS5BProxy, this, _1)); + s5bProxyFinder->start(); +} + +void FileTransferManagerImpl::addS5BProxy(S5BProxyRequest::ref proxy) { + bytestreamProxy->addS5BProxy(proxy); +} + +boost::optional<JID> FileTransferManagerImpl::highestPriorityJIDSupportingFileTransfer(const JID& bareJID) { + JID fullReceipientJID; + int priority = INT_MIN; + + //getAllPresence(bareJID) gives you all presences for the bare JID (i.e. all resources) Remko Tronçon @ 11:11 + std::vector<Presence::ref> presences = presenceOracle->getAllPresence(bareJID); + + //iterate over them + foreach(Presence::ref pres, presences) { + if (pres->getPriority() > priority) { + // look up caps from the jid + DiscoInfo::ref info = capsProvider->getCaps(pres->getFrom()); + if (info && info->hasFeature(DiscoInfo::JingleFeature) && info->hasFeature(DiscoInfo::JingleFTFeature) && (info->hasFeature(DiscoInfo::JingleTransportsIBBFeature) || info->hasFeature(DiscoInfo::JingleTransportsS5BFeature))) { + + priority = pres->getPriority(); + fullReceipientJID = pres->getFrom(); + } + } + } + + return fullReceipientJID.isValid() ? boost::optional<JID>(fullReceipientJID) : boost::optional<JID>(); +} + +OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream) { + std::string filename = filepath.filename(); + boost::uintmax_t sizeInBytes = boost::filesystem::file_size(filepath); + boost::posix_time::ptime lastModified = boost::posix_time::from_time_t(boost::filesystem::last_write_time(filepath)); + return createOutgoingFileTransfer(to, filename, description, sizeInBytes, lastModified, bytestream); +} + +OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream) { + StreamInitiationFileInfo fileInfo; + fileInfo.setDate(lastModified); + fileInfo.setSize(sizeInBytes); + fileInfo.setName(filename); + fileInfo.setDescription(description); + + JID receipient = to; + + if(receipient.isBare()) { + boost::optional<JID> fullJID = highestPriorityJIDSupportingFileTransfer(receipient); + if (fullJID.is_initialized()) { + receipient = fullJID.get(); + } else { + return OutgoingFileTransfer::ref(); + } + } + + return outgoingFTManager->createOutgoingFileTransfer(ownJID, receipient, bytestream, fileInfo); +} + +} diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.h b/Swiften/FileTransfer/FileTransferManagerImpl.h new file mode 100644 index 0000000..248b437 --- /dev/null +++ b/Swiften/FileTransfer/FileTransferManagerImpl.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <string> + +#include <boost/filesystem.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <boost/optional.hpp> + +#include <Swiften/FileTransfer/FileTransferManager.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> +#include <Swiften/FileTransfer/IncomingFileTransfer.h> +#include <Swiften/Elements/S5BProxyRequest.h> + +namespace Swift { + class Client; + class ConnectionFactory; + class ConnectionServerFactory; + class ConnectivityManager; + class EntityCapsProvider; + class IQRouter; + class IncomingFileTransferManager; + class JingleSessionManager; + class LocalJingleTransportCandidateGeneratorFactory; + class OutgoingFileTransferManager; + class NATTraverser; + class PresenceOracle; + class ReadBytestream; + class RemoteJingleTransportCandidateSelectorFactory; + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamServer; + class SOCKS5BytestreamProxy; + class TimerFactory; + class SOCKS5BytestreamProxyFinder; + + class FileTransferManagerImpl : public FileTransferManager { + public: + FileTransferManagerImpl(const JID& ownFullJID, JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, PresenceOracle* presOracle, ConnectionFactory* connectionFactory, ConnectionServerFactory* connectionServerFactory, TimerFactory* timerFactory, NATTraverser* natTraverser); + ~FileTransferManagerImpl(); + + void startListeningOnPort(int port); + void addS5BProxy(S5BProxyRequest::ref proxy); + + OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const boost::filesystem::path& filepath, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream); + OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID& to, const std::string& filename, const std::string& description, const boost::uintmax_t sizeInBytes, const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream); + + private: + boost::optional<JID> highestPriorityJIDSupportingFileTransfer(const JID& bareJID); + + private: + JID ownJID; + + OutgoingFileTransferManager* outgoingFTManager; + IncomingFileTransferManager* incomingFTManager; + RemoteJingleTransportCandidateSelectorFactory* remoteCandidateSelectorFactory; + LocalJingleTransportCandidateGeneratorFactory* localCandidateGeneratorFactory; + JingleSessionManager* jingleSM; + IQRouter* iqRouter; + EntityCapsProvider* capsProvider; + PresenceOracle* presenceOracle; + + TimerFactory* timerFactory; + ConnectionFactory* connectionFactory; + ConnectionServerFactory* connectionServerFactory; + NATTraverser* natTraverser; + SOCKS5BytestreamRegistry* bytestreamRegistry; + SOCKS5BytestreamServer* bytestreamServer; + SOCKS5BytestreamProxy* bytestreamProxy; + ConnectivityManager* connectivityManager; + SOCKS5BytestreamProxyFinder* s5bProxyFinder; + }; + +} diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp index 4d29bd1..6a22c6a 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.cpp +++ b/Swiften/FileTransfer/FileWriteBytestream.cpp @@ -7,7 +7,7 @@ #include <boost/filesystem/fstream.hpp> #include <cassert> -#include "Swiften/FileTransfer/FileWriteBytestream.h" +#include <Swiften/FileTransfer/FileWriteBytestream.h> namespace Swift { @@ -21,12 +21,20 @@ FileWriteBytestream::~FileWriteBytestream() { } } -void FileWriteBytestream::write(const ByteArray& data) { +void FileWriteBytestream::write(const std::vector<unsigned char>& data) { if (!stream) { stream = new boost::filesystem::ofstream(file, std::ios_base::out|std::ios_base::binary); } assert(stream->good()); - stream->write(reinterpret_cast<const char*>(data.getData()), data.getSize()); + stream->write(reinterpret_cast<const char*>(&data[0]), data.size()); + onWrite(data); +} + +void FileWriteBytestream::close() { + if (stream) { + stream->close(); + stream = NULL; + } } } diff --git a/Swiften/FileTransfer/FileWriteBytestream.h b/Swiften/FileTransfer/FileWriteBytestream.h index c6f7b39..82c4a65 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.h +++ b/Swiften/FileTransfer/FileWriteBytestream.h @@ -6,10 +6,10 @@ #pragma once -#include <boost/filesystem.hpp> +#include <boost/filesystem/path.hpp> #include <boost/filesystem/fstream.hpp> -#include "Swiften/FileTransfer/WriteBytestream.h" +#include <Swiften/FileTransfer/WriteBytestream.h> namespace Swift { class FileWriteBytestream : public WriteBytestream { @@ -17,7 +17,8 @@ namespace Swift { FileWriteBytestream(const boost::filesystem::path& file); ~FileWriteBytestream(); - virtual void write(const ByteArray&); + virtual void write(const std::vector<unsigned char>&); + void close(); private: boost::filesystem::path file; diff --git a/Swiften/FileTransfer/IBBReceiveSession.cpp b/Swiften/FileTransfer/IBBReceiveSession.cpp index 5c90757..1a2bb3a 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.cpp +++ b/Swiften/FileTransfer/IBBReceiveSession.cpp @@ -4,31 +4,107 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/IBBReceiveSession.h" +#include <Swiften/FileTransfer/IBBReceiveSession.h> #include <boost/bind.hpp> -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/FileTransfer/IBBRequest.h" -#include "Swiften/FileTransfer/BytestreamException.h" +#include <Swiften/Base/Log.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/FileTransfer/IBBRequest.h> +#include <Swiften/FileTransfer/BytestreamException.h> +#include <Swiften/Queries/SetResponder.h> + +#include <cassert> namespace Swift { -IBBReceiveSession::IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router) : SetResponder<IBB>(router), id(id), from(from), size(size), bytestream(bytestream), router(router), sequenceNumber(0), active(false), receivedSize(0) { +class IBBReceiveSession::IBBResponder : public SetResponder<IBB> { + public: + IBBResponder(IBBReceiveSession* session, IQRouter* router) : SetResponder<IBB>(router), session(session), sequenceNumber(0), receivedSize(0) { + } + + virtual bool handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) { + if (from == session->from && ibb->getStreamID() == session->id) { + if (ibb->getAction() == IBB::Data) { + if (sequenceNumber == ibb->getSequenceNumber()) { + session->onDataReceived(ibb->getData()); + receivedSize += ibb->getData().size(); + sequenceNumber++; + sendResponse(from, id, IBB::ref()); + if (receivedSize >= session->size) { + if (receivedSize > session->size) { + std::cerr << "Warning: Received more data than expected" << std::endl; + } + session->finish(boost::optional<FileTransferError>()); + } + } + else { + SWIFT_LOG(warning) << "Received data out of order" << std::endl; + sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel); + session->finish(FileTransferError(FileTransferError::ClosedError)); + } + } + else if (ibb->getAction() == IBB::Open) { + SWIFT_LOG(debug) << "IBB open received" << std::endl; + sendResponse(from, id, IBB::ref()); + } + else if (ibb->getAction() == IBB::Close) { + SWIFT_LOG(debug) << "IBB close received" << std::endl; + sendResponse(from, id, IBB::ref()); + session->finish(FileTransferError(FileTransferError::ClosedError)); + } + return true; + } + SWIFT_LOG(debug) << "wrong from/sessionID: " << from << " == " << session->from << " / " <<ibb->getStreamID() << " == " << session->id << std::endl; + return false; + } + + private: + IBBReceiveSession* session; + int sequenceNumber; + size_t receivedSize; +}; + + +IBBReceiveSession::IBBReceiveSession( + const std::string& id, + const JID& from, + const JID& to, + size_t size, + IQRouter* router) : + id(id), + from(from), + to(to), + size(size), + router(router), + active(false) { + assert(!id.empty()); + assert(from.isValid()); + responder = new IBBResponder(this, router); } IBBReceiveSession::~IBBReceiveSession() { + if (active) { + SWIFT_LOG(warning) << "Session still active" << std::endl; + } + delete responder; } void IBBReceiveSession::start() { + SWIFT_LOG(debug) << "receive session started" << std::endl; active = true; + responder->start(); } void IBBReceiveSession::stop() { - if (active && router->isAvailable()) { - IBBRequest::create(from, IBB::createIBBClose(id), router)->send(); + SWIFT_LOG(debug) << "receive session stopped" << std::endl; + responder->stop(); + if (active) { + if (router->isAvailable()) { + IBBRequest::create(to, from, IBB::createIBBClose(id), router)->send(); + } + finish(boost::optional<FileTransferError>()); } - finish(boost::optional<FileTransferError>()); } void IBBReceiveSession::finish(boost::optional<FileTransferError> error) { @@ -36,34 +112,4 @@ void IBBReceiveSession::finish(boost::optional<FileTransferError> error) { onFinished(error); } -bool IBBReceiveSession::handleSetRequest(const JID& from, const JID&, const std::string& id, IBB::ref ibb) { - if (from == this->from && ibb->getStreamID() == id) { - if (ibb->getAction() == IBB::Data) { - if (sequenceNumber == ibb->getSequenceNumber()) { - bytestream->write(ibb->getData()); - receivedSize += ibb->getData().getSize(); - if (receivedSize >= size) { - if (receivedSize > size) { - std::cerr << "Warning: Received more data than expected" << std::endl; - } - finish(boost::optional<FileTransferError>()); - } - } - else { - sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel); - finish(FileTransferError(FileTransferError::ClosedError)); - } - } - else if (ibb->getAction() == IBB::Open) { - sendResponse(from, id, IBB::ref()); - } - else if (ibb->getAction() == IBB::Close) { - sendResponse(from, id, IBB::ref()); - finish(FileTransferError(FileTransferError::ClosedError)); - } - return true; - } - return false; -} - } diff --git a/Swiften/FileTransfer/IBBReceiveSession.h b/Swiften/FileTransfer/IBBReceiveSession.h index 6d936de..d1c47bf 100644 --- a/Swiften/FileTransfer/IBBReceiveSession.h +++ b/Swiften/FileTransfer/IBBReceiveSession.h @@ -7,27 +7,39 @@ #pragma once #include <boost/shared_ptr.hpp> -#include <boost/optional.hpp> +#include <boost/optional/optional_fwd.hpp> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/FileTransfer/WriteBytestream.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/IBB.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/FileTransfer/FileTransferError.h" -#include "Swiften/Queries/SetResponder.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/IBB.h> +#include <Swiften/FileTransfer/FileTransferError.h> namespace Swift { class IQRouter; - class IBBReceiveSession : public SetResponder<IBB> { + class IBBReceiveSession { public: - IBBReceiveSession(const std::string& id, const JID& from, size_t size, WriteBytestream::ref bytestream, IQRouter* router); + IBBReceiveSession( + const std::string& id, + const JID& from, + const JID& to, + size_t size, + IQRouter* router); ~IBBReceiveSession(); void start(); void stop(); + const JID& getSender() const { + return from; + } + + const JID& getReceiver() const { + return to; + } + + boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; boost::signal<void (boost::optional<FileTransferError>)> onFinished; private: @@ -35,13 +47,15 @@ namespace Swift { void finish(boost::optional<FileTransferError>); private: + class IBBResponder; + friend class IBBResponder; + std::string id; JID from; + JID to; size_t size; - WriteBytestream::ref bytestream; IQRouter* router; - int sequenceNumber; + IBBResponder* responder; bool active; - size_t receivedSize; }; } diff --git a/Swiften/FileTransfer/IBBRequest.h b/Swiften/FileTransfer/IBBRequest.h index f104277..58be173 100644 --- a/Swiften/FileTransfer/IBBRequest.h +++ b/Swiften/FileTransfer/IBBRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/IBB.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/IBB.h> namespace Swift { @@ -15,12 +15,12 @@ namespace Swift { public: typedef boost::shared_ptr<IBBRequest> ref; - static ref create(const JID& jid, boost::shared_ptr<IBB> payload, IQRouter* router) { - return ref(new IBBRequest(jid, payload, router)); + static ref create(const JID& from, const JID& to, boost::shared_ptr<IBB> payload, IQRouter* router) { + return ref(new IBBRequest(from, to, payload, router)); } private: - IBBRequest(const JID& jid, boost::shared_ptr<IBB> payload, IQRouter* router) : GenericRequest<IBB>(IQ::Set, jid, payload, router) { + IBBRequest(const JID& from, const JID& to, boost::shared_ptr<IBB> payload, IQRouter* router) : GenericRequest<IBB>(IQ::Set, from, to, payload, router) { } }; } diff --git a/Swiften/FileTransfer/IBBSendSession.cpp b/Swiften/FileTransfer/IBBSendSession.cpp index 0fb47d3..c24cc0a 100644 --- a/Swiften/FileTransfer/IBBSendSession.cpp +++ b/Swiften/FileTransfer/IBBSendSession.cpp @@ -4,24 +4,27 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/IBBSendSession.h" +#include <Swiften/FileTransfer/IBBSendSession.h> #include <boost/bind.hpp> -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/FileTransfer/IBBRequest.h" -#include "Swiften/FileTransfer/BytestreamException.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/FileTransfer/IBBRequest.h> +#include <Swiften/FileTransfer/BytestreamException.h> namespace Swift { -IBBSendSession::IBBSendSession(const std::string& id, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router) : id(id), to(to), bytestream(bytestream), router(router), blockSize(4096), sequenceNumber(0), active(false) { +IBBSendSession::IBBSendSession(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router) : id(id), from(from), to(to), bytestream(bytestream), router(router), blockSize(4096), sequenceNumber(0), active(false), waitingForData(false) { + bytestream->onDataAvailable.connect(boost::bind(&IBBSendSession::handleDataAvailable, this)); } IBBSendSession::~IBBSendSession() { + bytestream->onDataAvailable.disconnect(boost::bind(&IBBSendSession::handleDataAvailable, this)); } void IBBSendSession::start() { - IBBRequest::ref request = IBBRequest::create(to, IBB::createIBBOpen(id, blockSize), router); + IBBRequest::ref request = IBBRequest::create(from, to, IBB::createIBBOpen(id, blockSize), router); request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); active = true; request->send(); @@ -29,24 +32,15 @@ void IBBSendSession::start() { void IBBSendSession::stop() { if (active && router->isAvailable()) { - IBBRequest::create(to, IBB::createIBBClose(id), router)->send(); + IBBRequest::create(from, to, IBB::createIBBClose(id), router)->send(); } finish(boost::optional<FileTransferError>()); } void IBBSendSession::handleIBBResponse(IBB::ref, ErrorPayload::ref error) { - if (!error) { + if (!error && active) { if (!bytestream->isFinished()) { - try { - ByteArray data = bytestream->read(blockSize); - IBBRequest::ref request = IBBRequest::create(to, IBB::createIBBData(id, sequenceNumber, data), router); - sequenceNumber++; - request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); - request->send(); - } - catch (const BytestreamException& e) { - finish(FileTransferError(FileTransferError::ReadError)); - } + sendMoreData(); } else { finish(boost::optional<FileTransferError>()); @@ -57,9 +51,35 @@ void IBBSendSession::handleIBBResponse(IBB::ref, ErrorPayload::ref error) { } } +void IBBSendSession::sendMoreData() { + try { + boost::shared_ptr<ByteArray> data = bytestream->read(blockSize); + if (!data->empty()) { + waitingForData = false; + IBBRequest::ref request = IBBRequest::create(from, to, IBB::createIBBData(id, sequenceNumber, *data), router); + sequenceNumber++; + request->onResponse.connect(boost::bind(&IBBSendSession::handleIBBResponse, this, _1, _2)); + request->send(); + onBytesSent(data->size()); + } + else { + waitingForData = true; + } + } + catch (const BytestreamException&) { + finish(FileTransferError(FileTransferError::ReadError)); + } +} + void IBBSendSession::finish(boost::optional<FileTransferError> error) { active = false; onFinished(error); } +void IBBSendSession::handleDataAvailable() { + if (waitingForData) { + sendMoreData(); + } +} + } diff --git a/Swiften/FileTransfer/IBBSendSession.h b/Swiften/FileTransfer/IBBSendSession.h index bef7bec..abd217b 100644 --- a/Swiften/FileTransfer/IBBSendSession.h +++ b/Swiften/FileTransfer/IBBSendSession.h @@ -9,41 +9,54 @@ #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/FileTransfer/ReadBytestream.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/IBB.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/FileTransfer/FileTransferError.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/IBB.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/FileTransfer/FileTransferError.h> namespace Swift { class IQRouter; class IBBSendSession { public: - IBBSendSession(const std::string& id, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router); + IBBSendSession(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* router); ~IBBSendSession(); void start(); void stop(); + const JID& getSender() const { + return from; + } + + const JID& getReceiver() const { + return to; + } + void setBlockSize(int blockSize) { this->blockSize = blockSize; } boost::signal<void (boost::optional<FileTransferError>)> onFinished; + boost::signal<void (int)> onBytesSent; private: void handleIBBResponse(IBB::ref, ErrorPayload::ref); void finish(boost::optional<FileTransferError>); + void sendMoreData(); + void handleDataAvailable(); private: std::string id; + JID from; JID to; boost::shared_ptr<ReadBytestream> bytestream; IQRouter* router; int blockSize; int sequenceNumber; bool active; + bool waitingForData; }; } diff --git a/Swiften/FileTransfer/IncomingFileTransfer.cpp b/Swiften/FileTransfer/IncomingFileTransfer.cpp index 238ccce..7c97e4d 100644 --- a/Swiften/FileTransfer/IncomingFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingFileTransfer.cpp @@ -4,20 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/IncomingFileTransfer.h" +#include <Swiften/FileTransfer/IncomingFileTransfer.h> namespace Swift { IncomingFileTransfer::~IncomingFileTransfer() { - -} - -/*void IncomingFileTransfer::accept(WriteBytestream::ref) { - } -void IncomingFileTransfer::stop() { - -}*/ - } diff --git a/Swiften/FileTransfer/IncomingFileTransfer.h b/Swiften/FileTransfer/IncomingFileTransfer.h index 4286ef0..5b53d54 100644 --- a/Swiften/FileTransfer/IncomingFileTransfer.h +++ b/Swiften/FileTransfer/IncomingFileTransfer.h @@ -8,16 +8,21 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/FileTransfer/WriteBytestream.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/FileTransfer.h> +#include <Swiften/FileTransfer/WriteBytestream.h> namespace Swift { - class IncomingFileTransfer { + class IncomingFileTransfer : public FileTransfer { public: typedef boost::shared_ptr<IncomingFileTransfer> ref; virtual ~IncomingFileTransfer(); virtual void accept(WriteBytestream::ref) = 0; + + virtual const JID& getSender() const = 0; + virtual const JID& getRecipient() const = 0; }; } diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp index 5535840..22e8bf9 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp +++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp @@ -10,13 +10,17 @@ #include <Swiften/Elements/JingleDescription.h> #include <Swiften/Elements/JingleFileTransferDescription.h> -#include <Swiften/Elements/JingleIBBTransport.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> #include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/Jingle/Jingle.h> #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> namespace Swift { -IncomingFileTransferManager::IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router) : jingleSessionManager(jingleSessionManager), router(router) { +IncomingFileTransferManager::IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, + RemoteJingleTransportCandidateSelectorFactory* remoteFactory, + LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, TimerFactory* timerFactory) : jingleSessionManager(jingleSessionManager), router(router), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), timerFactory(timerFactory) { jingleSessionManager->addIncomingSessionHandler(this); } @@ -24,16 +28,22 @@ IncomingFileTransferManager::~IncomingFileTransferManager() { jingleSessionManager->removeIncomingSessionHandler(this); } -bool IncomingFileTransferManager::handleIncomingJingleSession(IncomingJingleSession::ref session) { - JingleContent::ref content = session->getContentWithDescription<JingleFileTransferDescription>(); - if (content) { - // Check for supported transports - if (content->getTransport<JingleIBBTransport>()) { - IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(session); - onIncomingFileTransfer(transfer); +bool IncomingFileTransferManager::handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient) { + if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) { + if (content->getTransport<JingleIBBTransportPayload>() || content->getTransport<JingleS5BTransportPayload>()) { + + JingleFileTransferDescription::ref description = content->getDescription<JingleFileTransferDescription>(); + + if (description && description->getOffers().size() == 1) { + IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>(recipient, session, content, remoteFactory, localFactory, router, bytestreamRegistry, bytestreamProxy, timerFactory); + onIncomingFileTransfer(transfer); + } else { + std::cerr << "Received a file-transfer request with no description or more than one file!" << std::endl; + session->sendTerminate(JinglePayload::Reason::FailedApplication); + } } else { - session->terminate(JinglePayload::Reason::UnsupportedTransports); + session->sendTerminate(JinglePayload::Reason::UnsupportedTransports); } return true; } diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.h b/Swiften/FileTransfer/IncomingFileTransferManager.h index a54b5cd..2d1c07f 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.h +++ b/Swiften/FileTransfer/IncomingFileTransferManager.h @@ -15,19 +15,29 @@ namespace Swift { class IQRouter; class JingleSessionManager; + class RemoteJingleTransportCandidateSelectorFactory; + class LocalJingleTransportCandidateGeneratorFactory; + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamProxy; + class TimerFactory; class IncomingFileTransferManager : public IncomingJingleSessionHandler { public: - IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router); + IncomingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, TimerFactory* timerFactory); ~IncomingFileTransferManager(); boost::signal<void (IncomingFileTransfer::ref)> onIncomingFileTransfer; private: - bool handleIncomingJingleSession(IncomingJingleSession::ref session); + bool handleIncomingJingleSession(JingleSession::ref session, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient); private: JingleSessionManager* jingleSessionManager; IQRouter* router; + RemoteJingleTransportCandidateSelectorFactory* remoteFactory; + LocalJingleTransportCandidateGeneratorFactory* localFactory; + SOCKS5BytestreamRegistry* bytestreamRegistry; + SOCKS5BytestreamProxy* bytestreamProxy; + TimerFactory* timerFactory; }; } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp index cb2f65c..0871568 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp @@ -6,14 +6,516 @@ #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> +#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Queries/GenericRequest.h> + namespace Swift { -IncomingJingleFileTransfer::IncomingJingleFileTransfer(IncomingJingleSession::ref session) : session(session) { +IncomingJingleFileTransfer::IncomingJingleFileTransfer( + const JID& ourJID, + JingleSession::ref session, + JingleContentPayload::ref content, + RemoteJingleTransportCandidateSelectorFactory* candidateSelectorFactory, + LocalJingleTransportCandidateGeneratorFactory* candidateGeneratorFactory, + IQRouter* router, + SOCKS5BytestreamRegistry* registry, + SOCKS5BytestreamProxy* proxy, + TimerFactory* timerFactory) : + ourJID(ourJID), + session(session), + router(router), + timerFactory(timerFactory), + initialContent(content), + state(Initial), + receivedBytes(0), + s5bRegistry(registry), + s5bProxy(proxy), + remoteTransportCandidateSelectFinished(false), + localTransportCandidateSelectFinished(false), + serverSession(0) { + + candidateSelector = candidateSelectorFactory->createCandidateSelector(); + candidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); + + candidateGenerator = candidateGeneratorFactory->createCandidateGenerator(); + candidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); + + session->onTransportInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); + session->onTransportReplaceReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2)); + session->onSessionTerminateReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); + session->onSessionInfoReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleSessionInfoReceived, this, _1)); + + description = initialContent->getDescription<JingleFileTransferDescription>(); + assert(description); + assert(description->getOffers().size() == 1); + StreamInitiationFileInfo fileInfo = description->getOffers().front(); + fileSizeInBytes = fileInfo.getSize(); + filename = fileInfo.getName(); + hash = fileInfo.getHash(); + algo = fileInfo.getAlgo(); + + waitOnHashTimer = timerFactory->createTimer(5000); + waitOnHashTimer->onTick.connect(boost::bind(&IncomingJingleFileTransfer::finishOffTransfer, this)); +} + +IncomingJingleFileTransfer::~IncomingJingleFileTransfer() { + stream->onWrite.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + delete hashCalculator; + + session->onSessionTerminateReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleSessionTerminateReceived, this)); + session->onTransportReplaceReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportReplaceReceived, this, _1, _2)); + session->onTransportInfoReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); + + candidateGenerator->onLocalTransportCandidatesGenerated.disconnect(boost::bind(&IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); + delete candidateGenerator; + candidateSelector->onRemoteTransportCandidateSelectFinished.disconnect(boost::bind(&IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); + delete candidateSelector; } void IncomingJingleFileTransfer::accept(WriteBytestream::ref stream) { + assert(!this->stream); this->stream = stream; + + hashCalculator = new IncrementalBytestreamHashCalculator( algo == "md5" || hash.empty() , algo == "sha-1" || hash.empty() ); + stream->onWrite.connect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + stream->onWrite.connect(boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1)); + onStateChange(FileTransfer::State(FileTransfer::State::Negotiating)); + if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) { + SWIFT_LOG(debug) << "Got IBB transport payload!" << std::endl; + setActiveTransport(createIBBTransport(ibbTransport)); + session->sendAccept(getContentID(), initialContent->getDescriptions()[0], ibbTransport); + } + else if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) { + SWIFT_LOG(debug) << "Got S5B transport payload!" << std::endl; + state = CreatingInitialTransports; + s5bSessionID = s5bTransport->getSessionID().empty() ? idGenerator.generateID() : s5bTransport->getSessionID(); + s5bDestination = SOCKS5BytestreamRegistry::getHostname(s5bSessionID, ourJID, session->getInitiator()); + s5bRegistry->addWriteBytestream(s5bDestination, stream); + fillCandidateMap(theirCandidates, s5bTransport); + candidateSelector->addRemoteTransportCandidates(s5bTransport); + candidateSelector->setRequesterTargtet(session->getInitiator(), ourJID); + s5bTransport->setSessionID(s5bSessionID); + candidateGenerator->generateLocalTransportCandidates(s5bTransport); + } + else { + assert(false); + } +} + +const JID& IncomingJingleFileTransfer::getSender() const { + return session->getInitiator(); +} + +const JID& IncomingJingleFileTransfer::getRecipient() const { + return ourJID; +} + +void IncomingJingleFileTransfer::cancel() { + session->sendTerminate(JinglePayload::Reason::Cancel); + + if (activeTransport) activeTransport->stop(); + if (serverSession) serverSession->stop(); + if (clientSession) clientSession->stop(); + onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); +} + +void IncomingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates) { + if (state == CreatingInitialTransports) { + if (JingleS5BTransportPayload::ref s5bCandidates = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(candidates)) { + //localTransportCandidateSelectFinished = true; + //JingleS5BTransportPayload::ref emptyCandidates = boost::make_shared<JingleS5BTransportPayload>(); + //emptyCandidates->setSessionID(s5bCandidates->getSessionID()); + fillCandidateMap(ourCandidates, s5bCandidates); + session->sendAccept(getContentID(), initialContent->getDescriptions()[0], s5bCandidates); + + state = NegotiatingTransport; + candidateSelector->selectCandidate(); + } + } + else { + SWIFT_LOG(debug) << "Unhandled state!" << std::endl; + } +} + + +void IncomingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << std::endl; + if (state == Terminated) { + return; + } + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { + //remoteTransportCandidateSelectFinished = true; + //selectedRemoteTransportCandidate = transport; + ourCandidate = s5bPayload; + //checkCandidateSelected(); + decideOnUsedTransport(); + session->sendTransportInfo(getContentID(), s5bPayload); + } + else { + SWIFT_LOG(debug) << "Expected something different here." << std::endl; + } +} + +void IncomingJingleFileTransfer::checkCandidateSelected() { + assert(false); + if (localTransportCandidateSelectFinished && remoteTransportCandidateSelectFinished) { + if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate) && candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) { + if (candidateGenerator->getPriority(selectedLocalTransportCandidate) > candidateSelector->getPriority(selectedRemoteTransportCandidate)) { + setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate)); + } + else { + setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate)); + } + } + else if (candidateSelector->isActualCandidate(selectedRemoteTransportCandidate)) { + setActiveTransport(candidateSelector->selectTransport(selectedRemoteTransportCandidate)); + } + else if (candidateGenerator->isActualCandidate(selectedLocalTransportCandidate)) { + setActiveTransport(candidateGenerator->selectTransport(selectedLocalTransportCandidate)); + } + else { + state = WaitingForFallbackOrTerminate; + } + } +} + +void IncomingJingleFileTransfer::setActiveTransport(JingleTransport::ref transport) { + state = Transferring; + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + activeTransport = transport; + activeTransport->onDataReceived.connect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); + activeTransport->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + activeTransport->start(); +} + +bool IncomingJingleFileTransfer::verifyReceviedData() { + if (algo.empty() || hash.empty()) { + SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; + return true; + } else { + if (algo == "sha-1") { + SWIFT_LOG(debug) << "verify data via SHA-1 hash: " << (hash == hashCalculator->getSHA1String()) << std::endl; + return hash == hashCalculator->getSHA1String(); + } + else if (algo == "md5") { + SWIFT_LOG(debug) << "verify data via MD5 hash: " << (hash == hashCalculator->getMD5String()) << std::endl; + return hash == hashCalculator->getMD5String(); + } + else { + SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; + return true; + } + } +} + +void IncomingJingleFileTransfer::finishOffTransfer() { + if (verifyReceviedData()) { + onStateChange(FileTransfer::State(FileTransfer::State::Finished)); + session->sendTerminate(JinglePayload::Reason::Success); + } else { + onStateChange(FileTransfer::State(FileTransfer::State::Failed, "Verification failed.")); + session->sendTerminate(JinglePayload::Reason::MediaError); + } + state = Terminated; + waitOnHashTimer->stop(); +} + +void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref jinglePayload) { + if (state == Terminated) { + return; + } + JingleFileTransferHash::ref transferHash = jinglePayload->getPayload<JingleFileTransferHash>(); + if (transferHash) { + SWIFT_LOG(debug) << "Recevied hash information." << std::endl; + if (transferHash->getHashes().find("sha-1") != transferHash->getHashes().end()) { + algo = "sha-1"; + hash = transferHash->getHashes().find("sha-1")->second; + } + else if (transferHash->getHashes().find("md5") != transferHash->getHashes().end()) { + algo = "md5"; + hash = transferHash->getHashes().find("md5")->second; + } + checkIfAllDataReceived(); + } +} + +void IncomingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { + SWIFT_LOG(debug) << "session terminate received" << std::endl; + if (activeTransport) activeTransport->stop(); + if (reason && reason.get().type == JinglePayload::Reason::Cancel) { + onStateChange(FileTransfer::State(FileTransfer::State::Canceled, "Other user canceled the transfer.")); + } + else if (reason && reason.get().type == JinglePayload::Reason::Success) { + /*if (verifyReceviedData()) { + onStateChange(FileTransfer::State(FileTransfer::State::Finished)); + } else { + onStateChange(FileTransfer::State(FileTransfer::State::Failed, "Verification failed.")); + }*/ + } + state = Terminated; +} + +void IncomingJingleFileTransfer::checkIfAllDataReceived() { + if (receivedBytes == fileSizeInBytes) { + SWIFT_LOG(debug) << "All data received." << std::endl; + if (hash.empty()) { + SWIFT_LOG(debug) << "No hash information yet. Waiting 5 seconds on hash info." << std::endl; + waitOnHashTimer->start(); + } else { + SWIFT_LOG(debug) << "We already have hash info using " << algo << " algorithm. Finishing off transfer." << std::endl; + finishOffTransfer(); + } + } + else if (receivedBytes > fileSizeInBytes) { + SWIFT_LOG(debug) << "We got more than we could handle!" << std::endl; + } +} + +void IncomingJingleFileTransfer::handleTransportDataReceived(const std::vector<unsigned char>& data) { + SWIFT_LOG(debug) << data.size() << " bytes received" << std::endl; + onProcessedBytes(data.size()); + stream->write(data); + receivedBytes += data.size(); + checkIfAllDataReceived(); +} + +void IncomingJingleFileTransfer::handleWriteStreamDataReceived(const std::vector<unsigned char>& data) { + receivedBytes += data.size(); + checkIfAllDataReceived(); +} + +void IncomingJingleFileTransfer::useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) { + SWIFT_LOG(debug) << std::endl; + if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { + // get proxy client session from remoteCandidateSelector + clientSession = candidateSelector->getS5BSession(); + + // wait on <activated/> transport-info + } else { + // ask s5b client + clientSession = candidateSelector->getS5BSession(); + if (clientSession) { + state = Transferring; + SWIFT_LOG(debug) << clientSession->getAddressPort().toString() << std::endl; + clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + clientSession->startReceiving(stream); + } else { + SWIFT_LOG(debug) << "No S5B client session found!!!" << std::endl; + } + } +} + +void IncomingJingleFileTransfer::useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate) { + SWIFT_LOG(debug) << std::endl; + + if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { + // get proxy client session from s5bRegistry + clientSession = s5bProxy->createSOCKS5BytestreamClientSession(candidate.hostPort, SOCKS5BytestreamRegistry::getHostname(s5bSessionID, ourJID, session->getInitiator())); + clientSession->onSessionReady.connect(boost::bind(&IncomingJingleFileTransfer::proxySessionReady, this, candidate.jid, _1)); + clientSession->start(); + + // on reply send activate + } else { + // ask s5b server + serverSession = s5bRegistry->getConnectedSession(s5bDestination); + if (serverSession) { + state = Transferring; + serverSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + serverSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + serverSession->startTransfer(); + } else { + SWIFT_LOG(debug) << "No S5B server session found!!!" << std::endl; + } + } +} + +void IncomingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) { + map.clear(); + foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) { + map[candidate.cid] = candidate; + } +} + + +void IncomingJingleFileTransfer::decideOnUsedTransport() { + if (ourCandidate && theirCandidate) { + if (ourCandidate->hasCandidateError() && theirCandidate->hasCandidateError()) { + state = WaitingForFallbackOrTerminate; + return; + } + std::string our_cid = ourCandidate->getCandidateUsed(); + std::string their_cid = theirCandidate->getCandidateUsed(); + if (ourCandidate->hasCandidateError() && !their_cid.empty()) { + useTheirCandidateChoiceForTransfer(ourCandidates[their_cid]); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } + else if (theirCandidate->hasCandidateError() && !our_cid.empty()) { + useOurCandidateChoiceForTransfer(theirCandidates[our_cid]); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } + else if (!our_cid.empty() && !their_cid.empty()) { + // compare priorites, if same they win + if (ourCandidates.find(their_cid) == ourCandidates.end() || theirCandidates.find(our_cid) == theirCandidates.end()) { + SWIFT_LOG(debug) << "Didn't recognize candidate IDs!" << std::endl; + session->sendTerminate(JinglePayload::Reason::FailedTransport); + onStateChange(FileTransfer::State(FileTransfer::State::Canceled, "Failed to negotiate candidate.")); + onFinished(FileTransferError(FileTransferError::PeerError)); + return; + } + + JingleS5BTransportPayload::Candidate our_candidate = theirCandidates[our_cid]; + JingleS5BTransportPayload::Candidate their_candidate = ourCandidates[their_cid]; + if (our_candidate.priority > their_candidate.priority) { + useOurCandidateChoiceForTransfer(our_candidate); + } + else if (our_candidate.priority < their_candidate.priority) { + useTheirCandidateChoiceForTransfer(their_candidate); + } + else { + useTheirCandidateChoiceForTransfer(their_candidate); + } + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } + else { + assert(false); + } + } else { + SWIFT_LOG(debug) << "Can't make a transport decision yet." << std::endl; + } +} + +void IncomingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) { + if (error) { + // indicate proxy error + } else { + // activate proxy + activateProxySession(proxy); + } +} + +void IncomingJingleFileTransfer::activateProxySession(const JID &proxy) { + S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); + proxyRequest->setSID(s5bSessionID); + proxyRequest->setActivate(session->getInitiator()); + + boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router); + request->onResponse.connect(boost::bind(&IncomingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2)); + request->send(); +} + +void IncomingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) { + SWIFT_LOG(debug) << std::endl; + if (error) { + SWIFT_LOG(debug) << "ERROR" << std::endl; + } else { + // send activated to other jingle party + JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); + proxyActivate->setActivated(theirCandidate->getCandidateUsed()); + session->sendTransportInfo(getContentID(), proxyActivate); + + // start transferring + clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + clientSession->startReceiving(stream); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } +} + +void IncomingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref transport) { + SWIFT_LOG(debug) << "transport info received" << std::endl; + if (state == Terminated) { + return; + } + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { + if (!s5bPayload->getActivated().empty()) { + if (ourCandidate->getCandidateUsed() == s5bPayload->getActivated()) { + clientSession->onBytesReceived.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + clientSession->onFinished.connect(boost::bind(&IncomingJingleFileTransfer::handleTransferFinished, this, _1)); + clientSession->startReceiving(stream); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } else { + SWIFT_LOG(debug) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; + JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>(); + proxyError->setProxyError(true); + proxyError->setSessionID(s5bSessionID); + session->sendTransportInfo(getContentID(), proxyError); + } + } else { + theirCandidate = s5bPayload; + decideOnUsedTransport(); + } + } + else { + SWIFT_LOG(debug) << "Expected something different here." << std::endl; + } + /*localTransportCandidateSelectFinished = true; + selectedLocalTransportCandidate = transport; + if (candidateGenerator->isActualCandidate(transport)) { + candidateSelector->setMinimumPriority(candidateGenerator->getPriority(transport)); + }*/ + //checkCandidateSelected(); +} + +void IncomingJingleFileTransfer::handleTransportReplaceReceived(const JingleContentID& content, JingleTransportPayload::ref transport) { + if (state == Terminated) { + return; + } + if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { + SWIFT_LOG(debug) << "transport replaced with IBB" << std::endl; + setActiveTransport(createIBBTransport(ibbTransport)); + session->sendTransportAccept(content, ibbTransport); + } else { + SWIFT_LOG(debug) << "transport replaced failed" << std::endl; + session->sendTransportReject(content, transport); + } +} + +void IncomingJingleFileTransfer::stopActiveTransport() { + if (activeTransport) { + activeTransport->stop(); + activeTransport->onDataReceived.disconnect(boost::bind(&IncomingJingleFileTransfer::handleTransportDataReceived, this, _1)); + } +} + +JingleIncomingIBBTransport::ref IncomingJingleFileTransfer::createIBBTransport(JingleIBBTransportPayload::ref ibbTransport) { + // TODO: getOffer() -> getOffers correction + return boost::make_shared<JingleIncomingIBBTransport>(session->getInitiator(), getRecipient(), ibbTransport->getSessionID(), description->getOffers()[0].getSize(), router); +} + +JingleContentID IncomingJingleFileTransfer::getContentID() const { + return JingleContentID(initialContent->getName(), initialContent->getCreator()); +} + +void IncomingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { + if (state == Terminated) { + return; + } + + if (error) { + session->sendTerminate(JinglePayload::Reason::ConnectivityError); + onStateChange(FileTransfer::State(FileTransfer::State::Failed)); + onFinished(error); + } + // } } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h index d69449e..4ae0bfb 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h @@ -7,21 +7,128 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <boost/cstdint.hpp> -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/Jingle/JingleContentID.h> #include <Swiften/FileTransfer/IncomingFileTransfer.h> +#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { + class IQRouter; + class RemoteJingleTransportCandidateSelectorFactory; + class LocalJingleTransportCandidateGeneratorFactory; + class RemoteJingleTransportCandidateSelector; + class LocalJingleTransportCandidateGenerator; + class SOCKS5BytestreamRegistry; + class SOCKS5BytestreamProxy; + class IncrementalBytestreamHashCalculator; + class IncomingJingleFileTransfer : public IncomingFileTransfer { public: typedef boost::shared_ptr<IncomingJingleFileTransfer> ref; + enum State { + Initial, + CreatingInitialTransports, + NegotiatingTransport, + Transferring, + WaitingForFallbackOrTerminate, + Terminated + }; - IncomingJingleFileTransfer(IncomingJingleSession::ref session); + IncomingJingleFileTransfer( + const JID& recipient, + JingleSession::ref, + JingleContentPayload::ref content, + RemoteJingleTransportCandidateSelectorFactory*, + LocalJingleTransportCandidateGeneratorFactory*, + IQRouter* router, + SOCKS5BytestreamRegistry* bytestreamRegistry, + SOCKS5BytestreamProxy* bytestreamProxy, + TimerFactory*); + ~IncomingJingleFileTransfer(); virtual void accept(WriteBytestream::ref); + virtual const JID& getSender() const; + virtual const JID& getRecipient() const; + void cancel(); + + private: + void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason>); + void handleSessionInfoReceived(JinglePayload::ref); + void handleTransportReplaceReceived(const JingleContentID&, JingleTransportPayload::ref); + void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); + void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref candidates); + void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref candidate); + void setActiveTransport(JingleTransport::ref transport); + void handleTransportDataReceived(const std::vector<unsigned char>& data); + void handleWriteStreamDataReceived(const std::vector<unsigned char>& data); + void stopActiveTransport(); + void checkCandidateSelected(); + JingleIncomingIBBTransport::ref createIBBTransport(JingleIBBTransportPayload::ref ibbTransport); + JingleContentID getContentID() const; + void checkIfAllDataReceived(); + bool verifyReceviedData(); + void finishOffTransfer(); + void handleTransferFinished(boost::optional<FileTransferError>); + + private: + typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + + private: + void activateProxySession(const JID &proxy); + void handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error); + void proxySessionReady(const JID& proxy, bool error); + + private: + void useOurCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate); + void useTheirCandidateChoiceForTransfer(JingleS5BTransportPayload::Candidate candidate); + void decideOnUsedTransport(); + void fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload); private: - IncomingJingleSession::ref session; + JID ourJID; + JingleSession::ref session; + IQRouter* router; + TimerFactory* timerFactory; + JingleContentPayload::ref initialContent; + State state; + JingleFileTransferDescription::ref description; WriteBytestream::ref stream; + boost::uintmax_t receivedBytes; + IncrementalBytestreamHashCalculator* hashCalculator; + Timer::ref waitOnHashTimer; + IDGenerator idGenerator; + + RemoteJingleTransportCandidateSelector* candidateSelector; + LocalJingleTransportCandidateGenerator* candidateGenerator; + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamProxy* s5bProxy; + bool remoteTransportCandidateSelectFinished; + JingleTransportPayload::ref selectedRemoteTransportCandidate; + bool localTransportCandidateSelectFinished; + JingleTransportPayload::ref selectedLocalTransportCandidate; + + JingleS5BTransportPayload::ref ourCandidate; + JingleS5BTransportPayload::ref theirCandidate; + CandidateMap ourCandidates; + CandidateMap theirCandidates; + SOCKS5BytestreamClientSession::ref clientSession; + std::string s5bDestination; + std::string s5bSessionID; + SOCKS5BytestreamServerSession* serverSession; + + JingleTransport::ref activeTransport; }; } diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp new file mode 100644 index 0000000..6b53a1b --- /dev/null +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> + +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/StringCodecs/MD5.h> +#include <Swiften/StringCodecs/SHA1.h> + +namespace Swift { + +IncrementalBytestreamHashCalculator::IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1) { + md5Hasher = doMD5 ? new MD5() : NULL; + sha1Hasher = doSHA1 ? new SHA1() : NULL; +} + +IncrementalBytestreamHashCalculator::~IncrementalBytestreamHashCalculator() { + delete md5Hasher; + delete sha1Hasher; +} + +void IncrementalBytestreamHashCalculator::feedData(const ByteArray& data) { + if (md5Hasher) { + md5Hasher->update(data); + } + if (sha1Hasher) { + sha1Hasher->update(data); + } +} +/* +void IncrementalBytestreamHashCalculator::feedData(const SafeByteArray& data) { + if (md5Hasher) { + md5Hasher->update(createByteArray(data.data(), data.size())); + } + if (sha1Hasher) { + sha1Hasher->update(createByteArray(data.data(), data.size())); + } +}*/ + +std::string IncrementalBytestreamHashCalculator::getSHA1String() { + if (sha1Hasher) { + ByteArray result = sha1Hasher->getHash(); + return Hexify::hexify(result); + } else { + return std::string(); + } +} + +std::string IncrementalBytestreamHashCalculator::getMD5String() { + if (md5Hasher) { + ByteArray result = md5Hasher->getHash(); + return Hexify::hexify(result); + } else { + return std::string(); + } +} + +} diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h new file mode 100644 index 0000000..64f4b5f --- /dev/null +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> + +namespace Swift { + +class MD5; +class SHA1; + +class IncrementalBytestreamHashCalculator { +public: + IncrementalBytestreamHashCalculator(bool doMD5, bool doSHA1); + ~IncrementalBytestreamHashCalculator(); + + void feedData(const ByteArray& data); + //void feedData(const SafeByteArray& data); + + std::string getSHA1String(); + std::string getMD5String(); + +private: + MD5* md5Hasher; + SHA1* sha1Hasher; +}; + +} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp new file mode 100644 index 0000000..ccca641 --- /dev/null +++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/JingleIncomingIBBTransport.h> + +namespace Swift { + +JingleIncomingIBBTransport::JingleIncomingIBBTransport(const JID& from, const JID& to, const std::string& id, size_t size, IQRouter* router) : ibbSession(id, from, to, size, router) { + ibbSession.onDataReceived.connect(boost::ref(onDataReceived)); + ibbSession.onFinished.connect(boost::ref(onFinished)); +} + +void JingleIncomingIBBTransport::start() { + ibbSession.start(); +} + +void JingleIncomingIBBTransport::stop() { + ibbSession.stop(); +} + +} diff --git a/Swiften/FileTransfer/JingleIncomingIBBTransport.h b/Swiften/FileTransfer/JingleIncomingIBBTransport.h new file mode 100644 index 0000000..be18a2d --- /dev/null +++ b/Swiften/FileTransfer/JingleIncomingIBBTransport.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/FileTransfer/IBBReceiveSession.h> + +namespace Swift { + class JingleIncomingIBBTransport : public JingleTransport { + public: + typedef boost::shared_ptr<JingleIncomingIBBTransport> ref; + + JingleIncomingIBBTransport(const JID& from, const JID& to, const std::string& id, size_t size, IQRouter* router); + + virtual void start(); + virtual void stop(); + + private: + IBBReceiveSession ibbSession; + }; +} diff --git a/Swiften/FileTransfer/JingleTransport.cpp b/Swiften/FileTransfer/JingleTransport.cpp new file mode 100644 index 0000000..c507922 --- /dev/null +++ b/Swiften/FileTransfer/JingleTransport.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/JingleTransport.h> + +namespace Swift { + +JingleTransport::~JingleTransport() { + +} + +} diff --git a/Swiften/FileTransfer/JingleTransport.h b/Swiften/FileTransfer/JingleTransport.h new file mode 100644 index 0000000..fa296e8 --- /dev/null +++ b/Swiften/FileTransfer/JingleTransport.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/FileTransfer.h> + +namespace Swift { + class JingleTransport { + public: + typedef boost::shared_ptr<JingleTransport> ref; + + virtual ~JingleTransport(); + + virtual void start() = 0; + virtual void stop() = 0; + + boost::signal<void (const std::vector<unsigned char>&)> onDataReceived; + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + }; +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp new file mode 100644 index 0000000..852902b --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> + +namespace Swift { + +LocalJingleTransportCandidateGenerator::~LocalJingleTransportCandidateGenerator() { +} + +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h new file mode 100644 index 0000000..041afe3 --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/Elements/JingleTransportPayload.h> +#include <Swiften/FileTransfer/JingleTransport.h> + +namespace Swift { + class LocalJingleTransportCandidateGenerator { + public: + virtual ~LocalJingleTransportCandidateGenerator(); + /** + * Should call onLocalTransportCandidatesGenerated if it has finished discovering local candidates. + */ + virtual void generateLocalTransportCandidates(JingleTransportPayload::ref) = 0; + + virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; + virtual int getPriority(JingleTransportPayload::ref) = 0; + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + + boost::signal<void (JingleTransportPayload::ref)> onLocalTransportCandidatesGenerated; + }; +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp new file mode 100644 index 0000000..a1e3874 --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> + +namespace Swift { + +LocalJingleTransportCandidateGeneratorFactory::~LocalJingleTransportCandidateGeneratorFactory() { +} + +} diff --git a/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h new file mode 100644 index 0000000..c969fc7 --- /dev/null +++ b/Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +namespace Swift { + class LocalJingleTransportCandidateGenerator; + + class LocalJingleTransportCandidateGeneratorFactory { + public: + virtual ~LocalJingleTransportCandidateGeneratorFactory(); + + virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() = 0; + }; +} diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.cpp b/Swiften/FileTransfer/OutgoingFileTransfer.cpp index 32f7e17..94d4348 100644 --- a/Swiften/FileTransfer/OutgoingFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingFileTransfer.cpp @@ -4,75 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/OutgoingFileTransfer.h" - -#include <boost/bind.hpp> - -#include "Swiften/FileTransfer/StreamInitiationRequest.h" -#include "Swiften/FileTransfer/BytestreamsRequest.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" -#include "Swiften/FileTransfer/IBBSendSession.h" +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> namespace Swift { -OutgoingFileTransfer::OutgoingFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) { -} - -void OutgoingFileTransfer::start() { - StreamInitiation::ref streamInitiation(new StreamInitiation()); - streamInitiation->setID(id); - streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); - //streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams"); - streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb"); - StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter); - request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); - request->send(); -} - -void OutgoingFileTransfer::stop() { -} - -void OutgoingFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { - if (error) { - finish(FileTransferError()); - } - else { - if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") { - socksServer->addBytestream(id, from, to, bytestream); - Bytestreams::ref bytestreams(new Bytestreams()); - bytestreams->setStreamID(id); - HostAddressPort addressPort = socksServer->getAddressPort(); - bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort())); - BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter); - request->onResponse.connect(boost::bind(&OutgoingFileTransfer::handleBytestreamsRequestResponse, this, _1, _2)); - request->send(); - } - else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") { - ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, to, bytestream, iqRouter)); - ibbSession->onFinished.connect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1)); - ibbSession->start(); - } - } -} - -void OutgoingFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { - if (error) { - finish(FileTransferError()); - } - //socksServer->onTransferFinished.connect(); -} - -void OutgoingFileTransfer::finish(boost::optional<FileTransferError> error) { - if (ibbSession) { - ibbSession->onFinished.disconnect(boost::bind(&OutgoingFileTransfer::handleIBBSessionFinished, this, _1)); - ibbSession.reset(); - } - socksServer->removeBytestream(id, from, to); - onFinished(error); -} - -void OutgoingFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) { - finish(error); +OutgoingFileTransfer::~OutgoingFileTransfer() { } } diff --git a/Swiften/FileTransfer/OutgoingFileTransfer.h b/Swiften/FileTransfer/OutgoingFileTransfer.h index a694c13..1ec1ae3 100644 --- a/Swiften/FileTransfer/OutgoingFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingFileTransfer.h @@ -8,45 +8,16 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/FileTransfer/ReadBytestream.h" -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/FileTransfer/FileTransferError.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/StreamInitiation.h" -#include "Swiften/Elements/Bytestreams.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/FileTransfer/IBBSendSession.h" +#include <Swiften/FileTransfer/FileTransfer.h> namespace Swift { - class IQRouter; - class SOCKS5BytestreamServer; - - class OutgoingFileTransfer { + class OutgoingFileTransfer : public FileTransfer { public: - OutgoingFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer); - - void start(); - void stop(); - - boost::signal<void (const boost::optional<FileTransferError>&)> onFinished; - - private: - void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref); - void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref); - void finish(boost::optional<FileTransferError> error); - void handleIBBSessionFinished(boost::optional<FileTransferError> error); + typedef boost::shared_ptr<OutgoingFileTransfer> ref; + public: + virtual ~OutgoingFileTransfer(); - private: - std::string id; - JID from; - JID to; - std::string name; - int size; - std::string description; - boost::shared_ptr<ReadBytestream> bytestream; - IQRouter* iqRouter; - SOCKS5BytestreamServer* socksServer; - boost::shared_ptr<IBBSendSession> ibbSession; + virtual void start() = 0; + virtual void stop() = 0; }; } diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp new file mode 100644 index 0000000..6f23bb7 --- /dev/null +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "OutgoingFileTransferManager.h" + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/JID/JID.h> +#include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/Jingle/JingleSessionImpl.h> +#include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h> +#include <Swiften/Base/IDGenerator.h> + +namespace Swift { + +OutgoingFileTransferManager::OutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy) { + idGenerator = new IDGenerator(); +} + +OutgoingFileTransferManager::~OutgoingFileTransferManager() { + delete idGenerator; +} + +boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgoingFileTransfer(const JID& from, const JID& receipient, boost::shared_ptr<ReadBytestream> readBytestream, const StreamInitiationFileInfo& fileInfo) { + // check if receipient support Jingle FT + + + JingleSessionImpl::ref jingleSession = boost::make_shared<JingleSessionImpl>(from, receipient, idGenerator->generateID(), iqRouter); + + //jsManager->getSession(receipient, idGenerator->generateID()); + assert(jingleSession); + jsManager->registerOutgoingSession(from, jingleSession); + boost::shared_ptr<OutgoingJingleFileTransfer> jingleFT = boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(jingleSession, remoteFactory, localFactory, iqRouter, idGenerator, from, receipient, readBytestream, fileInfo, bytestreamRegistry, bytestreamProxy)); + + // otherwise try SI + + // else fail + + return jingleFT; +} + +} diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.h b/Swiften/FileTransfer/OutgoingFileTransferManager.h new file mode 100644 index 0000000..c686001 --- /dev/null +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/JID/JID.h> + +namespace Swift { + +class JingleSessionManager; +class IQRouter; +class EntityCapsProvider; +class RemoteJingleTransportCandidateSelectorFactory; +class LocalJingleTransportCandidateGeneratorFactory; +class OutgoingFileTransfer; +class JID; +class IDGenerator; +class ReadBytestream; +class StreamInitiationFileInfo; +class SOCKS5BytestreamRegistry; +class SOCKS5BytestreamProxy; + +class OutgoingFileTransferManager { +public: + OutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy); + ~OutgoingFileTransferManager(); + + boost::shared_ptr<OutgoingFileTransfer> createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr<ReadBytestream>, const StreamInitiationFileInfo&); + +private: + JingleSessionManager* jsManager; + IQRouter* iqRouter; + EntityCapsProvider* capsProvider; + RemoteJingleTransportCandidateSelectorFactory* remoteFactory; + LocalJingleTransportCandidateGeneratorFactory* localFactory; + IDGenerator *idGenerator; + SOCKS5BytestreamRegistry* bytestreamRegistry; + SOCKS5BytestreamProxy* bytestreamProxy; +}; + +} diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp new file mode 100644 index 0000000..5e2a1c3 --- /dev/null +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "OutgoingJingleFileTransfer.h" + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Elements/JingleTransportPayload.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/FileTransfer/IBBSendSession.h> +#include <Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/StringCodecs/SHA1.h> + +#include <Swiften/Base/Log.h> + +namespace Swift { + +OutgoingJingleFileTransfer::OutgoingJingleFileTransfer(JingleSession::ref session, + RemoteJingleTransportCandidateSelectorFactory* remoteFactory, + LocalJingleTransportCandidateGeneratorFactory* localFactory, + IQRouter* router, + IDGenerator *idGenerator, + const JID& fromJID, + const JID& toJID, + boost::shared_ptr<ReadBytestream> readStream, + const StreamInitiationFileInfo &fileInfo, + SOCKS5BytestreamRegistry* bytestreamRegistry, + SOCKS5BytestreamProxy* bytestreamProxy) : + session(session), remoteFactory(remoteFactory), localFactory(localFactory), router(router), idGenerator(idGenerator), fromJID(fromJID), toJID(toJID), readStream(readStream), fileInfo(fileInfo), s5bRegistry(bytestreamRegistry), s5bProxy(bytestreamProxy), serverSession(NULL), contentID(JingleContentID(idGenerator->generateID(), JingleContentPayload::InitiatorCreator)), canceled(false) { + session->onSessionAcceptReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleSessionAcceptReceived, this, _1, _2, _3)); + session->onSessionTerminateReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleSessionTerminateReceived, this, _1)); + session->onTransportInfoReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransportInfoReceived, this, _1, _2)); + session->onTransportAcceptReceived.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransportAcceptReceived, this, _1, _2)); + fileSizeInBytes = fileInfo.getSize(); + filename = fileInfo.getName(); + + localCandidateGenerator = localFactory->createCandidateGenerator(); + localCandidateGenerator->onLocalTransportCandidatesGenerated.connect(boost::bind(&OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated, this, _1)); + + remoteCandidateSelector = remoteFactory->createCandidateSelector(); + remoteCandidateSelector->onRemoteTransportCandidateSelectFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished, this, _1)); + // calculate both, MD5 and SHA-1 since we don't know which one the other side supports + hashCalculator = new IncrementalBytestreamHashCalculator(true, true); + this->readStream->onRead.connect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); +} + +OutgoingJingleFileTransfer::~OutgoingJingleFileTransfer() { + readStream->onRead.disconnect(boost::bind(&IncrementalBytestreamHashCalculator::feedData, hashCalculator, _1)); + delete hashCalculator; +} + +void OutgoingJingleFileTransfer::start() { + onStateChange(FileTransfer::State(FileTransfer::State::WaitingForStart)); + + s5bSessionID = s5bRegistry->generateSessionID(); + SWIFT_LOG(debug) << "S5B SessionID: " << s5bSessionID << std::endl; + + //s5bProxy->connectToProxies(s5bSessionID); + + JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); + localCandidateGenerator->generateLocalTransportCandidates(transport); +} + +void OutgoingJingleFileTransfer::stop() { + +} + +void OutgoingJingleFileTransfer::cancel() { + canceled = true; + session->sendTerminate(JinglePayload::Reason::Cancel); + + if (ibbSession) { + ibbSession->stop(); + } + SOCKS5BytestreamServerSession *serverSession = s5bRegistry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); + if (serverSession) { + serverSession->stop(); + } + if (clientSession) { + clientSession->stop(); + } + onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); +} + +void OutgoingJingleFileTransfer::handleSessionAcceptReceived(const JingleContentID& id, JingleDescription::ref /* decription */, JingleTransportPayload::ref transportPayload) { + if (canceled) { + return; + } + onStateChange(FileTransfer::State(FileTransfer::State::Negotiating)); + + JingleIBBTransportPayload::ref ibbPayload; + JingleS5BTransportPayload::ref s5bPayload; + if ((ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transportPayload))) { + ibbSession = boost::make_shared<IBBSendSession>(ibbPayload->getSessionID(), fromJID, toJID, readStream, router); + ibbSession->setBlockSize(ibbPayload->getBlockSize()); + ibbSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + ibbSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + ibbSession->start(); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } + else if ((s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transportPayload))) { + fillCandidateMap(theirCandidates, s5bPayload); + remoteCandidateSelector->setRequesterTargtet(toJID, session->getInitiator()); + remoteCandidateSelector->addRemoteTransportCandidates(s5bPayload); + remoteCandidateSelector->selectCandidate(); + } + else { + // TODO: error handling + SWIFT_LOG(debug) << "Unknown transport payload! Try replaceing with IBB." << std::endl; + replaceTransportWithIBB(id); + } +} + +void OutgoingJingleFileTransfer::handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason) { + if (canceled) { + return; + } + + if (ibbSession) { + ibbSession->stop(); + } + if (clientSession) { + clientSession->stop(); + } + if (serverSession) { + serverSession->stop(); + } + + if (reason.is_initialized() && reason.get().type == JinglePayload::Reason::Cancel) { + onStateChange(FileTransfer::State(FileTransfer::State::Canceled)); + onFinished(FileTransferError(FileTransferError::PeerError)); + } else if (reason.is_initialized() && reason.get().type == JinglePayload::Reason::Success) { + onStateChange(FileTransfer::State(FileTransfer::State::Finished)); + onFinished(boost::optional<FileTransferError>()); + } else { + onStateChange(FileTransfer::State(FileTransfer::State::Failed)); + onFinished(FileTransferError(FileTransferError::PeerError)); + } + canceled = true; +} + +void OutgoingJingleFileTransfer::handleTransportAcceptReceived(const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { + if (canceled) { + return; + } + + if (JingleIBBTransportPayload::ref ibbPayload = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport)) { + ibbSession = boost::make_shared<IBBSendSession>(ibbPayload->getSessionID(), fromJID, toJID, readStream, router); + ibbSession->setBlockSize(ibbPayload->getBlockSize()); + ibbSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + ibbSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + ibbSession->start(); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } else { + // error handling + SWIFT_LOG(debug) << "Replacing with anything other than IBB isn't supported yet." << std::endl; + session->sendTerminate(JinglePayload::Reason::FailedTransport); + onStateChange(FileTransfer::State(FileTransfer::State::Failed)); + } +} + +void OutgoingJingleFileTransfer::startTransferViaOurCandidateChoice(JingleS5BTransportPayload::Candidate candidate) { + SWIFT_LOG(debug) << "Transferring data using our candidate." << std::endl; + if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { + // get proxy client session from remoteCandidateSelector + clientSession = remoteCandidateSelector->getS5BSession(); + + // wait on <activated/> transport-info + } else { + clientSession = remoteCandidateSelector->getS5BSession(); + clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + clientSession->startSending(readStream); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } + assert(clientSession); +} + +void OutgoingJingleFileTransfer::startTransferViaTheirCandidateChoice(JingleS5BTransportPayload::Candidate candidate) { + SWIFT_LOG(debug) << "Transferring data using their candidate." << std::endl; + if (candidate.type == JingleS5BTransportPayload::Candidate::ProxyType) { + // connect to proxy + clientSession = s5bProxy->createSOCKS5BytestreamClientSession(candidate.hostPort, SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); + clientSession->onSessionReady.connect(boost::bind(&OutgoingJingleFileTransfer::proxySessionReady, this, candidate.jid, _1)); + clientSession->start(); + + // on reply send activate + + } else { + serverSession = s5bRegistry->getConnectedSession(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID)); + serverSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + serverSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + serverSession->startTransfer(); + } + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); +} + +// decide on candidates according to http://xmpp.org/extensions/xep-0260.html#complete +void OutgoingJingleFileTransfer::decideOnCandidates() { + if (ourCandidateChoice && theirCandidateChoice) { + std::string our_cid = ourCandidateChoice->getCandidateUsed(); + std::string their_cid = theirCandidateChoice->getCandidateUsed(); + if (ourCandidateChoice->hasCandidateError() && theirCandidateChoice->hasCandidateError()) { + replaceTransportWithIBB(contentID); + } + else if (!our_cid.empty() && theirCandidateChoice->hasCandidateError()) { + // use our candidate + startTransferViaOurCandidateChoice(theirCandidates[our_cid]); + } + else if (!their_cid.empty() && ourCandidateChoice->hasCandidateError()) { + // use their candidate + startTransferViaTheirCandidateChoice(ourCandidates[their_cid]); + } + else if (!our_cid.empty() && !their_cid.empty()) { + // compare priorites, if same we win + if (ourCandidates.find(their_cid) == ourCandidates.end() || theirCandidates.find(our_cid) == theirCandidates.end()) { + SWIFT_LOG(debug) << "Didn't recognize candidate IDs!" << std::endl; + session->sendTerminate(JinglePayload::Reason::FailedTransport); + onStateChange(FileTransfer::State(FileTransfer::State::Failed)); + onFinished(FileTransferError(FileTransferError::PeerError)); + return; + } + + JingleS5BTransportPayload::Candidate ourCandidate = theirCandidates[our_cid]; + JingleS5BTransportPayload::Candidate theirCandidate = ourCandidates[their_cid]; + if (ourCandidate.priority > theirCandidate.priority) { + startTransferViaOurCandidateChoice(ourCandidate); + } + else if (ourCandidate.priority < theirCandidate.priority) { + startTransferViaTheirCandidateChoice(theirCandidate); + } + else { + startTransferViaOurCandidateChoice(ourCandidate); + } + } + } else { + SWIFT_LOG(debug) << "Can't make a decision yet!" << std::endl; + } +} + +void OutgoingJingleFileTransfer::fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload) { + map.clear(); + foreach (JingleS5BTransportPayload::Candidate candidate, s5bPayload->getCandidates()) { + map[candidate.cid] = candidate; + } +} + +void OutgoingJingleFileTransfer::proxySessionReady(const JID& proxy, bool error) { + if (error) { + // indicate proxy error + } else { + // activate proxy + activateProxySession(proxy); + } +} + +void OutgoingJingleFileTransfer::activateProxySession(const JID& proxy) { + S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); + proxyRequest->setSID(s5bSessionID); + proxyRequest->setActivate(toJID); + + boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Set, proxy, proxyRequest, router); + request->onResponse.connect(boost::bind(&OutgoingJingleFileTransfer::handleActivateProxySessionResult, this, _1, _2)); + request->send(); +} + +void OutgoingJingleFileTransfer::handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> /*request*/, ErrorPayload::ref error) { + if (error) { + SWIFT_LOG(debug) << "ERROR" << std::endl; + } else { + // send activated to other jingle party + JingleS5BTransportPayload::ref proxyActivate = boost::make_shared<JingleS5BTransportPayload>(); + proxyActivate->setActivated(theirCandidateChoice->getCandidateUsed()); + session->sendTransportInfo(contentID, proxyActivate); + + // start transferring + clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + clientSession->startSending(readStream); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } +} + +void OutgoingJingleFileTransfer::sendSessionInfoHash() { + SWIFT_LOG(debug) << std::endl; + JingleFileTransferHash::ref hashElement = boost::make_shared<JingleFileTransferHash>(); + hashElement->setHash("sha-1", hashCalculator->getSHA1String()); + hashElement->setHash("md5", hashCalculator->getMD5String()); + session->sendInfo(hashElement); +} + +void OutgoingJingleFileTransfer::handleTransportInfoReceived(const JingleContentID& /* contentID */, JingleTransportPayload::ref transport) { + if (canceled) { + return; + } + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport)) { + if (s5bPayload->hasCandidateError() || !s5bPayload->getCandidateUsed().empty()) { + theirCandidateChoice = s5bPayload; + decideOnCandidates(); + } else if(!s5bPayload->getActivated().empty()) { + if (ourCandidateChoice->getCandidateUsed() == s5bPayload->getActivated()) { + clientSession->onBytesSent.connect(boost::bind(boost::ref(onProcessedBytes), _1)); + clientSession->onFinished.connect(boost::bind(&OutgoingJingleFileTransfer::handleTransferFinished, this, _1)); + clientSession->startSending(readStream); + onStateChange(FileTransfer::State(FileTransfer::State::Transferring)); + } else { + SWIFT_LOG(debug) << "ourCandidateChoice doesn't match activated proxy candidate!" << std::endl; + JingleS5BTransportPayload::ref proxyError = boost::make_shared<JingleS5BTransportPayload>(); + proxyError->setProxyError(true); + proxyError->setSessionID(s5bSessionID); + session->sendTransportInfo(contentID, proxyError); + } + } + } +} + +void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { + if (canceled) { + return; + } + JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); + description->addOffer(fileInfo); + + JingleTransportPayload::ref transport; + if (JingleIBBTransportPayload::ref ibbTransport = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(payload)) { + ibbTransport->setBlockSize(4096); + ibbTransport->setSessionID(idGenerator->generateID()); + transport = ibbTransport; + } + else if (JingleS5BTransportPayload::ref s5bTransport = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(payload)) { + //fillCandidateMap(ourCandidates, s5bTransport); + //s5bTransport->setSessionID(s5bSessionID); + + JingleS5BTransportPayload::ref emptyCandidates = boost::make_shared<JingleS5BTransportPayload>(); + emptyCandidates->setSessionID(s5bTransport->getSessionID()); + fillCandidateMap(ourCandidates, emptyCandidates); + + transport = emptyCandidates; + s5bRegistry->addReadBytestream(SOCKS5BytestreamRegistry::getHostname(s5bSessionID, session->getInitiator(), toJID), readStream); + } + else { + SWIFT_LOG(debug) << "Unknown tranport payload: " << typeid(*payload).name() << std::endl; + return; + } + session->sendInitiate(contentID, description, transport); + onStateChange(FileTransfer::State(FileTransfer::State::WaitingForAccept)); +} + +void OutgoingJingleFileTransfer::handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref payload) { + if (canceled) { + return; + } + if (JingleS5BTransportPayload::ref s5bPayload = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(payload)) { + ourCandidateChoice = s5bPayload; + session->sendTransportInfo(contentID, s5bPayload); + decideOnCandidates(); + } +} + +void OutgoingJingleFileTransfer::replaceTransportWithIBB(const JingleContentID& id) { + SWIFT_LOG(debug) << "Both parties failed. Replace transport with IBB." << std::endl; + JingleIBBTransportPayload::ref ibbTransport = boost::make_shared<JingleIBBTransportPayload>(); + ibbTransport->setBlockSize(4096); + ibbTransport->setSessionID(idGenerator->generateID()); + session->sendTransportReplace(id, ibbTransport); +} + +void OutgoingJingleFileTransfer::handleTransferFinished(boost::optional<FileTransferError> error) { + if (error) { + session->sendTerminate(JinglePayload::Reason::ConnectivityError); + onStateChange(FileTransfer::State(FileTransfer::State::Failed)); + onFinished(error); + } else { + sendSessionInfoHash(); + /* + session->terminate(JinglePayload::Reason::Success); + onStateChange(FileTransfer::State(FileTransfer::State::Finished)); + */ + } + // +} + +} diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h new file mode 100644 index 0000000..ff7bfc7 --- /dev/null +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/StringCodecs/SHA1.h> + +namespace Swift { + +class RemoteJingleTransportCandidateSelectorFactory; +class RemoteJingleTransportCandidateSelector; +class LocalJingleTransportCandidateGeneratorFactory; +class LocalJingleTransportCandidateGenerator; +class IQRouter; +class ReadBytestream; +class IBBSendSession; +class IDGenerator; +class IncrementalBytestreamHashCalculator; +class SOCKS5BytestreamRegistry; +class SOCKS5BytestreamProxy; + +class OutgoingJingleFileTransfer : public OutgoingFileTransfer { +public: + OutgoingJingleFileTransfer(JingleSession::ref, + RemoteJingleTransportCandidateSelectorFactory*, + LocalJingleTransportCandidateGeneratorFactory*, + IQRouter*, + IDGenerator*, + const JID& from, + const JID& to, + boost::shared_ptr<ReadBytestream>, + const StreamInitiationFileInfo&, + SOCKS5BytestreamRegistry*, + SOCKS5BytestreamProxy*); + virtual ~OutgoingJingleFileTransfer(); + + void start(); + void stop(); + + void cancel(); + +private: + void handleSessionAcceptReceived(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); + void handleSessionTerminateReceived(boost::optional<JinglePayload::Reason> reason); + void handleTransportAcceptReceived(const JingleContentID&, JingleTransportPayload::ref); + void handleTransportInfoReceived(const JingleContentID&, JingleTransportPayload::ref); + + void handleLocalTransportCandidatesGenerated(JingleTransportPayload::ref); + void handleRemoteTransportCandidateSelectFinished(JingleTransportPayload::ref); + +private: + void replaceTransportWithIBB(const JingleContentID&); + void handleTransferFinished(boost::optional<FileTransferError>); + void activateProxySession(const JID &proxy); + void handleActivateProxySessionResult(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error); + void proxySessionReady(const JID& proxy, bool error); + +private: + typedef std::map<std::string, JingleS5BTransportPayload::Candidate> CandidateMap; + +private: + void startTransferViaOurCandidateChoice(JingleS5BTransportPayload::Candidate); + void startTransferViaTheirCandidateChoice(JingleS5BTransportPayload::Candidate); + void decideOnCandidates(); + void fillCandidateMap(CandidateMap& map, JingleS5BTransportPayload::ref s5bPayload); + +private: + void sendSessionInfoHash(); + +private: + JingleSession::ref session; + RemoteJingleTransportCandidateSelector* remoteCandidateSelector; + RemoteJingleTransportCandidateSelectorFactory* remoteFactory; + LocalJingleTransportCandidateGenerator* localCandidateGenerator; + LocalJingleTransportCandidateGeneratorFactory* localFactory; + + IQRouter* router; + IDGenerator* idGenerator; + JID fromJID; + JID toJID; + boost::shared_ptr<ReadBytestream> readStream; + StreamInitiationFileInfo fileInfo; + IncrementalBytestreamHashCalculator *hashCalculator; + + boost::shared_ptr<IBBSendSession> ibbSession; + + JingleS5BTransportPayload::ref ourCandidateChoice; + JingleS5BTransportPayload::ref theirCandidateChoice; + CandidateMap ourCandidates; + CandidateMap theirCandidates; + + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamProxy* s5bProxy; + SOCKS5BytestreamClientSession::ref clientSession; + SOCKS5BytestreamServerSession* serverSession; + JingleContentID contentID; + std::string s5bSessionID; + + bool canceled; +}; + +} diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp new file mode 100644 index 0000000..8a8237a --- /dev/null +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/OutgoingSIFileTransfer.h> + +#include <boost/bind.hpp> + +#include <Swiften/FileTransfer/StreamInitiationRequest.h> +#include <Swiften/FileTransfer/BytestreamsRequest.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/FileTransfer/IBBSendSession.h> + +namespace Swift { + +OutgoingSIFileTransfer::OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer) : id(id), from(from), to(to), name(name), size(size), description(description), bytestream(bytestream), iqRouter(iqRouter), socksServer(socksServer) { +} + +void OutgoingSIFileTransfer::start() { + StreamInitiation::ref streamInitiation(new StreamInitiation()); + streamInitiation->setID(id); + streamInitiation->setFileInfo(StreamInitiationFileInfo(name, description, size)); + //streamInitiation->addProvidedMethod("http://jabber.org/protocol/bytestreams"); + streamInitiation->addProvidedMethod("http://jabber.org/protocol/ibb"); + StreamInitiationRequest::ref request = StreamInitiationRequest::create(to, streamInitiation, iqRouter); + request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleStreamInitiationRequestResponse, this, _1, _2)); + request->send(); +} + +void OutgoingSIFileTransfer::stop() { +} + +void OutgoingSIFileTransfer::handleStreamInitiationRequestResponse(StreamInitiation::ref response, ErrorPayload::ref error) { + if (error) { + finish(FileTransferError()); + } + else { + if (response->getRequestedMethod() == "http://jabber.org/protocol/bytestreams") { + socksServer->addReadBytestream(id, from, to, bytestream); + Bytestreams::ref bytestreams(new Bytestreams()); + bytestreams->setStreamID(id); + HostAddressPort addressPort = socksServer->getAddressPort(); + bytestreams->addStreamHost(Bytestreams::StreamHost(addressPort.getAddress().toString(), from, addressPort.getPort())); + BytestreamsRequest::ref request = BytestreamsRequest::create(to, bytestreams, iqRouter); + request->onResponse.connect(boost::bind(&OutgoingSIFileTransfer::handleBytestreamsRequestResponse, this, _1, _2)); + request->send(); + } + else if (response->getRequestedMethod() == "http://jabber.org/protocol/ibb") { + ibbSession = boost::shared_ptr<IBBSendSession>(new IBBSendSession(id, from, to, bytestream, iqRouter)); + ibbSession->onFinished.connect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); + ibbSession->start(); + } + } +} + +void OutgoingSIFileTransfer::handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref error) { + if (error) { + finish(FileTransferError()); + } + //socksServer->onTransferFinished.connect(); +} + +void OutgoingSIFileTransfer::finish(boost::optional<FileTransferError> error) { + if (ibbSession) { + ibbSession->onFinished.disconnect(boost::bind(&OutgoingSIFileTransfer::handleIBBSessionFinished, this, _1)); + ibbSession.reset(); + } + socksServer->removeReadBytestream(id, from, to); + onFinished(error); +} + +void OutgoingSIFileTransfer::handleIBBSessionFinished(boost::optional<FileTransferError> error) { + finish(error); +} + +} diff --git a/Swiften/FileTransfer/OutgoingSIFileTransfer.h b/Swiften/FileTransfer/OutgoingSIFileTransfer.h new file mode 100644 index 0000000..584eb60 --- /dev/null +++ b/Swiften/FileTransfer/OutgoingSIFileTransfer.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/FileTransfer/OutgoingFileTransfer.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/FileTransferError.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/StreamInitiation.h> +#include <Swiften/Elements/Bytestreams.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/FileTransfer/IBBSendSession.h> + +namespace Swift { + class IQRouter; + class SOCKS5BytestreamServer; + + class OutgoingSIFileTransfer : public OutgoingFileTransfer { + public: + OutgoingSIFileTransfer(const std::string& id, const JID& from, const JID& to, const std::string& name, int size, const std::string& description, boost::shared_ptr<ReadBytestream> bytestream, IQRouter* iqRouter, SOCKS5BytestreamServer* socksServer); + + virtual void start(); + virtual void stop(); + + boost::signal<void (const boost::optional<FileTransferError>&)> onFinished; + + private: + void handleStreamInitiationRequestResponse(StreamInitiation::ref, ErrorPayload::ref); + void handleBytestreamsRequestResponse(Bytestreams::ref, ErrorPayload::ref); + void finish(boost::optional<FileTransferError> error); + void handleIBBSessionFinished(boost::optional<FileTransferError> error); + + private: + std::string id; + JID from; + JID to; + std::string name; + int size; + std::string description; + boost::shared_ptr<ReadBytestream> bytestream; + IQRouter* iqRouter; + SOCKS5BytestreamServer* socksServer; + boost::shared_ptr<IBBSendSession> ibbSession; + }; +} diff --git a/Swiften/FileTransfer/ReadBytestream.cpp b/Swiften/FileTransfer/ReadBytestream.cpp index 705906c..5fa10d8 100644 --- a/Swiften/FileTransfer/ReadBytestream.cpp +++ b/Swiften/FileTransfer/ReadBytestream.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/ReadBytestream.h" +#include <Swiften/FileTransfer/ReadBytestream.h> namespace Swift { diff --git a/Swiften/FileTransfer/ReadBytestream.h b/Swiften/FileTransfer/ReadBytestream.h index 4da2bc2..c94e4d3 100644 --- a/Swiften/FileTransfer/ReadBytestream.h +++ b/Swiften/FileTransfer/ReadBytestream.h @@ -6,13 +6,26 @@ #pragma once -#include "Swiften/Base/ByteArray.h" +#include <boost/shared_ptr.hpp> +#include <vector> + +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class ReadBytestream { public: virtual ~ReadBytestream(); - virtual ByteArray read(size_t size) = 0; + + /** + * Return an empty vector if no more data is available. + * Use onDataAvailable signal for signaling there is data available again. + */ + virtual boost::shared_ptr< std::vector<unsigned char> > read(size_t size) = 0; + virtual bool isFinished() const = 0; + + public: + boost::signal<void ()> onDataAvailable; + boost::signal<void (const std::vector<unsigned char>&)> onRead; }; } diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp new file mode 100644 index 0000000..338f221 --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> + +namespace Swift { + +RemoteJingleTransportCandidateSelector::~RemoteJingleTransportCandidateSelector() { +} + +} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h new file mode 100644 index 0000000..f8df8f9 --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/JingleTransportPayload.h> +#include <Swiften/FileTransfer/JingleTransport.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> + +namespace Swift { + class RemoteJingleTransportCandidateSelector { + public: + virtual ~RemoteJingleTransportCandidateSelector(); + + virtual void addRemoteTransportCandidates(JingleTransportPayload::ref) = 0; + virtual void selectCandidate() = 0; + virtual void setMinimumPriority(int) = 0; + virtual void setRequesterTargtet(const JID&, const JID&) {} + virtual SOCKS5BytestreamClientSession::ref getS5BSession() { return SOCKS5BytestreamClientSession::ref(); } + + virtual bool isActualCandidate(JingleTransportPayload::ref) = 0; + virtual int getPriority(JingleTransportPayload::ref) = 0; + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) = 0; + + boost::signal<void (JingleTransportPayload::ref)> onRemoteTransportCandidateSelectFinished; + }; +} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp new file mode 100644 index 0000000..36b7cba --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> + +namespace Swift { + +RemoteJingleTransportCandidateSelectorFactory::~RemoteJingleTransportCandidateSelectorFactory() { +} + +} diff --git a/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h new file mode 100644 index 0000000..caa3097 --- /dev/null +++ b/Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +namespace Swift { + class RemoteJingleTransportCandidateSelector; + + class RemoteJingleTransportCandidateSelectorFactory { + public: + virtual ~RemoteJingleTransportCandidateSelectorFactory(); + + virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() = 0; + }; +} diff --git a/Swiften/FileTransfer/SConscript b/Swiften/FileTransfer/SConscript index ea9e7bb..4e79992 100644 --- a/Swiften/FileTransfer/SConscript +++ b/Swiften/FileTransfer/SConscript @@ -1,19 +1,48 @@ -Import("swiften_env") +Import("swiften_env", "env") sources = [ "OutgoingFileTransfer.cpp", + "OutgoingSIFileTransfer.cpp", + "OutgoingJingleFileTransfer.cpp", + "OutgoingFileTransferManager.cpp", "IncomingFileTransfer.cpp", "IncomingJingleFileTransfer.cpp", - "IncomingFileTransferManager.cpp", + "IncomingFileTransferManager.cpp", + "RemoteJingleTransportCandidateSelector.cpp", + "RemoteJingleTransportCandidateSelectorFactory.cpp", + "LocalJingleTransportCandidateGenerator.cpp", + "LocalJingleTransportCandidateGeneratorFactory.cpp", + "DefaultRemoteJingleTransportCandidateSelectorFactory.cpp", + "DefaultLocalJingleTransportCandidateGeneratorFactory.cpp", + "DefaultRemoteJingleTransportCandidateSelector.cpp", + "DefaultLocalJingleTransportCandidateGenerator.cpp", + "JingleTransport.cpp", + "JingleIncomingIBBTransport.cpp", "ReadBytestream.cpp", "WriteBytestream.cpp", "FileReadBytestream.cpp", "FileWriteBytestream.cpp", + "SOCKS5BytestreamClientSession.cpp", "SOCKS5BytestreamServer.cpp", "SOCKS5BytestreamServerSession.cpp", "SOCKS5BytestreamRegistry.cpp", + "SOCKS5BytestreamProxy.cpp", + "SOCKS5BytestreamProxyFinder.cpp", "IBBSendSession.cpp", "IBBReceiveSession.cpp", + "FileTransferManager.cpp", + "FileTransferManagerImpl.cpp", + "IncrementalBytestreamHashCalculator.cpp", + "ConnectivityManager.cpp", ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) + +env.Append(UNITTEST_SOURCES = [ + File("UnitTest/SOCKS5BytestreamServerSessionTest.cpp"), + File("UnitTest/SOCKS5BytestreamClientSessionTest.cpp"), + File("UnitTest/IBBSendSessionTest.cpp"), + File("UnitTest/IBBReceiveSessionTest.cpp"), + File("UnitTest/IncomingJingleFileTransferTest.cpp"), + File("UnitTest/OutgoingJingleFileTransferTest.cpp"), + ]) diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp new file mode 100644 index 0000000..cd555e5 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "SOCKS5BytestreamClientSession.h" + +#include <boost/bind.hpp> + +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/Concat.h> +#include <Swiften/Base/Log.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/FileTransfer/BytestreamException.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Base/ByteArray.h> + +namespace Swift { + +SOCKS5BytestreamClientSession::SOCKS5BytestreamClientSession(boost::shared_ptr<Connection> connection, const HostAddressPort& addressPort, const std::string& destination, TimerFactory* timerFactory) : + connection(connection), addressPort(addressPort), destination(destination), state(Initial), chunkSize(131072) { + connection->onConnectFinished.connect(boost::bind(&SOCKS5BytestreamClientSession::handleConnectFinished, this, _1)); + connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamClientSession::handleDisconnected, this, _1)); + weFailedTimeout = timerFactory->createTimer(2000); + weFailedTimeout->onTick.connect(boost::bind(&SOCKS5BytestreamClientSession::handleWeFailedTimeout, this)); +} + +void SOCKS5BytestreamClientSession::start() { + assert(state == Initial); + SWIFT_LOG(debug) << "Trying to connect via TCP to " << addressPort.toString() << "." << std::endl; + weFailedTimeout->start(); + connection->connect(addressPort); +} + +void SOCKS5BytestreamClientSession::stop() { + connection->disconnect(); + connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); + connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + readBytestream.reset(); + state = Finished; +} + +void SOCKS5BytestreamClientSession::process() { + SWIFT_LOG(debug) << "unprocessedData.size(): " << unprocessedData.size() << std::endl; + ByteArray bndAddress; + switch(state) { + case Initial: + hello(); + break; + case Hello: + if (unprocessedData.size() > 1) { + unsigned char version = unprocessedData[0]; + unsigned char authMethod = unprocessedData[1]; + if (version != 5 || authMethod != 0) { + // signal failure to upper level + finish(true); + return; + } + unprocessedData.clear(); + authenticate(); + } + break; + case Authenticating: + if (unprocessedData.size() < 5) { + // need more data to start progressing + break; + } + if (unprocessedData[0] != '\x05') { + // wrong version + // disconnect & signal failure + finish(true); + break; + } + if (unprocessedData[1] != '\x00') { + // no success + // disconnect & signal failure + finish(true); + break; + } + if (unprocessedData[3] != '\x03') { + // we expect x'03' = DOMAINNAME here + // discconect & signal failure + finish(true); + break; + } + if (static_cast<size_t>(unprocessedData[4]) + 1 > unprocessedData.size() + 5) { + // complete domainname and port not available yet + break; + } + bndAddress = createByteArray(&vecptr(unprocessedData)[5], unprocessedData[4]); + if (unprocessedData[unprocessedData[4] + 5] != 0 && bndAddress == createByteArray(destination)) { + // we expect a 0 as port + // disconnect and fail + finish(true); + } + unprocessedData.clear(); + state = Ready; + SWIFT_LOG(debug) << "session ready" << std::endl; + // issue ready signal so the bytestream can be used for reading or writing + weFailedTimeout->stop(); + onSessionReady(false); + break; + case Ready: + SWIFT_LOG(debug) << "Received further data in Ready state." << std::endl; + break; + case Reading: + case Writing: + case Finished: + SWIFT_LOG(debug) << "Unexpected receive of data. Current state: " << state << std::endl; + SWIFT_LOG(debug) << "Data: " << Hexify::hexify(unprocessedData) << std::endl; + unprocessedData.clear(); + //assert(false); + } +} + +void SOCKS5BytestreamClientSession::hello() { + // Version 5, 1 auth method, No authentication + const SafeByteArray hello = createSafeByteArray("\x05\x01\x00", 3); + connection->write(hello); + state = Hello; +} + +void SOCKS5BytestreamClientSession::authenticate() { + SWIFT_LOG(debug) << std::endl; + SafeByteArray header = createSafeByteArray("\x05\x01\x00\x03", 4); + SafeByteArray message = header; + append(message, createSafeByteArray(destination.size())); + authenticateAddress = createByteArray(destination); + append(message, authenticateAddress); + append(message, createSafeByteArray("\x00\x00", 2)); // 2 byte for port + connection->write(message); + state = Authenticating; +} + +void SOCKS5BytestreamClientSession::startReceiving(boost::shared_ptr<WriteBytestream> writeStream) { + if (state == Ready) { + state = Reading; + writeBytestream = writeStream; + writeBytestream->write(unprocessedData); + onBytesReceived(unprocessedData.size()); + unprocessedData.clear(); + } else { + SWIFT_LOG(debug) << "Session isn't ready for transfer yet!" << std::endl; + } +} + +void SOCKS5BytestreamClientSession::startSending(boost::shared_ptr<ReadBytestream> readStream) { + if (state == Ready) { + state = Writing; + readBytestream = readStream; + connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); + sendData(); + } else { + SWIFT_LOG(debug) << "Session isn't ready for transfer yet!" << std::endl; + } +} + +HostAddressPort SOCKS5BytestreamClientSession::getAddressPort() const { + return addressPort; +} + +void SOCKS5BytestreamClientSession::sendData() { + if (!readBytestream->isFinished()) { + try { + boost::shared_ptr<ByteArray> dataToSend = readBytestream->read(chunkSize); + connection->write(createSafeByteArray(*dataToSend)); + onBytesSent(dataToSend->size()); + } + catch (const BytestreamException&) { + finish(true); + } + } + else { + finish(false); + } +} + +void SOCKS5BytestreamClientSession::finish(bool error) { + weFailedTimeout->stop(); + connection->disconnect(); + connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamClientSession::sendData, this)); + connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + readBytestream.reset(); + if (state == Initial || state == Hello || state == Authenticating) { + onSessionReady(true); + } + else { + state = Finished; + if (error) { + onFinished(boost::optional<FileTransferError>(FileTransferError::ReadError)); + } else { + onFinished(boost::optional<FileTransferError>()); + } + } +} + +void SOCKS5BytestreamClientSession::handleConnectFinished(bool error) { + if (error) { + SWIFT_LOG(debug) << "Failed to connect via TCP to " << addressPort.toString() << "." << std::endl; + finish(true); + } else { + SWIFT_LOG(debug) << "Successfully connected via TCP" << addressPort.toString() << "." << std::endl; + weFailedTimeout->start(); + connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamClientSession::handleDataRead, this, _1)); + process(); + } +} + +void SOCKS5BytestreamClientSession::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + SWIFT_LOG(debug) << "state: " << state << " data.size() = " << data->size() << std::endl; + if (state != Reading) { + append(unprocessedData, *data); + process(); + } + else { + writeBytestream->write(createByteArray(vecptr(*data), data->size())); + onBytesReceived(data->size()); + } +} + +void SOCKS5BytestreamClientSession::handleDisconnected(const boost::optional<Connection::Error>& error) { + SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; + if (error) { + finish(true); + } +} + +void SOCKS5BytestreamClientSession::handleWeFailedTimeout() { + SWIFT_LOG(debug) << "Failed due to timeout!" << std::endl; + finish(true); +} + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h new file mode 100644 index 0000000..ea45955 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/FileTransfer/FileTransferError.h> +#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/Timer.h> + +namespace Swift { + +class SOCKS5BytestreamRegistry; +class Connection; +class TimerFactory; + +/** + * A session which has been connected to a SOCKS5 server (requester). + * + */ +class SOCKS5BytestreamClientSession { +public: + enum State { + Initial, + Hello, + Authenticating, + Ready, + Writing, + Reading, + Finished, + }; + +public: + typedef boost::shared_ptr<SOCKS5BytestreamClientSession> ref; + +public: + SOCKS5BytestreamClientSession(boost::shared_ptr<Connection> connection, const HostAddressPort&, const std::string&, TimerFactory*); + + void start(); + void stop(); + + void startReceiving(boost::shared_ptr<WriteBytestream>); + void startSending(boost::shared_ptr<ReadBytestream>); + + HostAddressPort getAddressPort() const; + + boost::signal<void (bool /*error*/)> onSessionReady; + + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + boost::signal<void (int)> onBytesSent; + boost::signal<void (int)> onBytesReceived; + +private: + void process(); + void hello(); + void authenticate(); + + void handleConnectFinished(bool error); + void handleDataRead(boost::shared_ptr<SafeByteArray>); + void handleDisconnected(const boost::optional<Connection::Error>&); + void handleWeFailedTimeout(); + + void finish(bool error); + void sendData(); + +private: + boost::shared_ptr<Connection> connection; + HostAddressPort addressPort; + std::string destination; // hexify(SHA1(sessionID + requester + target)) + + State state; + int destinationPort; + + ByteArray unprocessedData; + ByteArray authenticateAddress; + + int chunkSize; + boost::shared_ptr<WriteBytestream> writeBytestream; + boost::shared_ptr<ReadBytestream> readBytestream; + + Timer::ref weFailedTimeout; +}; + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp new file mode 100644 index 0000000..9599fd1 --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxy.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "SOCKS5BytestreamProxy.h" + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/Base/Log.h> + +namespace Swift { + +SOCKS5BytestreamProxy::SOCKS5BytestreamProxy(ConnectionFactory *connFactory, TimerFactory *timeFactory) : connectionFactory(connFactory), timerFactory(timeFactory) { + +} + +void SOCKS5BytestreamProxy::addS5BProxy(S5BProxyRequest::ref proxy) { + localS5BProxies.push_back(proxy); +} + +const std::vector<S5BProxyRequest::ref>& SOCKS5BytestreamProxy::getS5BProxies() const { + return localS5BProxies; +} + +void SOCKS5BytestreamProxy::connectToProxies(const std::string& sessionID) { + SWIFT_LOG(debug) << "session ID: " << sessionID << std::endl; + ProxyJIDClientSessionMap clientSessions; + + foreach(S5BProxyRequest::ref proxy, localS5BProxies) { + boost::shared_ptr<Connection> conn = connectionFactory->createConnection(); + + boost::shared_ptr<SOCKS5BytestreamClientSession> session = boost::make_shared<SOCKS5BytestreamClientSession>(conn, proxy->getStreamHost().get().addressPort, sessionID, timerFactory); + clientSessions[proxy->getStreamHost().get().jid] = session; + session->start(); + } + + proxySessions[sessionID] = clientSessions; +} + +boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID) { + // checking parameters + if (proxySessions.find(sessionID) == proxySessions.end()) { + return boost::shared_ptr<SOCKS5BytestreamClientSession>(); + } + if (proxySessions[sessionID].find(proxyJID) == proxySessions[sessionID].end()) { + return boost::shared_ptr<SOCKS5BytestreamClientSession>(); + } + + // get active session + boost::shared_ptr<SOCKS5BytestreamClientSession> activeSession = proxySessions[sessionID][proxyJID]; + proxySessions[sessionID].erase(proxyJID); + + // close other sessions + foreach(const ProxyJIDClientSessionMap::value_type& myPair, proxySessions[sessionID]) { + myPair.second->stop(); + } + + proxySessions.erase(sessionID); + + return activeSession; +} + +boost::shared_ptr<SOCKS5BytestreamClientSession> SOCKS5BytestreamProxy::createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr) { + SOCKS5BytestreamClientSession::ref connection = boost::make_shared<SOCKS5BytestreamClientSession>(connectionFactory->createConnection(), addressPort, destAddr, timerFactory); + return connection; +} + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxy.h b/Swiften/FileTransfer/SOCKS5BytestreamProxy.h new file mode 100644 index 0000000..8f80cea --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxy.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> +#include <vector> + +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/TimerFactory.h> + +namespace Swift { + +/** + * - manages list of working S5B proxies + * - creates initial connections (for the candidates you provide) + */ +class SOCKS5BytestreamProxy { +public: + SOCKS5BytestreamProxy(ConnectionFactory*, TimerFactory*); + + void addS5BProxy(S5BProxyRequest::ref); + const std::vector<S5BProxyRequest::ref>& getS5BProxies() const; + + void connectToProxies(const std::string& sessionID); + boost::shared_ptr<SOCKS5BytestreamClientSession> getProxySessionAndCloseOthers(const JID& proxyJID, const std::string& sessionID); + + boost::shared_ptr<SOCKS5BytestreamClientSession> createSOCKS5BytestreamClientSession(HostAddressPort addressPort, const std::string& destAddr); + +private: + ConnectionFactory* connectionFactory; + TimerFactory* timerFactory; + + typedef std::map<JID, boost::shared_ptr<SOCKS5BytestreamClientSession> > ProxyJIDClientSessionMap; + std::map<std::string, ProxyJIDClientSessionMap> proxySessions; + + std::vector<S5BProxyRequest::ref> localS5BProxies; +}; + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp new file mode 100644 index 0000000..9d7505b --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Queries/IQRouter.h> + +namespace Swift { + +SOCKS5BytestreamProxyFinder::SOCKS5BytestreamProxyFinder(const JID& service, IQRouter *iqRouter) : service(service), iqRouter(iqRouter) { +} + +SOCKS5BytestreamProxyFinder::~SOCKS5BytestreamProxyFinder() { +} + +void SOCKS5BytestreamProxyFinder::start() { + serviceWalker = boost::make_shared<DiscoServiceWalker>(service, iqRouter); + serviceWalker->onServiceFound.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleServiceFound, this, _1, _2)); + serviceWalker->beginWalk(); +} + +void SOCKS5BytestreamProxyFinder::stop() { + serviceWalker->endWalk(); + serviceWalker->onServiceFound.disconnect(boost::bind(&SOCKS5BytestreamProxyFinder::handleServiceFound, this, _1, _2)); + serviceWalker.reset(); +} + +void SOCKS5BytestreamProxyFinder::sendBytestreamQuery(const JID& jid) { + S5BProxyRequest::ref proxyRequest = boost::make_shared<S5BProxyRequest>(); + boost::shared_ptr<GenericRequest<S5BProxyRequest> > request = boost::make_shared<GenericRequest<S5BProxyRequest> >(IQ::Get, jid, proxyRequest, iqRouter); + request->onResponse.connect(boost::bind(&SOCKS5BytestreamProxyFinder::handleProxyResponse, this, _1, _2)); + request->send(); +} + +void SOCKS5BytestreamProxyFinder::handleServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> discoInfo) { + if (discoInfo->hasFeature(DiscoInfo::Bytestream)) { + sendBytestreamQuery(jid); + } +} + +void SOCKS5BytestreamProxyFinder::handleProxyResponse(boost::shared_ptr<S5BProxyRequest> request, ErrorPayload::ref error) { + if (error) { + SWIFT_LOG(debug) << "ERROR" << std::endl; + } else { + if (request) { + onProxyFound(request); + } else { + //assert(false); + } + } +} + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h new file mode 100644 index 0000000..071e03a --- /dev/null +++ b/Swiften/FileTransfer/SOCKS5BytestreamProxyFinder.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Disco/DiscoServiceWalker.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Elements/S5BProxyRequest.h> + +namespace Swift { + +class JID; +class IQRouter; + +class SOCKS5BytestreamProxyFinder { +public: + SOCKS5BytestreamProxyFinder(const JID& service, IQRouter *iqRouter); + ~SOCKS5BytestreamProxyFinder(); + + void start(); + void stop(); + + boost::signal<void(boost::shared_ptr<S5BProxyRequest>)> onProxyFound; + +private: + void sendBytestreamQuery(const JID&); + + void handleServiceFound(const JID&, boost::shared_ptr<DiscoInfo>); + void handleProxyResponse(boost::shared_ptr<S5BProxyRequest>, ErrorPayload::ref); +private: + JID service; + IQRouter* iqRouter; + boost::shared_ptr<DiscoServiceWalker> serviceWalker; + std::vector<boost::shared_ptr<GenericRequest<S5BProxyRequest> > > requests; +}; + +} diff --git a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp index 7f889b1..ffc4298 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.cpp @@ -4,29 +4,69 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/SOCKS5BytestreamRegistry.h" +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Hexify.h> namespace Swift { SOCKS5BytestreamRegistry::SOCKS5BytestreamRegistry() { } -void SOCKS5BytestreamRegistry::addBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream) { - byteStreams[destination] = byteStream; +void SOCKS5BytestreamRegistry::addReadBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream) { + readBytestreams[destination] = byteStream; } -void SOCKS5BytestreamRegistry::removeBytestream(const std::string& destination) { - byteStreams.erase(destination); +void SOCKS5BytestreamRegistry::removeReadBytestream(const std::string& destination) { + readBytestreams.erase(destination); } -boost::shared_ptr<ReadBytestream> SOCKS5BytestreamRegistry::getBytestream(const std::string& destination) const { - BytestreamMap::const_iterator i = byteStreams.find(destination); - if (i != byteStreams.end()) { +boost::shared_ptr<ReadBytestream> SOCKS5BytestreamRegistry::getReadBytestream(const std::string& destination) const { + ReadBytestreamMap::const_iterator i = readBytestreams.find(destination); + if (i != readBytestreams.end()) { return i->second; } return boost::shared_ptr<ReadBytestream>(); } +void SOCKS5BytestreamRegistry::addWriteBytestream(const std::string& destination, boost::shared_ptr<WriteBytestream> byteStream) { + writeBytestreams[destination] = byteStream; +} + +void SOCKS5BytestreamRegistry::removeWriteBytestream(const std::string& destination) { + writeBytestreams.erase(destination); +} + +boost::shared_ptr<WriteBytestream> SOCKS5BytestreamRegistry::getWriteBytestream(const std::string& destination) const { + WriteBytestreamMap::const_iterator i = writeBytestreams.find(destination); + if (i != writeBytestreams.end()) { + return i->second; + } + return boost::shared_ptr<WriteBytestream>(); +} + +std::string SOCKS5BytestreamRegistry::generateSessionID() { + return idGenerator.generateID(); +} + +SOCKS5BytestreamServerSession* SOCKS5BytestreamRegistry::getConnectedSession(const std::string& destination) { + if (serverSessions.find(destination) != serverSessions.end()) { + return serverSessions[destination]; + } else { + SWIFT_LOG(debug) << "No active connction for stream ID " << destination << " found!" << std::endl; + return NULL; + } +} + +std::string SOCKS5BytestreamRegistry::getHostname(const std::string& sessionID, const JID& requester, const JID& target) { + return Hexify::hexify(SHA1::getHash(createSafeByteArray(sessionID + requester.toString() + target.toString()))); +} } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h index 7cee256..779aabb 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamRegistry.h @@ -7,23 +7,58 @@ #pragma once #include <boost/shared_ptr.hpp> -#include <map> +#include <map> #include <string> -#include "Swiften/FileTransfer/ReadBytestream.h" +#include <vector> +#include <set> + +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/Network/HostAddressPort.h> namespace Swift { class SOCKS5BytestreamRegistry { public: SOCKS5BytestreamRegistry(); - boost::shared_ptr<ReadBytestream> getBytestream(const std::string& destination) const; - void addBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream); - void removeBytestream(const std::string& destination); + boost::shared_ptr<ReadBytestream> getReadBytestream(const std::string& destination) const; + void addReadBytestream(const std::string& destination, boost::shared_ptr<ReadBytestream> byteStream); + void removeReadBytestream(const std::string& destination); + + boost::shared_ptr<WriteBytestream> getWriteBytestream(const std::string& destination) const; + void addWriteBytestream(const std::string& destination, boost::shared_ptr<WriteBytestream> byteStream); + void removeWriteBytestream(const std::string& destination); + + /** + * Generate a new session ID to use for new S5B streams. + */ + std::string generateSessionID(); + + /** + * Start an actual transfer. + */ + SOCKS5BytestreamServerSession* getConnectedSession(const std::string& destination); + + public: + static std::string getHostname(const std::string& sessionID, const JID& requester, const JID& target); private: - typedef std::map<std::string, boost::shared_ptr<ReadBytestream> > BytestreamMap; - BytestreamMap byteStreams; + friend class SOCKS5BytestreamServerSession; + + typedef std::map<std::string, boost::shared_ptr<ReadBytestream> > ReadBytestreamMap; + ReadBytestreamMap readBytestreams; + + typedef std::map<std::string, boost::shared_ptr<WriteBytestream> > WriteBytestreamMap; + WriteBytestreamMap writeBytestreams; + + std::map<std::string, SOCKS5BytestreamServerSession*> serverSessions; + + IDGenerator idGenerator; }; } - diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp index 9bc49ae..90fed7a 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServer.cpp @@ -4,17 +4,19 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/SOCKS5BytestreamServer.h" +#include <Swiften/FileTransfer/SOCKS5BytestreamServer.h> #include <boost/bind.hpp> -#include "Swiften/StringCodecs/Hexify.h" -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamServerSession.h" +#include <Swiften/Base/Log.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> namespace Swift { -SOCKS5BytestreamServer::SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer) : connectionServer(connectionServer) { +SOCKS5BytestreamServer::SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer, SOCKS5BytestreamRegistry* registry) : connectionServer(connectionServer), registry(registry) { } void SOCKS5BytestreamServer::start() { @@ -25,20 +27,20 @@ void SOCKS5BytestreamServer::stop() { connectionServer->onNewConnection.disconnect(boost::bind(&SOCKS5BytestreamServer::handleNewConnection, this, _1)); } -void SOCKS5BytestreamServer::addBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream) { - bytestreams.addBytestream(getSOCKSDestinationAddress(id, from, to), byteStream); +void SOCKS5BytestreamServer::addReadBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream) { + registry->addReadBytestream(getSOCKSDestinationAddress(id, from, to), byteStream); } -void SOCKS5BytestreamServer::removeBytestream(const std::string& id, const JID& from, const JID& to) { - bytestreams.removeBytestream(getSOCKSDestinationAddress(id, from, to)); +void SOCKS5BytestreamServer::removeReadBytestream(const std::string& id, const JID& from, const JID& to) { + registry->removeReadBytestream(getSOCKSDestinationAddress(id, from, to)); } std::string SOCKS5BytestreamServer::getSOCKSDestinationAddress(const std::string& id, const JID& from, const JID& to) { - return Hexify::hexify(SHA1::getHash(ByteArray(id + from.toString() + to.toString()))); + return Hexify::hexify(SHA1::getHash(createByteArray(id + from.toString() + to.toString()))); } void SOCKS5BytestreamServer::handleNewConnection(boost::shared_ptr<Connection> connection) { - boost::shared_ptr<SOCKS5BytestreamServerSession> session(new SOCKS5BytestreamServerSession(connection, &bytestreams)); + boost::shared_ptr<SOCKS5BytestreamServerSession> session(new SOCKS5BytestreamServerSession(connection, registry)); sessions.push_back(session); session->start(); } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServer.h b/Swiften/FileTransfer/SOCKS5BytestreamServer.h index d5a62bb..6bb598e 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServer.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServer.h @@ -9,26 +9,26 @@ #include <boost/shared_ptr.hpp> #include <map> -#include "Swiften/Network/ConnectionServer.h" +#include <Swiften/Network/ConnectionServer.h> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/FileTransfer/ReadBytestream.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamRegistry.h" +#include <Swiften/JID/JID.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> namespace Swift { class SOCKS5BytestreamServerSession; class SOCKS5BytestreamServer { public: - SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer); + SOCKS5BytestreamServer(boost::shared_ptr<ConnectionServer> connectionServer, SOCKS5BytestreamRegistry* registry); HostAddressPort getAddressPort() const; void start(); void stop(); - void addBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream); - void removeBytestream(const std::string& id, const JID& from, const JID& to); + void addReadBytestream(const std::string& id, const JID& from, const JID& to, boost::shared_ptr<ReadBytestream> byteStream); + void removeReadBytestream(const std::string& id, const JID& from, const JID& to); /*protected: boost::shared_ptr<ReadBytestream> getBytestream(const std::string& dest);*/ @@ -42,7 +42,7 @@ namespace Swift { friend class SOCKS5BytestreamServerSession; boost::shared_ptr<ConnectionServer> connectionServer; - SOCKS5BytestreamRegistry bytestreams; + SOCKS5BytestreamRegistry* registry; std::vector<boost::shared_ptr<SOCKS5BytestreamServerSession> > sessions; }; } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index 9951f7a..f660fda 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -4,17 +4,23 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/SOCKS5BytestreamServerSession.h" +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> #include <boost/bind.hpp> +#include <iostream> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamRegistry.h" -#include "Swiften/FileTransfer/BytestreamException.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/Concat.h> +#include <Swiften/Base/Log.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/BytestreamException.h> namespace Swift { -SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession(boost::shared_ptr<Connection> connection, SOCKS5BytestreamRegistry* bytestreams) : connection(connection), bytestreams(bytestreams), state(Initial), chunkSize(4096) { +SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession(boost::shared_ptr<Connection> connection, SOCKS5BytestreamRegistry* bytestreams) : connection(connection), bytestreams(bytestreams), state(Initial), chunkSize(131072) { + connection->onDisconnected.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); } SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { @@ -25,68 +31,111 @@ SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() { } void SOCKS5BytestreamServerSession::start() { + SWIFT_LOG(debug) << std::endl; connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); state = WaitingForAuthentication; } void SOCKS5BytestreamServerSession::stop() { - finish(false); + connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); + connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); + connection->disconnect(); + state = Finished; +} + +void SOCKS5BytestreamServerSession::startTransfer() { + if (state == ReadyForTransfer) { + if (readBytestream) { + state = WritingData; + connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); + sendData(); + } + else if(writeBytestream) { + state = ReadingData; + writeBytestream->write(unprocessedData); + onBytesReceived(unprocessedData.size()); + unprocessedData.clear(); + } + } else { + SWIFT_LOG(debug) << "Not ready for transfer!" << std::endl; + } } -void SOCKS5BytestreamServerSession::handleDataRead(const ByteArray& data) { - unprocessedData += data; - process(); +HostAddressPort SOCKS5BytestreamServerSession::getAddressPort() const { + return connection->getLocalAddress(); +} + +void SOCKS5BytestreamServerSession::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + if (state != ReadingData) { + append(unprocessedData, *data); + process(); + } else { + writeBytestream->write(createByteArray(vecptr(*data), data->size())); + onBytesReceived(data->size()); + } +} + +void SOCKS5BytestreamServerSession::handleDisconnected(const boost::optional<Connection::Error>& error) { + SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; + if (error) { + finish(true); + } } void SOCKS5BytestreamServerSession::process() { if (state == WaitingForAuthentication) { - if (unprocessedData.getSize() >= 2) { + if (unprocessedData.size() >= 2) { size_t authCount = unprocessedData[1]; size_t i = 2; - while (i < 2 + authCount && i < unprocessedData.getSize()) { + while (i < 2 + authCount && i < unprocessedData.size()) { // Skip authentication mechanism ++i; } if (i == 2 + authCount) { // Authentication message is complete - if (i != unprocessedData.getSize()) { - std::cerr << "SOCKS5BytestreamServerSession: Junk after authentication mechanism"; + if (i != unprocessedData.size()) { + SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; } unprocessedData.clear(); - connection->write(ByteArray("\x05\x00", 2)); + connection->write(createSafeByteArray("\x05\x00", 2)); state = WaitingForRequest; } } } else if (state == WaitingForRequest) { - if (unprocessedData.getSize() >= 5) { + if (unprocessedData.size() >= 5) { ByteArray requestID; size_t i = 5; size_t hostnameSize = unprocessedData[4]; - while (i < 5 + hostnameSize && i < unprocessedData.getSize()) { - requestID += unprocessedData[i]; + while (i < 5 + hostnameSize && i < unprocessedData.size()) { + requestID.push_back(unprocessedData[i]); ++i; } - // Skip the port: + // Skip the port: 2 byte large, one already skipped. Add one for comparison with size i += 2; - if (i >= unprocessedData.getSize()) { - if (i != unprocessedData.getSize()) { - std::cerr << "SOCKS5BytestreamServerSession: Junk after authentication mechanism"; + if (i <= unprocessedData.size()) { + if (i != unprocessedData.size()) { + SWIFT_LOG(debug) << "Junk after authentication mechanism" << std::endl; } - bytestream = bytestreams->getBytestream(requestID.toString()); - ByteArray result("\x05", 1); - result += bytestream ? 0x0 : 0x4; - result += ByteArray("\x00\x03", 2); - result += static_cast<char>(requestID.getSize()); - result += requestID + ByteArray("\x00\x00", 2); - if (!bytestream) { + unprocessedData.clear(); + std::string streamID = byteArrayToString(requestID); + readBytestream = bytestreams->getReadBytestream(streamID); + writeBytestream = bytestreams->getWriteBytestream(streamID); + SafeByteArray result = createSafeByteArray("\x05", 1); + result.push_back((readBytestream || writeBytestream) ? 0x0 : 0x4); + append(result, createByteArray("\x00\x03", 2)); + result.push_back(static_cast<char>(requestID.size())); + append(result, concat(requestID, createByteArray("\x00\x00", 2))); + if (!readBytestream && !writeBytestream) { + SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!" << std::endl; connection->write(result); finish(true); } else { - state = SendingData; - connection->onDataWritten.connect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); + SWIFT_LOG(deubg) << "Found " << (readBytestream ? "Readstream" : "Writestream") << ". Sent OK." << std::endl; connection->write(result); + bytestreams->serverSessions[streamID] = this; + state = ReadyForTransfer; } } } @@ -94,11 +143,13 @@ void SOCKS5BytestreamServerSession::process() { } void SOCKS5BytestreamServerSession::sendData() { - if (!bytestream->isFinished()) { + if (!readBytestream->isFinished()) { try { - connection->write(bytestream->read(chunkSize)); + SafeByteArray dataToSend = createSafeByteArray(*readBytestream->read(chunkSize)); + connection->write(dataToSend); + onBytesSent(dataToSend.size()); } - catch (const BytestreamException& e) { + catch (const BytestreamException&) { finish(true); } } @@ -110,9 +161,14 @@ void SOCKS5BytestreamServerSession::sendData() { void SOCKS5BytestreamServerSession::finish(bool error) { connection->onDataWritten.disconnect(boost::bind(&SOCKS5BytestreamServerSession::sendData, this)); connection->onDataRead.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDataRead, this, _1)); - bytestream.reset(); + connection->onDisconnected.disconnect(boost::bind(&SOCKS5BytestreamServerSession::handleDisconnected, this, _1)); + readBytestream.reset(); state = Finished; - onFinished(error); + if (error) { + onFinished(boost::optional<FileTransferError>(FileTransferError::PeerError)); + } else { + onFinished(boost::optional<FileTransferError>()); + } } } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h index f430f5d..4557a36 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h @@ -8,20 +8,27 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/FileTransfer/ReadBytestream.h" +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/FileTransfer/ReadBytestream.h> +#include <Swiften/FileTransfer/WriteBytestream.h> +#include <Swiften/FileTransfer/FileTransferError.h> namespace Swift { class SOCKS5BytestreamRegistry; class SOCKS5BytestreamServerSession { public: + typedef boost::shared_ptr<SOCKS5BytestreamServerSession> ref; + + public: enum State { Initial, WaitingForAuthentication, WaitingForRequest, - SendingData, + ReadyForTransfer, + ReadingData, + WritingData, Finished, }; @@ -35,12 +42,18 @@ namespace Swift { void start(); void stop(); - boost::signal<void (bool /* error */)> onFinished; + void startTransfer(); + HostAddressPort getAddressPort() const; + + boost::signal<void (boost::optional<FileTransferError>)> onFinished; + boost::signal<void (int)> onBytesSent; + boost::signal<void (int)> onBytesReceived; private: void finish(bool error); void process(); - void handleDataRead(const ByteArray&); + void handleDataRead(boost::shared_ptr<SafeByteArray>); + void handleDisconnected(const boost::optional<Connection::Error>&); void sendData(); private: @@ -49,6 +62,7 @@ namespace Swift { ByteArray unprocessedData; State state; int chunkSize; - boost::shared_ptr<ReadBytestream> bytestream; + boost::shared_ptr<ReadBytestream> readBytestream; + boost::shared_ptr<WriteBytestream> writeBytestream; }; } diff --git a/Swiften/FileTransfer/StreamInitiationRequest.h b/Swiften/FileTransfer/StreamInitiationRequest.h index f516d4b..658a8a9 100644 --- a/Swiften/FileTransfer/StreamInitiationRequest.h +++ b/Swiften/FileTransfer/StreamInitiationRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/StreamInitiation.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/StreamInitiation.h> namespace Swift { @@ -19,8 +19,15 @@ namespace Swift { return ref(new StreamInitiationRequest(jid, payload, router)); } + static ref create(const JID& from, const JID& to, boost::shared_ptr<StreamInitiation> payload, IQRouter* router) { + return ref(new StreamInitiationRequest(from, to, payload, router)); + } + private: StreamInitiationRequest(const JID& jid, boost::shared_ptr<StreamInitiation> payload, IQRouter* router) : GenericRequest<StreamInitiation>(IQ::Set, jid, payload, router) { } + + StreamInitiationRequest(const JID& from, const JID& to, boost::shared_ptr<StreamInitiation> payload, IQRouter* router) : GenericRequest<StreamInitiation>(IQ::Set, from, to, payload, router) { + } }; } diff --git a/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h new file mode 100644 index 0000000..ae06cd3 --- /dev/null +++ b/Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> +#include <boost/filesystem.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/FileTransfer/FileTransferManager.h> + +namespace Swift { + class DummyFileTransferManager : public FileTransferManager { + public: + DummyFileTransferManager() : FileTransferManager() { + } + + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const boost::filesystem::path&, const std::string&, boost::shared_ptr<ReadBytestream>) { + return OutgoingFileTransfer::ref(); + } + + virtual OutgoingFileTransfer::ref createOutgoingFileTransfer(const JID&, const std::string&, const std::string&, const boost::uintmax_t, const boost::posix_time::ptime&, boost::shared_ptr<ReadBytestream>) { + return OutgoingFileTransfer::ref(); + } + + virtual void startListeningOnPort(int) { + } + + virtual void addS5BProxy(boost::shared_ptr<S5BProxyRequest>) { + } + + }; +} diff --git a/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp new file mode 100644 index 0000000..c62636d --- /dev/null +++ b/Swiften/FileTransfer/UnitTest/IBBReceiveSessionTest.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <vector> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/FileTransfer/IBBReceiveSession.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> + +using namespace Swift; + +class IBBReceiveSessionTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IBBReceiveSessionTest); + CPPUNIT_TEST(testOpen); + CPPUNIT_TEST(testReceiveData); + CPPUNIT_TEST(testReceiveMultipleData); + CPPUNIT_TEST(testReceiveDataForOtherSession); + CPPUNIT_TEST(testReceiveDataOutOfOrder); + CPPUNIT_TEST(testReceiveLastData); + CPPUNIT_TEST(testReceiveClose); + CPPUNIT_TEST(testStopWhileActive); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + stanzaChannel = new DummyStanzaChannel(); + iqRouter = new IQRouter(stanzaChannel); + finished = false; + } + + void tearDown() { + delete iqRouter; + delete stanzaChannel; + } + + void testOpen() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(0, "id-open")); + CPPUNIT_ASSERT(!finished); + + testling->stop(); + } + + void testReceiveData() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(1, "id-a")); + CPPUNIT_ASSERT(createByteArray("abc") == receivedData); + CPPUNIT_ASSERT(!finished); + + testling->stop(); + } + + void testReceiveMultipleData() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, createByteArray("def")), "foo@bar.com/baz", "id-b")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); + CPPUNIT_ASSERT(createByteArray("abcdef") == receivedData); + CPPUNIT_ASSERT(!finished); + + testling->stop(); + } + + void testReceiveDataForOtherSession() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("othersession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + + CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(1, "id-a")); + + testling->stop(); + } + + void testReceiveDataOutOfOrder() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("def")), "foo@bar.com/baz", "id-b")); + + CPPUNIT_ASSERT(stanzaChannel->isErrorAtIndex(2, "id-b")); + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(error); + + testling->stop(); + } + + void testReceiveLastData() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession", 6)); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 1, createByteArray("def")), "foo@bar.com/baz", "id-b")); + + CPPUNIT_ASSERT(stanzaChannel->isResultAtIndex(2, "id-b")); + CPPUNIT_ASSERT(createByteArray("abcdef") == receivedData); + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(!error); + + testling->stop(); + } + + void testReceiveClose() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBClose("mysession"), "foo@bar.com/baz", "id-close")); + + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(error); + + testling->stop(); + } + + void testStopWhileActive() { + boost::shared_ptr<IBBReceiveSession> testling(createSession("foo@bar.com/baz", "mysession")); + testling->start(); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + + testling->stop(); + + CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set)); + IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>(); + CPPUNIT_ASSERT_EQUAL(IBB::Close, ibb->getAction()); + CPPUNIT_ASSERT_EQUAL(std::string("mysession"), ibb->getStreamID()); + CPPUNIT_ASSERT(finished); + CPPUNIT_ASSERT(!error); + } + + private: + IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { + IQ::ref request = IQ::createRequest(IQ::Set, JID("baz@fum.com/dum"), id, ibb); + request->setFrom(from); + return request; + } + + IBBReceiveSession* createSession(const std::string& from, const std::string& id, size_t size = 0x1000) { + IBBReceiveSession* session = new IBBReceiveSession(id, JID(from), JID(), size, iqRouter); + session->onDataReceived.connect(boost::bind(&IBBReceiveSessionTest::handleDataReceived, this, _1)); + session->onFinished.connect(boost::bind(&IBBReceiveSessionTest::handleFinished, this, _1)); + return session; + } + + + void handleFinished(boost::optional<FileTransferError> error) { + finished = true; + this->error = error; + } + + void handleDataReceived(const std::vector<unsigned char>& data) { + receivedData.insert(receivedData.end(), data.begin(), data.end()); + } + + private: + DummyStanzaChannel* stanzaChannel; + IQRouter* iqRouter; + bool finished; + boost::optional<FileTransferError> error; + std::vector<unsigned char> receivedData; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IBBReceiveSessionTest); diff --git a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp index e89ef93..d12f99e 100644 --- a/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IBBSendSessionTest.cpp @@ -4,17 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" - #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <vector> #include <boost/bind.hpp> -#include "Swiften/FileTransfer/IBBSendSession.h" -#include "Swiften/FileTransfer/ByteArrayReadBytestream.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Client/DummyStanzaChannel.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/FileTransfer/IBBSendSession.h> +#include <Swiften/FileTransfer/ByteArrayReadBytestream.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; @@ -27,13 +26,19 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_TEST(testErrorResponseFinishesWithError); CPPUNIT_TEST(testStopDuringSessionCloses); CPPUNIT_TEST(testStopAfterFinishedDoesNotClose); + CPPUNIT_TEST(testDataStreamPauseStopsSendingData); + CPPUNIT_TEST(testDataStreamResumeAfterPauseSendsData); + CPPUNIT_TEST(testDataStreamResumeBeforePauseDoesNotSendData); + CPPUNIT_TEST(testDataStreamResumeAfterResumeDoesNotSendData); + CPPUNIT_TEST_SUITE_END(); public: void setUp() { stanzaChannel = new DummyStanzaChannel(); iqRouter = new IQRouter(stanzaChannel); - bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg"))); + bytestream = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(createByteArray("abcdefg"))); + finished = false; } void tearDown() { @@ -42,7 +47,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { } void testStart() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(1234); testling->start(); @@ -56,7 +61,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { } void testStart_ResponseStartsSending() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(3); testling->start(); @@ -66,13 +71,13 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(1, JID("foo@bar.com/baz"), IQ::Set)); IBB::ref ibb = stanzaChannel->sentStanzas[1]->getPayload<IBB>(); CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction()); - CPPUNIT_ASSERT_EQUAL(ByteArray("abc"), ibb->getData()); + CPPUNIT_ASSERT(createByteArray("abc") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(0, ibb->getSequenceNumber()); CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID()); } void testResponseContinuesSending() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(3); testling->start(); stanzaChannel->onIQReceived(createIBBResult()); @@ -82,13 +87,13 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(stanzaChannel->isRequestAtIndex<IBB>(2, JID("foo@bar.com/baz"), IQ::Set)); IBB::ref ibb = stanzaChannel->sentStanzas[2]->getPayload<IBB>(); CPPUNIT_ASSERT_EQUAL(IBB::Data, ibb->getAction()); - CPPUNIT_ASSERT_EQUAL(ByteArray("def"), ibb->getData()); + CPPUNIT_ASSERT(createByteArray("def") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(1, ibb->getSequenceNumber()); CPPUNIT_ASSERT_EQUAL(std::string("myid"), ibb->getStreamID()); } void testRespondToAllFinishes() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(3); testling->start(); stanzaChannel->onIQReceived(createIBBResult()); @@ -101,7 +106,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { } void testErrorResponseFinishesWithError() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(3); testling->start(); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); @@ -111,7 +116,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { } void testStopDuringSessionCloses() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(3); testling->start(); testling->stop(); @@ -126,7 +131,7 @@ class IBBSendSessionTest : public CppUnit::TestFixture { } void testStopAfterFinishedDoesNotClose() { - std::auto_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); testling->setBlockSize(16); testling->start(); stanzaChannel->onIQReceived(createIBBResult()); @@ -137,15 +142,74 @@ class IBBSendSessionTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); } - + + void testDataStreamPauseStopsSendingData() { + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + bytestream->setDataComplete(false); + testling->setBlockSize(3); + testling->start(); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + + CPPUNIT_ASSERT(!finished); + CPPUNIT_ASSERT(!error); + + CPPUNIT_ASSERT_EQUAL(4, static_cast<int>(stanzaChannel->sentStanzas.size())); + } + + void testDataStreamResumeAfterPauseSendsData() { + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + bytestream->setDataComplete(false); + testling->setBlockSize(3); + testling->start(); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + + bytestream->addData(createByteArray("xyz")); + + CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(stanzaChannel->sentStanzas.size())); + } + + void testDataStreamResumeBeforePauseDoesNotSendData() { + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + bytestream->setDataComplete(false); + testling->setBlockSize(3); + testling->start(); + stanzaChannel->onIQReceived(createIBBResult()); + + bytestream->addData(createByteArray("xyz")); + + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); + } + + void testDataStreamResumeAfterResumeDoesNotSendData() { + boost::shared_ptr<IBBSendSession> testling = createSession("foo@bar.com/baz"); + bytestream->setDataComplete(false); + testling->setBlockSize(3); + testling->start(); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + stanzaChannel->onIQReceived(createIBBResult()); + + bytestream->addData(createByteArray("xyz")); + bytestream->addData(createByteArray("xuv")); + + CPPUNIT_ASSERT_EQUAL(5, static_cast<int>(stanzaChannel->sentStanzas.size())); + } + private: IQ::ref createIBBResult() { return IQ::createResult(JID("baz@fum.com/dum"), stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size()-1]->getTo(), stanzaChannel->sentStanzas[stanzaChannel->sentStanzas.size()-1]->getID(), boost::shared_ptr<IBB>()); } private: - std::auto_ptr<IBBSendSession> createSession(const std::string& to) { - std::auto_ptr<IBBSendSession> session(new IBBSendSession("myid", JID(to), bytestream, iqRouter)); + boost::shared_ptr<IBBSendSession> createSession(const std::string& to) { + boost::shared_ptr<IBBSendSession> session(new IBBSendSession("myid", JID(), JID(to), bytestream, iqRouter)); session->onFinished.connect(boost::bind(&IBBSendSessionTest::handleFinished, this, _1)); return session; } diff --git a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp new file mode 100644 index 0000000..4c6ae72 --- /dev/null +++ b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Elements/IBB.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> +#include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> +#include <Swiften/Jingle/FakeJingleSession.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/DummyConnectionFactory.h> +#include <Swiften/Network/PlatformNATTraversalWorker.h> +#include <Swiften/Queries/IQRouter.h> + +#include <iostream> + +using namespace Swift; +using namespace boost; + +class FakeRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { + void addRemoteTransportCandidates(JingleTransportPayload::ref cand) { + candidate = cand; + } + + void selectCandidate() { + boost::shared_ptr<JingleS5BTransportPayload> payload = make_shared<JingleS5BTransportPayload>(); + payload->setCandidateError(true); + payload->setSessionID(candidate->getSessionID()); + onRemoteTransportCandidateSelectFinished(payload); + } + + void setMinimumPriority(int) { + + } + + bool isActualCandidate(JingleTransportPayload::ref) { + return false; + } + + int getPriority(JingleTransportPayload::ref) { + return 0; + } + + JingleTransport::ref selectTransport(JingleTransportPayload::ref) { + return JingleTransport::ref(); + } + +private: + JingleTransportPayload::ref candidate; +}; + +class FakeRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { +public: + virtual ~FakeRemoteJingleTransportCandidateSelectorFactory() { + + } + + virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() { + return new FakeRemoteJingleTransportCandidateSelector(); + } +}; + +class FakeLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { +public: + virtual void generateLocalTransportCandidates(JingleTransportPayload::ref payload) { + JingleS5BTransportPayload::ref payL = make_shared<JingleS5BTransportPayload>(); + payL->setSessionID(payload->getSessionID()); + onLocalTransportCandidatesGenerated(payL); + } + + void emitonLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { + onLocalTransportCandidatesGenerated(payload); + } + + virtual bool isActualCandidate(JingleTransportPayload::ref) { + return false; + } + + virtual int getPriority(JingleTransportPayload::ref) { + return 0; + } + + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) { + return JingleTransport::ref(); + } +}; + +class FakeLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory { +public: + virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() { + return new FakeLocalJingleTransportCandidateGenerator(); + } +}; + +class IncomingJingleFileTransferTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(IncomingJingleFileTransferTest); + CPPUNIT_TEST(test_AcceptOnyIBBSendsSessionAccept); + CPPUNIT_TEST(test_OnlyIBBTransferReceiveWorks); + CPPUNIT_TEST(test_AcceptFailingS5BFallsBackToIBB); + CPPUNIT_TEST_SUITE_END(); +public: + shared_ptr<IncomingJingleFileTransfer> createTestling() { + JID ourJID("our@jid.org/full"); + return make_shared<IncomingJingleFileTransfer>(ourJID, shared_ptr<JingleSession>(fakeJingleSession), jingleContentPayload, fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, bytestreamRegistry, bytestreamProxy, timerFactory); + } + + IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { + IQ::ref request = IQ::createRequest(IQ::Set, JID("foo@bar.com/baz"), id, ibb); + request->setFrom(from); + return request; + } + + void setUp() { + eventLoop = new DummyEventLoop(); + fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession"); + jingleContentPayload = make_shared<JingleContentPayload>(); + fakeRJTCSF = make_shared<FakeRemoteJingleTransportCandidateSelectorFactory>(); + fakeLJTCF = make_shared<FakeLocalJingleTransportCandidateGeneratorFactory>(); + stanzaChannel = new DummyStanzaChannel(); + iqRouter = new IQRouter(stanzaChannel); + bytestreamRegistry = new SOCKS5BytestreamRegistry(); + timerFactory = new DummyTimerFactory(); + connectionFactory = new DummyConnectionFactory(eventLoop); + bytestreamProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + } + + void tearDown() { + delete bytestreamProxy; + delete connectionFactory; + delete timerFactory; + delete bytestreamRegistry; + delete iqRouter; + delete stanzaChannel; + delete eventLoop; + } + + // Tests whether IncomingJingleFileTransfer would accept a IBB only file transfer. + void test_AcceptOnyIBBSendsSessionAccept() { + //1. create your test incoming file transfer + shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); + desc->addOffer(StreamInitiationFileInfo("foo.txt", "", 10)); + jingleContentPayload->addDescription(desc); + JingleIBBTransportPayload::ref tpRef = make_shared<JingleIBBTransportPayload>(); + tpRef->setSessionID("mysession"); + jingleContentPayload->addTransport(tpRef); + + shared_ptr<IncomingJingleFileTransfer> fileTransfer = createTestling(); + + //2. do 'accept' on a dummy writebytestream (you'll have to look if there already is one) + shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>(); + fileTransfer->accept(byteStream); + + // check whether accept has been called + getCall<FakeJingleSession::AcceptCall>(0); + } + + void test_OnlyIBBTransferReceiveWorks() { + //1. create your test incoming file transfer + shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); + desc->addOffer(StreamInitiationFileInfo("file.txt", "", 10)); + jingleContentPayload->addDescription(desc); + JingleIBBTransportPayload::ref tpRef = make_shared<JingleIBBTransportPayload>(); + tpRef->setSessionID("mysession"); + jingleContentPayload->addTransport(tpRef); + + shared_ptr<IncomingJingleFileTransfer> fileTransfer = createTestling(); + + //2. do 'accept' on a dummy writebytestream (you'll have to look if there already is one) + shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>(); + fileTransfer->accept(byteStream); + + // check whether accept has been called + getCall<FakeJingleSession::AcceptCall>(0); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + CPPUNIT_ASSERT(createByteArray("abc") == byteStream->getData()); + } + + void test_AcceptFailingS5BFallsBackToIBB() { + //1. create your test incoming file transfer + addFileTransferDescription(); + + // add SOCKS5BytestreamTransportPayload + JingleS5BTransportPayload::ref payLoad = addJingleS5BPayload(); + + shared_ptr<IncomingJingleFileTransfer> fileTransfer = createTestling(); + + //2. do 'accept' on a dummy writebytestream (you'll have to look if there already is one) + shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>(); + fileTransfer->accept(byteStream); + + // check whether accept has been called + FakeJingleSession::AcceptCall acceptCall = getCall<FakeJingleSession::AcceptCall>(0); + CPPUNIT_ASSERT_EQUAL(payLoad->getSessionID(), acceptCall.payload->getSessionID()); + + // check for candidate error + FakeJingleSession::InfoTransportCall infoTransportCall = getCall<FakeJingleSession::InfoTransportCall>(1); + JingleS5BTransportPayload::ref s5bPayload = dynamic_pointer_cast<JingleS5BTransportPayload>(infoTransportCall.payload); + CPPUNIT_ASSERT(s5bPayload->hasCandidateError()); + + // indicate transport replace (Romeo) + fakeJingleSession->onTransportReplaceReceived(getContentID(), addJingleIBBPayload()); + + FakeJingleSession::AcceptTransportCall acceptTransportCall = getCall<FakeJingleSession::AcceptTransportCall>(2); + + // send a bit of data + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBOpen("mysession", 0x10), "foo@bar.com/baz", "id-open")); + stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); + CPPUNIT_ASSERT(createByteArray("abc") == byteStream->getData()); + } + + void test_S5BTransferReceiveTest() { + addFileTransferDescription(); + JingleS5BTransportPayload::ref payLoad = addJingleS5BPayload(); + } + +private: + void addFileTransferDescription() { + shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); + desc->addOffer(StreamInitiationFileInfo("file.txt", "", 10)); + jingleContentPayload->addDescription(desc); + } + + shared_ptr<JingleS5BTransportPayload> addJingleS5BPayload() { + JingleS5BTransportPayload::ref payLoad = make_shared<JingleS5BTransportPayload>(); + payLoad->setSessionID("mysession"); + jingleContentPayload->addTransport(payLoad); + return payLoad; + } + + shared_ptr<JingleIBBTransportPayload> addJingleIBBPayload() { + JingleIBBTransportPayload::ref payLoad = make_shared<JingleIBBTransportPayload>(); + payLoad->setSessionID("mysession"); + jingleContentPayload->addTransport(payLoad); + return payLoad; + } + + JingleContentID getContentID() const { + return JingleContentID(jingleContentPayload->getName(), jingleContentPayload->getCreator()); + } + + template <typename T> T getCall(int i) const { + size_t index = static_cast<size_t>(i); + CPPUNIT_ASSERT(index < fakeJingleSession->calledCommands.size()); + T* cmd = boost::get<T>(&fakeJingleSession->calledCommands[index]); + CPPUNIT_ASSERT(cmd); + return *cmd; + } + +private: + EventLoop* eventLoop; + FakeJingleSession* fakeJingleSession; + shared_ptr<JingleContentPayload> jingleContentPayload; + shared_ptr<FakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF; + shared_ptr<FakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF; + DummyStanzaChannel* stanzaChannel; + IQRouter* iqRouter; + SOCKS5BytestreamRegistry* bytestreamRegistry; + DummyConnectionFactory* connectionFactory; + SOCKS5BytestreamProxy* bytestreamProxy; + DummyTimerFactory* timerFactory; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(IncomingJingleFileTransferTest); diff --git a/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp new file mode 100644 index 0000000..0c324bf --- /dev/null +++ b/Swiften/FileTransfer/UnitTest/OutgoingJingleFileTransferTest.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/bind.hpp> +#include <boost/optional.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/FileTransfer/OutgoingJingleFileTransfer.h> +#include <Swiften/Jingle/FakeJingleSession.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelectorFactory.h> +#include <Swiften/FileTransfer/RemoteJingleTransportCandidateSelector.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGeneratorFactory.h> +#include <Swiften/FileTransfer/LocalJingleTransportCandidateGenerator.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/FileTransfer/ByteArrayReadBytestream.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamProxy.h> + +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/IBB.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/IDGenerator.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/PlatformNATTraversalWorker.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/Network/DummyConnection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/DummyConnectionFactory.h> + +#include <Swiften/Base/Log.h> + +#include <iostream> + +using namespace Swift; + +class OFakeRemoteJingleTransportCandidateSelector : public RemoteJingleTransportCandidateSelector { + void addRemoteTransportCandidates(JingleTransportPayload::ref cand) { + candidate = cand; + } + + void selectCandidate() { + JingleS5BTransportPayload::ref payload = boost::make_shared<JingleS5BTransportPayload>(); + payload->setCandidateError(true); + payload->setSessionID(candidate->getSessionID()); + onRemoteTransportCandidateSelectFinished(payload); + } + + void setMinimumPriority(int) { + + } + + bool isActualCandidate(JingleTransportPayload::ref) { + return false; + } + + int getPriority(JingleTransportPayload::ref) { + return 0; + } + + JingleTransport::ref selectTransport(JingleTransportPayload::ref) { + return JingleTransport::ref(); + } + +private: + JingleTransportPayload::ref candidate; +}; + +class OFakeRemoteJingleTransportCandidateSelectorFactory : public RemoteJingleTransportCandidateSelectorFactory { +public: + virtual ~OFakeRemoteJingleTransportCandidateSelectorFactory() { + + } + + virtual RemoteJingleTransportCandidateSelector* createCandidateSelector() { + return new OFakeRemoteJingleTransportCandidateSelector(); + } +}; + +class OFakeLocalJingleTransportCandidateGenerator : public LocalJingleTransportCandidateGenerator { +public: + virtual void generateLocalTransportCandidates(JingleTransportPayload::ref /* payload */) { + //JingleTransportPayload::ref payL = make_shared<JingleTransportPayload>(); + //payL->setSessionID(payload->getSessionID()); + JingleS5BTransportPayload::ref payL = boost::make_shared<JingleS5BTransportPayload>(); + + onLocalTransportCandidatesGenerated(payL); + } + + void emitonLocalTransportCandidatesGenerated(JingleTransportPayload::ref payload) { + onLocalTransportCandidatesGenerated(payload); + } + + virtual bool isActualCandidate(JingleTransportPayload::ref) { + return false; + } + + virtual int getPriority(JingleTransportPayload::ref) { + return 0; + } + + virtual JingleTransport::ref selectTransport(JingleTransportPayload::ref) { + return JingleTransport::ref(); + } +}; + +class OFakeLocalJingleTransportCandidateGeneratorFactory : public LocalJingleTransportCandidateGeneratorFactory { +public: + virtual LocalJingleTransportCandidateGenerator* createCandidateGenerator() { + return new OFakeLocalJingleTransportCandidateGenerator(); + } +}; + +class OutgoingJingleFileTransferTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(OutgoingJingleFileTransferTest); + CPPUNIT_TEST(test_SendSessionInitiateOnStart); + CPPUNIT_TEST(test_IBBStartsAfterSendingSessionAccept); + CPPUNIT_TEST(test_ReceiveSessionTerminateAfterSessionInitiate); + CPPUNIT_TEST_SUITE_END(); + + class FTStatusHelper { + public: + bool finishedCalled; + FileTransferError::Type error; + void handleFileTransferFinished(boost::optional<FileTransferError> error) { + finishedCalled = true; + if (error.is_initialized()) this->error = error.get().getType(); + } + }; +public: + + boost::shared_ptr<OutgoingJingleFileTransfer> createTestling() { + JID to("test@foo.com/bla"); + StreamInitiationFileInfo fileInfo; + fileInfo.setDescription("some file"); + fileInfo.setName("test.bin"); + fileInfo.setHash("asdjasdas"); + fileInfo.setSize(1024 * 1024); + return boost::shared_ptr<OutgoingJingleFileTransfer>(new OutgoingJingleFileTransfer(boost::shared_ptr<JingleSession>(fakeJingleSession), fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, idGen, JID(), to, stream, fileInfo, s5bRegistry, s5bProxy)); + } + + IQ::ref createIBBRequest(IBB::ref ibb, const JID& from, const std::string& id) { + IQ::ref request = IQ::createRequest(IQ::Set, JID("foo@bar.com/baz"), id, ibb); + request->setFrom(from); + return request; + } + + void setUp() { + fakeJingleSession = new FakeJingleSession("foo@bar.com/baz", "mysession"); + jingleContentPayload = boost::make_shared<JingleContentPayload>(); + fakeRJTCSF = boost::make_shared<OFakeRemoteJingleTransportCandidateSelectorFactory>(); + fakeLJTCF = boost::make_shared<OFakeLocalJingleTransportCandidateGeneratorFactory>(); + stanzaChannel = new DummyStanzaChannel(); + iqRouter = new IQRouter(stanzaChannel); + eventLoop = new DummyEventLoop(); + timerFactory = new DummyTimerFactory(); + connectionFactory = new DummyConnectionFactory(eventLoop); + s5bRegistry = new SOCKS5BytestreamRegistry(); + s5bProxy = new SOCKS5BytestreamProxy(connectionFactory, timerFactory); + + data.clear(); + for (int n=0; n < 1024 * 1024; ++n) { + data.push_back(34); + } + + stream = boost::make_shared<ByteArrayReadBytestream>(data); + + idGen = new IDGenerator(); + } + + void tearDown() { + delete idGen; + delete s5bRegistry; + delete connectionFactory; + delete timerFactory; + delete eventLoop; + delete iqRouter; + delete stanzaChannel; + } + + + void test_SendSessionInitiateOnStart() { + boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling(); + transfer->start(); + FakeJingleSession::InitiateCall call = getCall<FakeJingleSession::InitiateCall>(0); + JingleFileTransferDescription::ref description = boost::dynamic_pointer_cast<JingleFileTransferDescription>(call.description); + CPPUNIT_ASSERT(description); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), description->getOffers().size()); + CPPUNIT_ASSERT(static_cast<size_t>(1048576) == description->getOffers()[0].getSize()); + + JingleS5BTransportPayload::ref transport = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(call.payload); + CPPUNIT_ASSERT(transport); + } + + void test_IBBStartsAfterSendingSessionAccept() { + boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling(); + transfer->start(); + + FakeJingleSession::InitiateCall call = getCall<FakeJingleSession::InitiateCall>(0); + // FIXME: we initiate with SOCSK5 now and not IBB, needs to be fixed. + /* + fakeJingleSession->onSessionAcceptReceived(call.id, call.description, call.payload); + IQ::ref iqOpenStanza = stanzaChannel->getStanzaAtIndex<IQ>(0); + CPPUNIT_ASSERT(iqOpenStanza); + */ + } + + void test_ReceiveSessionTerminateAfterSessionInitiate() { + boost::shared_ptr<OutgoingJingleFileTransfer> transfer = createTestling(); + transfer->start(); + + getCall<FakeJingleSession::InitiateCall>(0); + + FTStatusHelper helper; + helper.finishedCalled = false; + transfer->onFinished.connect(bind(&FTStatusHelper::handleFileTransferFinished, &helper, _1)); + fakeJingleSession->onSessionTerminateReceived(JinglePayload::Reason(JinglePayload::Reason::Busy)); + CPPUNIT_ASSERT_EQUAL(true, helper.finishedCalled); + CPPUNIT_ASSERT(FileTransferError::PeerError == helper.error); + } + + +//TODO: some more testcases + +private: + void addFileTransferDescription() { + boost::shared_ptr<JingleFileTransferDescription> desc = boost::make_shared<JingleFileTransferDescription>(); + desc->addOffer(StreamInitiationFileInfo()); + jingleContentPayload->addDescription(desc); + } + + boost::shared_ptr<JingleS5BTransportPayload> addJingleS5BPayload() { + JingleS5BTransportPayload::ref payLoad = boost::make_shared<JingleS5BTransportPayload>(); + payLoad->setSessionID("mysession"); + jingleContentPayload->addTransport(payLoad); + return payLoad; + } + + boost::shared_ptr<JingleIBBTransportPayload> addJingleIBBPayload() { + JingleIBBTransportPayload::ref payLoad = boost::make_shared<JingleIBBTransportPayload>(); + payLoad->setSessionID("mysession"); + jingleContentPayload->addTransport(payLoad); + return payLoad; + } + + JingleContentID getContentID() const { + return JingleContentID(jingleContentPayload->getName(), jingleContentPayload->getCreator()); + } + + template <typename T> T getCall(int i) const { + size_t index = static_cast<size_t>(i); + CPPUNIT_ASSERT(index < fakeJingleSession->calledCommands.size()); + T* cmd = boost::get<T>(&fakeJingleSession->calledCommands[index]); + CPPUNIT_ASSERT(cmd); + return *cmd; + } + +private: + std::vector<unsigned char> data; + boost::shared_ptr<ByteArrayReadBytestream> stream; + FakeJingleSession* fakeJingleSession; + boost::shared_ptr<JingleContentPayload> jingleContentPayload; + boost::shared_ptr<OFakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF; + boost::shared_ptr<OFakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF; + DummyStanzaChannel* stanzaChannel; + IQRouter* iqRouter; + IDGenerator* idGen; + EventLoop *eventLoop; + SOCKS5BytestreamRegistry* s5bRegistry; + SOCKS5BytestreamProxy* s5bProxy; + DummyTimerFactory* timerFactory; + DummyConnectionFactory* connectionFactory; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(OutgoingJingleFileTransferTest); diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp new file mode 100644 index 0000000..527e0ca --- /dev/null +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamClientSessionTest.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/bind.hpp> +#include <boost/random/mersenne_twister.hpp> +#include <boost/random/uniform_int.hpp> +#include <boost/random/variate_generator.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Concat.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/StartStopper.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/FileTransfer/ByteArrayReadBytestream.h> +#include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamClientSession.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/DummyConnection.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/StringCodecs/Hexify.h> + +using namespace Swift; + +boost::mt19937 randomGen; + +class SOCKS5BytestreamClientSessionTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(SOCKS5BytestreamClientSessionTest); + CPPUNIT_TEST(testForSessionReady); + CPPUNIT_TEST(testErrorHandlingHello); + CPPUNIT_TEST(testErrorHandlingRequest); + CPPUNIT_TEST(testWriteBytestream); + CPPUNIT_TEST(testReadBytestream); + CPPUNIT_TEST_SUITE_END(); + + const HostAddressPort destinationAddressPort; + const std::string destination; + +public: + SOCKS5BytestreamClientSessionTest() : destinationAddressPort(HostAddressPort(HostAddress("127.0.0.1"), 8888)), + destination(SOCKS5BytestreamRegistry::getHostname("foo", JID("requester@example.com/test"), JID("target@example.com/test"))), eventLoop(NULL), timerFactory(NULL) { } + + void setUp() { + randomGen.seed(time(NULL)); + eventLoop = new DummyEventLoop(); + timerFactory = new DummyTimerFactory(); + connection = boost::make_shared<MockeryConnection>(failingPorts, true, eventLoop); + //connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1)); + //stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(createByteArray("abcdefg"))); +// connection->onDataRead.connect(boost::bind(&SOCKS5BytestreamClientSessionTest::handleDataRead, this, _1)); + } + + void tearDown() { + //connection.reset(); + delete timerFactory; + delete eventLoop; + } + + void testForSessionReady() { + TestHelper helper; + connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1)); + + SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory); + clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1)); + + clientSession->start(); + eventLoop->processEvents(); + CPPUNIT_ASSERT(createByteArray("\x05\x01\x00", 3) == helper.unprocessedInput); + + helper.unprocessedInput.clear(); + serverRespondHelloOK(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00\x03", 4), createByteArray(&helper.unprocessedInput[0], 4)); + CPPUNIT_ASSERT_EQUAL(createByteArray(destination.size()), createByteArray(helper.unprocessedInput[4])); + CPPUNIT_ASSERT_EQUAL(createByteArray(destination), createByteArray(&helper.unprocessedInput[5], destination.size())); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1)); + + helper.unprocessedInput.clear(); + serverRespondRequestOK(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled); + CPPUNIT_ASSERT_EQUAL(false, helper.sessionReadyError); + } + + void testErrorHandlingHello() { + TestHelper helper; + connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1)); + + SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory); + clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1)); + + clientSession->start(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00", 3), helper.unprocessedInput); + + helper.unprocessedInput.clear(); + serverRespondHelloAuthFail(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled); + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyError); + CPPUNIT_ASSERT_EQUAL(true, connection->disconnectCalled); + } + + void testErrorHandlingRequest() { + TestHelper helper; + connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1)); + + SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory); + clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1)); + + clientSession->start(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00", 3), helper.unprocessedInput); + + helper.unprocessedInput.clear(); + serverRespondHelloOK(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x05\x01\x00\x03", 4), createByteArray(&helper.unprocessedInput[0], 4)); + CPPUNIT_ASSERT_EQUAL(createByteArray(destination.size()), createByteArray(helper.unprocessedInput[4])); + CPPUNIT_ASSERT_EQUAL(createByteArray(destination), createByteArray(&helper.unprocessedInput[5], destination.size())); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x00", 1), createByteArray(&helper.unprocessedInput[5 + destination.size()], 1)); + + helper.unprocessedInput.clear(); + serverRespondRequestFail(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled); + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyError); + CPPUNIT_ASSERT_EQUAL(true, connection->disconnectCalled); + } + + void testWriteBytestream() { + TestHelper helper; + connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1)); + + SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory); + clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1)); + + clientSession->start(); + eventLoop->processEvents(); + + helper.unprocessedInput.clear(); + serverRespondHelloOK(); + eventLoop->processEvents(); + + helper.unprocessedInput.clear(); + serverRespondRequestOK(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled); + CPPUNIT_ASSERT_EQUAL(false, helper.sessionReadyError); + + boost::shared_ptr<ByteArrayWriteBytestream> output = boost::make_shared<ByteArrayWriteBytestream>(); + clientSession->startReceiving(output); + + ByteArray transferData = generateRandomByteArray(1024); + connection->onDataRead(createSafeByteArrayRef(transferData.data(), transferData.size())); + CPPUNIT_ASSERT_EQUAL(transferData, output->getData()); + } + + void testReadBytestream() { + TestHelper helper; + connection->onDataSent.connect(boost::bind(&TestHelper::handleConnectionDataWritten, &helper, _1)); + + SOCKS5BytestreamClientSession::ref clientSession = boost::make_shared<SOCKS5BytestreamClientSession>(connection, destinationAddressPort, destination, timerFactory); + clientSession->onSessionReady.connect(boost::bind(&TestHelper::handleSessionReady, &helper, _1)); + + clientSession->start(); + eventLoop->processEvents(); + + helper.unprocessedInput.clear(); + serverRespondHelloOK(); + eventLoop->processEvents(); + + helper.unprocessedInput.clear(); + serverRespondRequestOK(); + eventLoop->processEvents(); + CPPUNIT_ASSERT_EQUAL(true, helper.sessionReadyCalled); + CPPUNIT_ASSERT_EQUAL(false, helper.sessionReadyError); + + helper.unprocessedInput.clear(); + ByteArray transferData = generateRandomByteArray(1024); + boost::shared_ptr<ByteArrayReadBytestream> input = boost::make_shared<ByteArrayReadBytestream>(transferData); + clientSession->startSending(input); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(createByteArray(transferData.data(), transferData.size()), helper.unprocessedInput); + } + + + +private: + static ByteArray generateRandomByteArray(size_t len) { + boost::uniform_int<> dist(0, 255); + boost::variate_generator<boost::mt19937&, boost::uniform_int<> > randomByte(randomGen, dist); + ByteArray result(len); + for (size_t i=0; i < len; ++i ) { + result[i] = randomByte(); + } + return result; + } + + // Server responses + void serverRespondHelloOK() { + connection->onDataRead(createSafeByteArrayRef("\x05\00", 2)); + } + + void serverRespondHelloAuthFail() { + connection->onDataRead(createSafeByteArrayRef("\x05\xFF", 2)); + } + + void serverRespondRequestOK() { + boost::shared_ptr<SafeByteArray> dataToSend = createSafeByteArrayRef("\x05\x00\x00\x03", 4); + append(*dataToSend, createSafeByteArray(destination.size())); + append(*dataToSend, createSafeByteArray(destination)); + append(*dataToSend, createSafeByteArray("\x00", 1)); + connection->onDataRead(dataToSend); + } + + void serverRespondRequestFail() { + boost::shared_ptr<SafeByteArray> correctData = createSafeByteArrayRef("\x05\x00\x00\x03", 4); + append(*correctData, createSafeByteArray(destination.size())); + append(*correctData, createSafeByteArray(destination)); + append(*correctData, createSafeByteArray("\x00", 1)); + + boost::shared_ptr<SafeByteArray> dataToSend; + //ByteArray failingData = Hexify::unhexify("8417947d1d305c72c11520ea7d2c6e787396705e72c312c6ccc3f66613d7cae1b91b7ab48e8b59a17d559c15fb51"); + //append(dataToSend, failingData); + //SWIFT_LOG(debug) << "hexed: " << Hexify::hexify(failingData) << std::endl; + do { + ByteArray rndArray = generateRandomByteArray(correctData->size()); + dataToSend = createSafeByteArrayRef(rndArray.data(), rndArray.size()); + } while (*dataToSend == *correctData); + connection->onDataRead(dataToSend); + } + +private: + struct TestHelper { + TestHelper() : sessionReadyCalled(false), sessionReadyError(false) {} + ByteArray unprocessedInput; + bool sessionReadyCalled; + bool sessionReadyError; + + void handleConnectionDataWritten(const SafeByteArray& data) { + append(unprocessedInput, data); + //SWIFT_LOG(debug) << "unprocessedInput (" << unprocessedInput.size() << "): " << Hexify::hexify(unprocessedInput) << std::endl; + } + + void handleSessionReady(bool error) { + sessionReadyCalled = true; + sessionReadyError = error; + } + }; + + +private: + struct MockeryConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<MockeryConnection> { + public: + MockeryConnection(const std::vector<HostAddressPort>& failingPorts, bool isResponsive, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), isResponsive(isResponsive), disconnectCalled(false) {} + + void listen() { assert(false); } + void connect(const HostAddressPort& address) { + hostAddressPort = address; + if (isResponsive) { + bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end(); + eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail)); + } + } + + HostAddressPort getLocalAddress() const { return HostAddressPort(); } + void disconnect() { + disconnectCalled = true; + } + + void write(const SafeByteArray& data) { + eventLoop->postEvent(boost::ref(onDataWritten), shared_from_this()); + onDataSent(data); + } + + boost::signal<void (const SafeByteArray&)> onDataSent; + + EventLoop* eventLoop; + boost::optional<HostAddressPort> hostAddressPort; + std::vector<HostAddressPort> failingPorts; + bool isResponsive; + bool disconnectCalled; + }; + +private: + DummyEventLoop* eventLoop; + DummyTimerFactory* timerFactory; + boost::shared_ptr<MockeryConnection> connection; + const std::vector<HostAddressPort> failingPorts; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SOCKS5BytestreamClientSessionTest); diff --git a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp index c6d246d..4fe72c0 100644 --- a/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp +++ b/Swiften/FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp @@ -4,18 +4,19 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "Swiften/FileTransfer/SOCKS5BytestreamServerSession.h" -#include "Swiften/FileTransfer/ByteArrayReadBytestream.h" -#include "Swiften/FileTransfer/SOCKS5BytestreamRegistry.h" -#include "Swiften/Network/DummyConnection.h" -#include "Swiften/EventLoop/DummyEventLoop.h" -#include "Swiften/Base/StartStopper.h" +#include <Swiften/Base/Concat.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerSession.h> +#include <Swiften/FileTransfer/ByteArrayReadBytestream.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/Network/DummyConnection.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Base/StartStopper.h> using namespace Swift; @@ -33,122 +34,127 @@ class SOCKS5BytestreamServerSessionTest : public CppUnit::TestFixture { void setUp() { receivedDataChunks = 0; eventLoop = new DummyEventLoop(); + bytestreams = new SOCKS5BytestreamRegistry(); connection = boost::shared_ptr<DummyConnection>(new DummyConnection(eventLoop)); connection->onDataSent.connect(boost::bind(&SOCKS5BytestreamServerSessionTest::handleDataWritten, this, _1)); - stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(ByteArray("abcdefg"))); + stream1 = boost::shared_ptr<ByteArrayReadBytestream>(new ByteArrayReadBytestream(createByteArray("abcdefg"))); } void tearDown() { connection.reset(); + delete bytestreams; delete eventLoop; } void testAuthenticate() { - std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - receive(ByteArray("\x05\x02\x01\x02")); + receive(createSafeByteArray("\x05\x02\x01\x02")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData); + CPPUNIT_ASSERT(createByteArray("\x05\x00", 2) == receivedData); } void testAuthenticate_Chunked() { - std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - receive(ByteArray("\x05\x02\x01")); + receive(createSafeByteArray("\x05\x02\x01")); - CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.getSize())); - receive(ByteArray("\x01")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00", 2), receivedData); + CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(receivedData.size())); + receive(createSafeByteArray("\x01")); + CPPUNIT_ASSERT(createByteArray("\x05\x00", 2) == receivedData); } void testRequest() { - std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams.addBytestream("abcdef", stream1); + bytestreams->addReadBytestream("abcdef", stream1); authenticate(); - ByteArray hostname("abcdef"); - receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), ByteArray(receivedData.getData(), 13)); + ByteArray hostname(createByteArray("abcdef")); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + CPPUNIT_ASSERT(createByteArray("\x05\x00\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == createByteArray(&receivedData[0], 13)); } void testRequest_UnknownBytestream() { - std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); authenticate(); - ByteArray hostname("abcdef"); - receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.getSize() + hostname + ByteArray("\x00\x00", 2)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13), receivedData); + ByteArray hostname(createByteArray("abcdef")); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); + CPPUNIT_ASSERT(createByteArray("\x05\x04\x00\x03\x06\x61\x62\x63\x64\x65\x66\x00\x00", 13) == receivedData); } void testReceiveData() { - std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams.addBytestream("abcdef", stream1); + bytestreams->addReadBytestream("abcdef", stream1); authenticate(); request("abcdef"); eventLoop->processEvents(); + testling->startTransfer(); skipHeader("abcdef"); + eventLoop->processEvents(); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData); + CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData); CPPUNIT_ASSERT_EQUAL(2, receivedDataChunks); } void testReceiveData_Chunked() { - std::auto_ptr<SOCKS5BytestreamServerSession> testling(createSession()); + boost::shared_ptr<SOCKS5BytestreamServerSession> testling(createSession()); testling->setChunkSize(3); StartStopper<SOCKS5BytestreamServerSession> stopper(testling.get()); - bytestreams.addBytestream("abcdef", stream1); + bytestreams->addReadBytestream("abcdef", stream1); authenticate(); request("abcdef"); eventLoop->processEvents(); - + testling->startTransfer(); + eventLoop->processEvents(); skipHeader("abcdef"); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefg"), receivedData); + CPPUNIT_ASSERT(createByteArray("abcdefg") == receivedData); CPPUNIT_ASSERT_EQUAL(4, receivedDataChunks); } private: - void receive(const ByteArray& data) { + void receive(const SafeByteArray& data) { connection->receive(data); eventLoop->processEvents(); } void authenticate() { - receive(ByteArray("\x05\x02\x01\x02")); + receive(createSafeByteArray("\x05\x02\x01\x02")); receivedData.clear(); receivedDataChunks = 0; } void request(const std::string& hostname) { - receive(ByteArray("\x05\x01\x00\x03", 4) + hostname.size() + hostname + ByteArray("\x00\x00", 2)); + receive(concat(createSafeByteArray("\x05\x01\x00\x03", 4), createSafeByteArray(hostname.size()), createSafeByteArray(hostname), createSafeByteArray("\x00\x00", 2))); } void skipHeader(const std::string& hostname) { int headerSize = 7 + hostname.size(); - receivedData = ByteArray(receivedData.getData() + headerSize, receivedData.getSize() - headerSize); + receivedData = createByteArray(&receivedData[headerSize], receivedData.size() - headerSize); } - void handleDataWritten(const ByteArray& data) { - receivedData += data; + void handleDataWritten(const SafeByteArray& data) { + receivedData.insert(receivedData.end(), data.begin(), data.end()); receivedDataChunks++; } private: SOCKS5BytestreamServerSession* createSession() { - SOCKS5BytestreamServerSession* session = new SOCKS5BytestreamServerSession(connection, &bytestreams); + SOCKS5BytestreamServerSession* session = new SOCKS5BytestreamServerSession(connection, bytestreams); return session; } private: DummyEventLoop* eventLoop; - SOCKS5BytestreamRegistry bytestreams; + SOCKS5BytestreamRegistry* bytestreams; boost::shared_ptr<DummyConnection> connection; - ByteArray receivedData; + std::vector<unsigned char> receivedData; int receivedDataChunks; boost::shared_ptr<ByteArrayReadBytestream> stream1; }; diff --git a/Swiften/FileTransfer/WriteBytestream.cpp b/Swiften/FileTransfer/WriteBytestream.cpp index f1a5afc..8d10193 100644 --- a/Swiften/FileTransfer/WriteBytestream.cpp +++ b/Swiften/FileTransfer/WriteBytestream.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/FileTransfer/WriteBytestream.h" +#include <Swiften/FileTransfer/WriteBytestream.h> namespace Swift { diff --git a/Swiften/FileTransfer/WriteBytestream.h b/Swiften/FileTransfer/WriteBytestream.h index 1dc791c..fb6f2f1 100644 --- a/Swiften/FileTransfer/WriteBytestream.h +++ b/Swiften/FileTransfer/WriteBytestream.h @@ -7,8 +7,9 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <vector> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class WriteBytestream { @@ -17,6 +18,8 @@ namespace Swift { virtual ~WriteBytestream(); - virtual void write(const ByteArray&) = 0; + virtual void write(const std::vector<unsigned char>&) = 0; + + boost::signal<void (const std::vector<unsigned char>&)> onWrite; }; } diff --git a/Swiften/History/HistoryManager.cpp b/Swiften/History/HistoryManager.cpp index 7017899..7eb66ab 100644 --- a/Swiften/History/HistoryManager.cpp +++ b/Swiften/History/HistoryManager.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/History/HistoryManager.h" +#include <Swiften/History/HistoryManager.h> namespace Swift { diff --git a/Swiften/History/SQLiteHistoryManager.cpp b/Swiften/History/SQLiteHistoryManager.cpp index 9d5a000..3b65f62 100644 --- a/Swiften/History/SQLiteHistoryManager.cpp +++ b/Swiften/History/SQLiteHistoryManager.cpp @@ -7,8 +7,8 @@ #include <iostream> #include <boost/lexical_cast.hpp> -#include "sqlite3.h" -#include "Swiften/History/SQLiteHistoryManager.h" +#include <sqlite3.h> +#include <Swiften/History/SQLiteHistoryManager.h> namespace { diff --git a/Swiften/History/SQLiteHistoryManager.h b/Swiften/History/SQLiteHistoryManager.h index a2b89f4..ffd9492 100644 --- a/Swiften/History/SQLiteHistoryManager.h +++ b/Swiften/History/SQLiteHistoryManager.h @@ -8,7 +8,7 @@ #include <boost/optional.hpp> -#include "Swiften/History/HistoryManager.h" +#include <Swiften/History/HistoryManager.h> struct sqlite3; diff --git a/Swiften/History/UnitTest/SQLiteHistoryManagerTest.cpp b/Swiften/History/UnitTest/SQLiteHistoryManagerTest.cpp index 0092e0f..4123008 100644 --- a/Swiften/History/UnitTest/SQLiteHistoryManagerTest.cpp +++ b/Swiften/History/UnitTest/SQLiteHistoryManagerTest.cpp @@ -8,7 +8,7 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/date_time/posix_time/posix_time.hpp> -#include "Swiften/History/SQLiteHistoryManager.h" +#include <Swiften/History/SQLiteHistoryManager.h> using namespace Swift; @@ -34,7 +34,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void testAddMessage() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); HistoryMessage testMessage("Test", JID("foo@bar.com"), JID("fum@baz.org"), boost::posix_time::time_from_string("1980-01-21 22:03")); testling->addMessage(testMessage); @@ -44,7 +44,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void testAddMessage_TwoMessages() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); HistoryMessage testMessage1("Test1", JID("foo@bar.com"), JID("fum@baz.org"), boost::posix_time::time_from_string("1980-01-21 22:03")); testling->addMessage(testMessage1); HistoryMessage testMessage2("Test2", JID("fum@baz.org"), JID("foo@bar.com"), boost::posix_time::time_from_string("1975-03-09 22:04")); @@ -57,7 +57,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void testGetIDForJID_SameJID() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); int id1 = testling->getIDForJID(JID("foo@bar.com")); int id2 = testling->getIDForJID(JID("foo@bar.com")); @@ -65,7 +65,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void testGetIDForJID_DifferentJIDs() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); int id1 = testling->getIDForJID(JID("foo@bar.com")); int id2 = testling->getIDForJID(JID("foo@baz.com")); @@ -73,7 +73,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void getJIDFromID() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); int id = testling->addJID(JID("foo@bar.com")); boost::optional<JID> result(testling->getJIDFromID(id)); @@ -82,7 +82,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void getJIDFromID_UnexistingID() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); boost::optional<JID> result(testling->getJIDFromID(1)); @@ -90,7 +90,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void getIDFromJID() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); int id = testling->addJID(JID("foo@bar.com")); boost::optional<int> result(testling->getIDFromJID(JID("foo@bar.com"))); @@ -99,7 +99,7 @@ class SQLiteHistoryManagerTest : public CppUnit::TestFixture { } void getIDFromJID_UnexistingJID() { - std::auto_ptr<SQLiteHistoryManager> testling(createHistoryManager()); + boost::shared_ptr<SQLiteHistoryManager> testling(createHistoryManager()); boost::optional<int> result(testling->getIDFromJID(JID("foo@bar.com"))); diff --git a/Swiften/IDN/IDNA.cpp b/Swiften/IDN/IDNA.cpp index 6b6c7a4..16b4183 100644 --- a/Swiften/IDN/IDNA.cpp +++ b/Swiften/IDN/IDNA.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/IDN/IDNA.h" +#include <Swiften/IDN/IDNA.h> #include <stringprep.h> #include <vector> diff --git a/Swiften/IDN/StringPrep.cpp b/Swiften/IDN/StringPrep.cpp index d54fb0b..db09523 100644 --- a/Swiften/IDN/StringPrep.cpp +++ b/Swiften/IDN/StringPrep.cpp @@ -4,36 +4,58 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/IDN/StringPrep.h" +#include <Swiften/IDN/StringPrep.h> #include <stringprep.h> #include <vector> #include <cassert> +#include <Swiften/Base/SafeAllocator.h> -namespace Swift { +using namespace Swift; + + namespace { + static const int MAX_STRINGPREP_SIZE = 1024; -static const int MAX_STRINGPREP_SIZE = 1024; + const Stringprep_profile* getLibIDNProfile(StringPrep::Profile profile) { + switch(profile) { + case StringPrep::NamePrep: return stringprep_nameprep; break; + case StringPrep::XMPPNodePrep: return stringprep_xmpp_nodeprep; break; + case StringPrep::XMPPResourcePrep: return stringprep_xmpp_resourceprep; break; + case StringPrep::SASLPrep: return stringprep_saslprep; break; + } + assert(false); + return 0; + } -const Stringprep_profile* getLibIDNProfile(StringPrep::Profile profile) { - switch(profile) { - case StringPrep::NamePrep: return stringprep_nameprep; break; - case StringPrep::XMPPNodePrep: return stringprep_xmpp_nodeprep; break; - case StringPrep::XMPPResourcePrep: return stringprep_xmpp_resourceprep; break; - case StringPrep::SASLPrep: return stringprep_saslprep; break; + template<typename StringType, typename ContainerType> + ContainerType getStringPrepared(const StringType& s, StringPrep::Profile profile) { + ContainerType input(s.begin(), s.end()); + input.resize(MAX_STRINGPREP_SIZE); + if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) { + return input; + } + else { + return ContainerType(); + } } - assert(false); - return 0; } +namespace Swift { + std::string StringPrep::getPrepared(const std::string& s, Profile profile) { - std::vector<char> input(s.begin(), s.end()); - input.resize(MAX_STRINGPREP_SIZE); - if (stringprep(&input[0], MAX_STRINGPREP_SIZE, static_cast<Stringprep_profile_flags>(0), getLibIDNProfile(profile)) == 0) { - return std::string(&input[0]); + std::vector<char> preparedData = getStringPrepared< std::string, std::vector<char> >(s, profile); + if (preparedData.empty()) { + throw std::exception(); } - else { + return std::string(vecptr(preparedData)); +} + +SafeByteArray StringPrep::getPrepared(const SafeByteArray& s, Profile profile) { + std::vector<char, SafeAllocator<char> > preparedData = getStringPrepared<SafeByteArray, std::vector<char, SafeAllocator<char> > >(s, profile); + if (preparedData.empty()) { throw std::exception(); } + return createSafeByteArray(reinterpret_cast<const char*>(vecptr(preparedData))); } } diff --git a/Swiften/IDN/StringPrep.h b/Swiften/IDN/StringPrep.h index f40553b..dc8fadc 100644 --- a/Swiften/IDN/StringPrep.h +++ b/Swiften/IDN/StringPrep.h @@ -7,6 +7,7 @@ #pragma once #include <string> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class StringPrep { @@ -19,5 +20,6 @@ namespace Swift { }; static std::string getPrepared(const std::string& s, Profile profile); + static SafeByteArray getPrepared(const SafeByteArray& s, Profile profile); }; } diff --git a/Swiften/JID/JID.cpp b/Swiften/JID/JID.cpp index f121120..66d6ff6 100644 --- a/Swiften/JID/JID.cpp +++ b/Swiften/JID/JID.cpp @@ -7,17 +7,24 @@ #define SWIFTEN_CACHE_JID_PREP #include <vector> +#include <list> #include <iostream> #include <string> #ifdef SWIFTEN_CACHE_JID_PREP #include <boost/unordered_map.hpp> #endif +#include <boost/assign/list_of.hpp> +#include <boost/algorithm/string/find_format.hpp> +#include <boost/algorithm/string/finder.hpp> +#include <sstream> #include <stringprep.h> #include <Swiften/Base/String.h> -#include "Swiften/JID/JID.h" -#include "Swiften/IDN/StringPrep.h" +#include <Swiften/JID/JID.h> +#include <Swiften/IDN/StringPrep.h> + +using namespace Swift; #ifdef SWIFTEN_CACHE_JID_PREP typedef boost::unordered_map<std::string, std::string> PrepCache; @@ -27,7 +34,81 @@ static PrepCache domainPrepCache; static PrepCache resourcePrepCache; #endif -namespace Swift { +static const std::list<char> escapedChars = boost::assign::list_of(' ')('"')('&')('\'')('/')('<')('>')('@')(':'); + +static std::string getEscaped(char c) { + return makeString() << '\\' << std::hex << static_cast<int>(c); +} + +static bool getEscapeSequenceValue(const std::string& sequence, unsigned char& value) { + std::stringstream s; + unsigned int v; + s << std::hex << sequence; + s >> v; + value = static_cast<unsigned char>(v); + return (!s.fail() && !s.bad() && (value == 0x5C || std::find(escapedChars.begin(), escapedChars.end(), value) != escapedChars.end())); +} + +// Disabling this code for now, since GCC4.5+boost1.42 (on ubuntu) seems to +// result in a bug. Replacing it with naive code. +#if 0 +struct UnescapedCharacterFinder { + template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { + for (; begin != end; ++begin) { + if (std::find(escapedChars.begin(), escapedChars.end(), *begin) != escapedChars.end()) { + return boost::iterator_range<Iterator>(begin, begin + 1); + } + else if (*begin == '\\') { + // Check if we have an escaped dissalowed character sequence + Iterator innerBegin = begin + 1; + if (innerBegin != end && innerBegin + 1 != end) { + Iterator innerEnd = innerBegin + 2; + unsigned char value; + if (getEscapeSequenceValue(std::string(innerBegin, innerEnd), value)) { + return boost::iterator_range<Iterator>(begin, begin + 1); + } + } + } + } + return boost::iterator_range<Iterator>(end, end); + } +}; + +struct UnescapedCharacterFormatter { + template<typename FindResult> std::string operator()(const FindResult& match) const { + std::ostringstream s; + s << '\\' << std::hex << static_cast<int>(*match.begin()); + return s.str(); + } +}; + +struct EscapedCharacterFinder { + template<typename Iterator> boost::iterator_range<Iterator> operator()(Iterator begin, Iterator end) { + for (; begin != end; ++begin) { + if (*begin == '\\') { + Iterator innerEnd = begin + 1; + for (size_t i = 0; i < 2 && innerEnd != end; ++i, ++innerEnd) { + } + unsigned char value; + if (getEscapeSequenceValue(std::string(begin + 1, innerEnd), value)) { + return boost::iterator_range<Iterator>(begin, innerEnd); + } + } + } + return boost::iterator_range<Iterator>(end, end); + } +}; + +struct EscapedCharacterFormatter { + template<typename FindResult> std::string operator()(const FindResult& match) const { + unsigned char value; + if (getEscapeSequenceValue(std::string(match.begin() + 1, match.end()), value)) { + return std::string(reinterpret_cast<const char*>(&value), 1); + } + return boost::copy_range<std::string>(match); + } +}; +#endif JID::JID(const char* jid) : valid_(true) { initializeFromString(std::string(jid)); @@ -137,5 +218,48 @@ int JID::compare(const Swift::JID& o, CompareType compareType) const { return 0; } -} // namespace Swift - +std::string JID::getEscapedNode(const std::string& node) { + std::string result; + for (std::string::const_iterator i = node.begin(); i != node.end(); ++i) { + if (std::find(escapedChars.begin(), escapedChars.end(), *i) != escapedChars.end()) { + result += getEscaped(*i); + continue; + } + else if (*i == '\\') { + // Check if we have an escaped dissalowed character sequence + std::string::const_iterator innerBegin = i + 1; + if (innerBegin != node.end() && innerBegin + 1 != node.end()) { + std::string::const_iterator innerEnd = innerBegin + 2; + unsigned char value; + if (getEscapeSequenceValue(std::string(innerBegin, innerEnd), value)) { + result += getEscaped(*i); + continue; + } + } + } + result += *i; + } + return result; + //return boost::find_format_all_copy(node, UnescapedCharacterFinder(), UnescapedCharacterFormatter()); +} + +std::string JID::getUnescapedNode() const { + std::string result; + for (std::string::const_iterator j = node_.begin(); j != node_.end();) { + if (*j == '\\') { + std::string::const_iterator innerEnd = j + 1; + for (size_t i = 0; i < 2 && innerEnd != node_.end(); ++i, ++innerEnd) { + } + unsigned char value; + if (getEscapeSequenceValue(std::string(j + 1, innerEnd), value)) { + result += std::string(reinterpret_cast<const char*>(&value), 1); + j = innerEnd; + continue; + } + } + result += *j; + ++j; + } + return result; + //return boost::find_format_all_copy(node_, EscapedCharacterFinder(), EscapedCharacterFormatter()); +} diff --git a/Swiften/JID/JID.h b/Swiften/JID/JID.h index 1a7dbe3..a4461ba 100644 --- a/Swiften/JID/JID.h +++ b/Swiften/JID/JID.h @@ -7,37 +7,120 @@ #pragma once #include <string> -#include <ostream> +//#include <iosfwd> +#include <iostream> namespace Swift { + /** + * This represents the JID used in XMPP + * (RFC6120 - http://tools.ietf.org/html/rfc6120 ). + * For a description of format, see the RFC or page 14 of + * XMPP: The Definitive Guide (Saint-Andre et al.) + * + * Particularly - a Bare JID is a JID without a resource part. + * + * A JID can be invalid (when isValid() returns false). No member methods are + * guaranteed to work correctly if they do. + */ class JID { public: enum CompareType { WithResource, WithoutResource }; - JID(const std::string& = std::string()); + /** + * Create a JID from its String representation. + * + * e.g. + * wonderland.lit + * wonderland.lit/rabbithole + * alice@wonderland.lit + * alice@wonderland.lit/TeaParty + * + * @param jid String representation. Invalid JID if empty or invalid. + */ + JID(const std::string& jid = std::string()); + + /** + * See std::string constructor. + */ JID(const char*); + + /** + * Create a bare JID from the node and domain parts. + * + * JID("node@domain") == JID("node", "domain") + * unless you pass in empty values. + * + * @param node JID node part. + * @param domain JID domain part. + */ JID(const std::string& node, const std::string& domain); + /** + * Create a bare JID from the node, domain and resource parts. + * + * JID("node@domain/resource") == JID("node", "domain", "resource") + * unless you pass in empty values. + * + * @param node JID node part. + * @param domain JID domain part. + * @param resource JID resource part. + */ JID(const std::string& node, const std::string& domain, const std::string& resource); + /** + * @return Is a correctly-formatted JID. + */ bool isValid() const { return valid_; } + /** + * e.g. JID("node@domain").getNode() == "node" + * @return could be empty. + */ const std::string& getNode() const { return node_; } + + /** + * e.g. JID("node@domain").getDomain() == "domain" + */ const std::string& getDomain() const { return domain_; } + + /** + * e.g. JID("node@domain/resource").getResource() == "resource" + * @return could be empty. + */ const std::string& getResource() const { return resource_; } + + /** + * Is a bare JID, i.e. has no resource part. + */ bool isBare() const { return !hasResource_; } + /** + * Returns the given node, escaped according to XEP-0106. + * The resulting node is a valid node for a JID, whereas the input value can contain characters + * that are not allowed. + */ + static std::string getEscapedNode(const std::string& node); + + /** + * Returns the node of the current JID, unescaped according to XEP-0106. + */ + std::string getUnescapedNode() const; + + /** + * Get the JID without a resource. + * @return Invalid if the original is invalid. + */ JID toBare() const { JID result(*this); result.hasResource_ = false; diff --git a/Swiften/JID/UnitTest/JIDTest.cpp b/Swiften/JID/UnitTest/JIDTest.cpp index e083918..81d24ea 100644 --- a/Swiften/JID/UnitTest/JIDTest.cpp +++ b/Swiften/JID/UnitTest/JIDTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> using namespace Swift; @@ -53,6 +53,11 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_TEST(testSmallerThan_Larger); CPPUNIT_TEST(testHasResource); CPPUNIT_TEST(testHasResource_NoResource); + CPPUNIT_TEST(testGetEscapedNode); + CPPUNIT_TEST(testGetEscapedNode_XEP106Examples); + CPPUNIT_TEST(testGetEscapedNode_BackslashAtEnd); + CPPUNIT_TEST(testGetUnescapedNode); + CPPUNIT_TEST(testGetUnescapedNode_XEP106Examples); CPPUNIT_TEST_SUITE_END(); public: @@ -325,6 +330,61 @@ class JIDTest : public CppUnit::TestFixture CPPUNIT_ASSERT(testling.isBare()); } + + void testGetEscapedNode() { + std::string escaped = JID::getEscapedNode("alice@wonderland.lit"); + CPPUNIT_ASSERT_EQUAL(std::string("alice\\40wonderland.lit"), escaped); + + escaped = JID::getEscapedNode("\\& \" ' / <\\\\> @ :\\3a\\40"); + CPPUNIT_ASSERT_EQUAL(std::string("\\\\26\\20\\22\\20\\27\\20\\2f\\20\\3c\\\\\\3e\\20\\40\\20\\3a\\5c3a\\5c40"), escaped); + } + + void testGetEscapedNode_XEP106Examples() { + CPPUNIT_ASSERT_EQUAL(std::string("\\2plus\\2is\\4"), JID::getEscapedNode("\\2plus\\2is\\4")); + CPPUNIT_ASSERT_EQUAL(std::string("foo\\bar"), JID::getEscapedNode("foo\\bar")); + CPPUNIT_ASSERT_EQUAL(std::string("foob\\41r"), JID::getEscapedNode("foob\\41r")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("space cadet"), std::string("space\\20cadet")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("call me \"ishmael\""), std::string("call\\20me\\20\\22ishmael\\22")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("at&t guy"), std::string("at\\26t\\20guy")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("d'artagnan"), std::string("d\\27artagnan")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("/.fanboy"), std::string("\\2f.fanboy")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("::foo::"), std::string("\\3a\\3afoo\\3a\\3a")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("<foo>"), std::string("\\3cfoo\\3e")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("user@host"), std::string("user\\40host")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\net"), std::string("c\\3a\\net")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\\\net"), std::string("c\\3a\\\\net")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\cool stuff"), std::string("c\\3a\\cool\\20stuff")); + CPPUNIT_ASSERT_EQUAL(JID::getEscapedNode("c:\\5commas"), std::string("c\\3a\\5c5commas")); + } + + void testGetEscapedNode_BackslashAtEnd() { + CPPUNIT_ASSERT_EQUAL(std::string("foo\\"), JID::getEscapedNode("foo\\")); + } + + void testGetUnescapedNode() { + std::string input = "\\& \" ' / <\\\\> @ : \\5c\\40"; + JID testling(JID::getEscapedNode(input) + "@y"); + CPPUNIT_ASSERT(testling.isValid()); + CPPUNIT_ASSERT_EQUAL(input, testling.getUnescapedNode()); + } + + void testGetUnescapedNode_XEP106Examples() { + CPPUNIT_ASSERT_EQUAL(std::string("\\2plus\\2is\\4"), JID("\\2plus\\2is\\4@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("foo\\bar"), JID("foo\\bar@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("foob\\41r"), JID("foob\\41r@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("space cadet"), JID("space\\20cadet@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("call me \"ishmael\""), JID("call\\20me\\20\\22ishmael\\22@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("at&t guy"), JID("at\\26t\\20guy@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("d'artagnan"), JID("d\\27artagnan@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("/.fanboy"), JID("\\2f.fanboy@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("::foo::"), JID("\\3a\\3afoo\\3a\\3a@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("<foo>"), JID("\\3cfoo\\3e@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("user@host"), JID("user\\40host@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\net"), JID("c\\3a\\net@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\\\net"), JID("c\\3a\\\\net@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\cool stuff"), JID("c\\3a\\cool\\20stuff@example.com").getUnescapedNode()); + CPPUNIT_ASSERT_EQUAL(std::string("c:\\5commas"), JID("c\\3a\\5c5commas@example.com").getUnescapedNode()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(JIDTest); diff --git a/Swiften/Jingle/FakeJingleSession.cpp b/Swiften/Jingle/FakeJingleSession.cpp new file mode 100644 index 0000000..82ec631 --- /dev/null +++ b/Swiften/Jingle/FakeJingleSession.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Jingle/FakeJingleSession.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +FakeJingleSession::FakeJingleSession(const JID& initiator, const std::string& id) : JingleSession(initiator, id) { + +} + +FakeJingleSession::~FakeJingleSession() { +} + +void FakeJingleSession::sendInitiate(const JingleContentID& id, JingleDescription::ref desc, JingleTransportPayload::ref payload) { + calledCommands.push_back(InitiateCall(id, desc, payload)); +} + +void FakeJingleSession::sendTerminate(JinglePayload::Reason::Type reason) { + calledCommands.push_back(TerminateCall(reason)); +} + +void FakeJingleSession::sendInfo(boost::shared_ptr<Payload> payload) { + calledCommands.push_back(InfoCall(payload)); +} + +void FakeJingleSession::sendAccept(const JingleContentID& id, JingleDescription::ref desc, JingleTransportPayload::ref payload) { + calledCommands.push_back(AcceptCall(id, desc, payload)); +} + +void FakeJingleSession::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref payload) { + calledCommands.push_back(InfoTransportCall(id, payload)); +} + +void FakeJingleSession::sendTransportAccept(const JingleContentID& id, JingleTransportPayload::ref payload) { + calledCommands.push_back(AcceptTransportCall(id, payload)); +} + +void FakeJingleSession::sendTransportReject(const JingleContentID& id, JingleTransportPayload::ref payload) { + calledCommands.push_back(RejectTransportCall(id, payload)); +} + +void FakeJingleSession::sendTransportReplace(const JingleContentID& id, JingleTransportPayload::ref payload) { + calledCommands.push_back(ReplaceTransportCall(id, payload)); +} + +} diff --git a/Swiften/Jingle/FakeJingleSession.h b/Swiften/Jingle/FakeJingleSession.h new file mode 100644 index 0000000..fd3d7b7 --- /dev/null +++ b/Swiften/Jingle/FakeJingleSession.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> +#include <string> +#include <vector> +#include <boost/variant.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Jingle/JingleSession.h> +#include <Swiften/Jingle/JingleContentID.h> + +namespace Swift { + class JingleContentID; + + class FakeJingleSession : public JingleSession { + public: + struct InitiateCall { + InitiateCall(JingleContentID contentId, JingleDescription::ref desc, JingleTransportPayload::ref payL) : id(contentId), description(desc), payload(payL) {} + JingleContentID id; + JingleDescription::ref description; + JingleTransportPayload::ref payload; + }; + + struct TerminateCall { + TerminateCall(JinglePayload::Reason::Type r) : reason(r) {} + JinglePayload::Reason::Type reason; + }; + + struct InfoCall { + InfoCall(boost::shared_ptr<Payload> info) : payload(info) {} + boost::shared_ptr<Payload> payload; + }; + + struct AcceptCall { + AcceptCall(JingleContentID contentId, JingleDescription::ref desc, JingleTransportPayload::ref payL) : id(contentId), description(desc), payload(payL) {} + JingleContentID id; + JingleDescription::ref description; + JingleTransportPayload::ref payload; + }; + + struct InfoTransportCall { + InfoTransportCall(JingleContentID contentId, JingleTransportPayload::ref payL) : id(contentId), payload(payL) {} + JingleContentID id; + JingleTransportPayload::ref payload; + }; + + struct AcceptTransportCall { + AcceptTransportCall(JingleContentID contentId, JingleTransportPayload::ref payL) : id(contentId), payload(payL) {} + JingleContentID id; + JingleTransportPayload::ref payload; + }; + + struct RejectTransportCall { + RejectTransportCall(JingleContentID contentId, JingleTransportPayload::ref payL) : id(contentId), payload(payL) {} + JingleContentID id; + JingleTransportPayload::ref payload; + }; + + struct ReplaceTransportCall { + ReplaceTransportCall(JingleContentID contentId, JingleTransportPayload::ref payL) : id(contentId), payload(payL) {} + JingleContentID id; + JingleTransportPayload::ref payload; + }; + + typedef boost::variant<InitiateCall, TerminateCall, AcceptCall, InfoCall, InfoTransportCall, AcceptTransportCall, RejectTransportCall, ReplaceTransportCall> Command; + + public: + typedef boost::shared_ptr<FakeJingleSession> ref; + + FakeJingleSession(const JID& initiator, const std::string& id); + virtual ~FakeJingleSession(); + + virtual void sendInitiate(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); + virtual void sendTerminate(JinglePayload::Reason::Type reason); + virtual void sendInfo(boost::shared_ptr<Payload>); + virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref = JingleTransportPayload::ref()); + virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref); + + public: + std::vector<Command> calledCommands; + }; +} diff --git a/Swiften/Jingle/IncomingJingleSession.cpp b/Swiften/Jingle/IncomingJingleSession.cpp deleted file mode 100644 index b18d9d3..0000000 --- a/Swiften/Jingle/IncomingJingleSession.cpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Jingle/IncomingJingleSession.h> - -namespace Swift { - -IncomingJingleSession::IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : JingleSession(id, contents) { - -} - -} diff --git a/Swiften/Jingle/IncomingJingleSession.h b/Swiften/Jingle/IncomingJingleSession.h deleted file mode 100644 index 64816f6..0000000 --- a/Swiften/Jingle/IncomingJingleSession.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2011 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include <boost/shared_ptr.hpp> - -#include <Swiften/Jingle/JingleSession.h> - -namespace Swift { - class IncomingJingleSession : public JingleSession { - public: - IncomingJingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents); - - typedef boost::shared_ptr<IncomingJingleSession> ref; - }; -} diff --git a/Swiften/Jingle/IncomingJingleSessionHandler.h b/Swiften/Jingle/IncomingJingleSessionHandler.h index 5bf9237..d23570d 100644 --- a/Swiften/Jingle/IncomingJingleSessionHandler.h +++ b/Swiften/Jingle/IncomingJingleSessionHandler.h @@ -6,13 +6,13 @@ #pragma once -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSession.h> namespace Swift { class IncomingJingleSessionHandler { public: virtual ~IncomingJingleSessionHandler(); - virtual bool handleIncomingJingleSession(IncomingJingleSession::ref) = 0; + virtual bool handleIncomingJingleSession(JingleSession::ref, const std::vector<JingleContentPayload::ref>& contents, const JID& recipient) = 0; }; } diff --git a/Swiften/Jingle/Jingle.h b/Swiften/Jingle/Jingle.h new file mode 100644 index 0000000..ba4dfe3 --- /dev/null +++ b/Swiften/Jingle/Jingle.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/Elements/JingleContentPayload.h> + +namespace Swift { + namespace Jingle { + template<typename T> + JingleContentPayload::ref getContentWithDescription(const std::vector<JingleContentPayload::ref>& contents) { + for (size_t i = 0; i < contents.size(); ++i) { + if (contents[i]->getDescription<T>()) { + return contents[i]; + } + } + return JingleContentPayload::ref(); + } + } +} diff --git a/Swiften/Jingle/JingleContentID.h b/Swiften/Jingle/JingleContentID.h new file mode 100644 index 0000000..fc0cc8f --- /dev/null +++ b/Swiften/Jingle/JingleContentID.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Elements/JingleContentPayload.h> + +namespace Swift { + class JingleContentID { + public: + JingleContentID(const std::string& name, JingleContentPayload::Creator creator) : name(name), creator(creator) { + } + + const std::string getName() const { + return this->name; + } + + JingleContentPayload::Creator getCreator() const { + return this->creator; + } + + private: + std::string name; + JingleContentPayload::Creator creator; + }; +} diff --git a/Swiften/Jingle/JingleResponder.cpp b/Swiften/Jingle/JingleResponder.cpp index 2397e63..4c82f51 100644 --- a/Swiften/Jingle/JingleResponder.cpp +++ b/Swiften/Jingle/JingleResponder.cpp @@ -9,14 +9,19 @@ #include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Jingle/JingleSessionManager.h> -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSessionImpl.h> + +#include <Swiften/Base/Log.h> namespace Swift { -JingleResponder::JingleResponder(JingleSessionManager* sessionManager, IQRouter* router) : SetResponder<JinglePayload>(router), sessionManager(sessionManager) { +JingleResponder::JingleResponder(JingleSessionManager* sessionManager, IQRouter* router) : SetResponder<JinglePayload>(router), sessionManager(sessionManager), router(router) { +} + +JingleResponder::~JingleResponder() { } -bool JingleResponder::handleSetRequest(const JID& from, const JID&, const std::string& id, boost::shared_ptr<JinglePayload> payload) { +bool JingleResponder::handleSetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<JinglePayload> payload) { if (payload->getAction() == JinglePayload::SessionInitiate) { if (sessionManager->getSession(from, payload->getSessionID())) { // TODO: Add tie-break error @@ -24,17 +29,29 @@ bool JingleResponder::handleSetRequest(const JID& from, const JID&, const std::s } else { sendResponse(from, id, boost::shared_ptr<JinglePayload>()); - IncomingJingleSession::ref session = boost::make_shared<IncomingJingleSession>(id, payload->getContents()); - sessionManager->handleIncomingSession(from, session); + if (!payload->getInitiator().isBare()) { + JingleSessionImpl::ref session = boost::make_shared<JingleSessionImpl>(payload->getInitiator(), from, payload->getSessionID(), router); + sessionManager->handleIncomingSession(from, to, session, payload->getContents()); + } else { + SWIFT_LOG(debug) << "Unable to create Jingle session due to initiator not being a full JID." << std::endl; + } } } else { - JingleSession::ref session = sessionManager->getSession(from, payload->getSessionID()); + JingleSessionImpl::ref session; + if (payload->getInitiator().isValid()) { + SWIFT_LOG(debug) << "Lookup session by initiator." << std::endl; + session = sessionManager->getSession(payload->getInitiator(), payload->getSessionID()); + } else { + SWIFT_LOG(debug) << "Lookup session by from attribute." << std::endl; + session = sessionManager->getSession(from, payload->getSessionID()); + } if (session) { session->handleIncomingAction(payload); sendResponse(from, id, boost::shared_ptr<JinglePayload>()); } else { + std::cerr << "WARN: Didn't find jingle session!" << std::endl; // TODO: Add jingle-specific error sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel); } diff --git a/Swiften/Jingle/JingleResponder.h b/Swiften/Jingle/JingleResponder.h index 6e1965c..6f4d688 100644 --- a/Swiften/Jingle/JingleResponder.h +++ b/Swiften/Jingle/JingleResponder.h @@ -16,11 +16,12 @@ namespace Swift { class JingleResponder : public SetResponder<JinglePayload> { public: JingleResponder(JingleSessionManager* sessionManager, IQRouter* router); - + virtual ~JingleResponder(); private: virtual bool handleSetRequest(const JID& from, const JID& to, const std::string& id, boost::shared_ptr<JinglePayload> payload); private: JingleSessionManager* sessionManager; + IQRouter* router; }; } diff --git a/Swiften/Jingle/JingleSession.cpp b/Swiften/Jingle/JingleSession.cpp index d255abd..eb649f3 100644 --- a/Swiften/Jingle/JingleSession.cpp +++ b/Swiften/Jingle/JingleSession.cpp @@ -10,21 +10,13 @@ namespace Swift { -JingleSession::JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents) : id(id), contents(contents) { - +JingleSession::JingleSession(const JID& initiator, const std::string& id) : initiator(initiator), id(id) { + // initiator must always be a full JID; session lookup based on it wouldn't work otherwise + // this is checked on an upper level so that the assert never fails + assert(!initiator.isBare()); } JingleSession::~JingleSession() { } -void JingleSession::handleIncomingAction(JinglePayload::ref) { -} - -void JingleSession::terminate(JinglePayload::Reason::Type reason) { - JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, id); - payload->setReason(JinglePayload::Reason(reason)); - //onAction(payload) -} - - } diff --git a/Swiften/Jingle/JingleSession.h b/Swiften/Jingle/JingleSession.h index fe8aa01..150ad79 100644 --- a/Swiften/Jingle/JingleSession.h +++ b/Swiften/Jingle/JingleSession.h @@ -7,47 +7,51 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <boost/optional.hpp> -#include <Swiften/Base/boost_bsignals.h> #include <string> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> #include <Swiften/Elements/JinglePayload.h> -#include <Swiften/Elements/JingleContent.h> -#include <Swiften/Base/foreach.h> namespace Swift { + class JingleContentID; + class JingleSession { - friend class JingleResponder; public: typedef boost::shared_ptr<JingleSession> ref; - JingleSession(const std::string& id, const std::vector<JingleContent::ref>& contents); + JingleSession(const JID& initiator, const std::string& id); virtual ~JingleSession(); - std::string getID() const { - return id; + const JID& getInitiator() const { + return initiator; } - template<typename T> - JingleContent::ref getContentWithDescription() const { - foreach (JingleContent::ref content, contents) { - if (content->getDescription<T>()) { - return content; - } - } - return JingleContent::ref(); - } - - const std::vector<JingleContent::ref>& getContents() const { - return contents; + const std::string& getID() const { + return id; } + virtual void sendInitiate(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref) = 0; + virtual void sendTerminate(JinglePayload::Reason::Type reason) = 0; + virtual void sendInfo(boost::shared_ptr<Payload>) = 0; + virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref = JingleTransportPayload::ref()) = 0; + virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref) = 0; + virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref) = 0; + virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref) = 0; + virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref) = 0; - void terminate(JinglePayload::Reason::Type reason); - - private: - void handleIncomingAction(JinglePayload::ref); + public: + boost::signal<void (const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref)> onSessionAcceptReceived; + boost::signal<void (JinglePayload::ref)> onSessionInfoReceived; + boost::signal<void (boost::optional<JinglePayload::Reason>)> onSessionTerminateReceived; + boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportAcceptReceived; + boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportInfoReceived; + boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportRejectReceived; + boost::signal<void (const JingleContentID&, JingleTransportPayload::ref)> onTransportReplaceReceived; private: + JID initiator; std::string id; - std::vector<JingleContent::ref> contents; }; } diff --git a/Swiften/Jingle/JingleSessionImpl.cpp b/Swiften/Jingle/JingleSessionImpl.cpp new file mode 100644 index 0000000..98c5196 --- /dev/null +++ b/Swiften/Jingle/JingleSessionImpl.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Jingle/JingleSessionImpl.h> + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Parser/PayloadParsers/JingleParser.h> +#include <Swiften/Jingle/JingleContentID.h> +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Queries/Request.h> +#include <Swiften/Queries/GenericRequest.h> + +#include <Swiften/Base/Log.h> + +#include "Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h" +#include "Swiften/FileTransfer/JingleTransport.h" + +namespace Swift { + +JingleSessionImpl::JingleSessionImpl(const JID& initiator, const JID& peerJID, const std::string& id, IQRouter* router) : JingleSession(initiator, id), iqRouter(router), peerJID(peerJID) { + SWIFT_LOG(debug) << "initiator: " << initiator << ", peerJID: " << peerJID << std::endl; +} + +void JingleSessionImpl::handleIncomingAction(JinglePayload::ref action) { + if (action->getAction() == JinglePayload::SessionTerminate) { + onSessionTerminateReceived(action->getReason()); + return; + } + if (action->getAction() == JinglePayload::SessionInfo) { + onSessionInfoReceived(action); + return; + } + + JingleContentPayload::ref content = action->getPayload<JingleContentPayload>(); + if (!content) { + SWIFT_LOG(debug) << "no content payload!" << std::endl; + return; + } + JingleContentID contentID(content->getName(), content->getCreator()); + JingleDescription::ref description = content->getDescriptions().empty() ? JingleDescription::ref() : content->getDescriptions()[0]; + JingleTransportPayload::ref transport = content->getTransports().empty() ? JingleTransportPayload::ref() : content->getTransports()[0]; + switch(action->getAction()) { + case JinglePayload::SessionAccept: + onSessionAcceptReceived(contentID, description, transport); + return; + case JinglePayload::TransportAccept: + onTransportAcceptReceived(contentID, transport); + return; + case JinglePayload::TransportInfo: + onTransportInfoReceived(contentID, transport); + return; + case JinglePayload::TransportReject: + onTransportRejectReceived(contentID, transport); + return; + case JinglePayload::TransportReplace: + onTransportReplaceReceived(contentID, transport); + return; + // following unused Jingle actions + case JinglePayload::ContentAccept: + case JinglePayload::ContentAdd: + case JinglePayload::ContentModify: + case JinglePayload::ContentReject: + case JinglePayload::ContentRemove: + case JinglePayload::DescriptionInfo: + case JinglePayload::SecurityInfo: + + // handled elsewhere + case JinglePayload::SessionInitiate: + case JinglePayload::SessionInfo: + case JinglePayload::SessionTerminate: + + case JinglePayload::UnknownAction: + return; + } + std::cerr << "Unhandled Jingle action!!! ACTION: " << action->getAction() << std::endl; +} + +void JingleSessionImpl::sendInitiate(const JingleContentID& id, JingleDescription::ref description, JingleTransportPayload::ref transport) { + JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionInitiate, getID()); + payload->setInitiator(getInitiator()); + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(id.getCreator()); + content->setName(id.getName()); + content->addDescription(description); + content->addTransport(transport); + payload->addPayload(content); + + sendSetRequest(payload); +} + +void JingleSessionImpl::sendTerminate(JinglePayload::Reason::Type reason) { + JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionTerminate, getID()); + payload->setReason(JinglePayload::Reason(reason)); + payload->setInitiator(getInitiator()); + sendSetRequest(payload); +} + +void JingleSessionImpl::sendInfo(boost::shared_ptr<Payload> info) { + JinglePayload::ref payload = boost::make_shared<JinglePayload>(JinglePayload::SessionInfo, getID()); + payload->addPayload(info); + + sendSetRequest(payload); +} + +void JingleSessionImpl::sendAccept(const JingleContentID& id, JingleDescription::ref description, JingleTransportPayload::ref transPayload) { + JinglePayload::ref payload = createPayload(); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(id.getCreator()); + content->setName(id.getName()); + content->addTransport(transPayload); + content->addDescription(description); + payload->setAction(JinglePayload::SessionAccept); + payload->addPayload(content); + + // put into IQ:set and send it away + sendSetRequest(payload); +} + + +void JingleSessionImpl::sendTransportAccept(const JingleContentID& id, JingleTransportPayload::ref transPayload) { + JinglePayload::ref payload = createPayload(); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(id.getCreator()); + content->setName(id.getName()); + content->addTransport(transPayload); + payload->setAction(JinglePayload::TransportAccept); + payload->addPayload(content); + + // put into IQ:set and send it away + sendSetRequest(payload); +} + +void JingleSessionImpl::sendTransportInfo(const JingleContentID& id, JingleTransportPayload::ref transPayload) { + JinglePayload::ref payload = createPayload(); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(id.getCreator()); + content->setName(id.getName()); + content->addTransport(transPayload); + payload->setAction(JinglePayload::TransportInfo); + payload->addPayload(content); + + sendSetRequest(payload); +} + +void JingleSessionImpl::sendTransportReject(const JingleContentID& /* id */, JingleTransportPayload::ref /* transPayload */) { + SWIFT_LOG(debug) << "NOT IMPLEMENTED YET!!!!" << std::endl; +} + +void JingleSessionImpl::sendTransportReplace(const JingleContentID& id, JingleTransportPayload::ref transPayload) { + JinglePayload::ref payload = createPayload(); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(id.getCreator()); + content->setName(id.getName()); + content->addTransport(transPayload); + payload->setAction(JinglePayload::TransportReplace); + payload->addContent(content); + + sendSetRequest(payload); +} + + +void JingleSessionImpl::sendSetRequest(JinglePayload::ref payload) { + boost::shared_ptr<GenericRequest<JinglePayload> > request = boost::make_shared<GenericRequest<JinglePayload> >(IQ::Set, peerJID, payload, iqRouter); + request->send(); +} + + +JinglePayload::ref JingleSessionImpl::createPayload() const { + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setSessionID(getID()); + payload->setInitiator(getInitiator()); + return payload; +} + + + +} diff --git a/Swiften/Jingle/JingleSessionImpl.h b/Swiften/Jingle/JingleSessionImpl.h new file mode 100644 index 0000000..3c1559a --- /dev/null +++ b/Swiften/Jingle/JingleSessionImpl.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Jingle/JingleSession.h> + +namespace Swift { + class IQRouter; + + class JingleSessionImpl : public JingleSession { + friend class JingleResponder; + public: + typedef boost::shared_ptr<JingleSessionImpl> ref; + + JingleSessionImpl(const JID& initiator, const JID&, const std::string& id, IQRouter* router); + + virtual void sendInitiate(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); + virtual void sendTerminate(JinglePayload::Reason::Type reason); + virtual void sendInfo(boost::shared_ptr<Payload>); + virtual void sendAccept(const JingleContentID&, JingleDescription::ref, JingleTransportPayload::ref); + virtual void sendTransportInfo(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendTransportAccept(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref); + virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref); + + private: + void handleIncomingAction(JinglePayload::ref); + + void sendSetRequest(JinglePayload::ref payload); + JinglePayload::ref createPayload() const; + + private: + IQRouter *iqRouter; + JID peerJID; + }; +} diff --git a/Swiften/Jingle/JingleSessionManager.cpp b/Swiften/Jingle/JingleSessionManager.cpp index e60449b..2e15fcd 100644 --- a/Swiften/Jingle/JingleSessionManager.cpp +++ b/Swiften/Jingle/JingleSessionManager.cpp @@ -7,20 +7,24 @@ #include <Swiften/Jingle/JingleSessionManager.h> #include <Swiften/Jingle/JingleResponder.h> #include <Swiften/Jingle/IncomingJingleSessionHandler.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Algorithm.h> namespace Swift { JingleSessionManager::JingleSessionManager(IQRouter* router) : router(router) { responder = new JingleResponder(this, router); + responder->start(); } JingleSessionManager::~JingleSessionManager() { + responder->stop(); delete responder; } -JingleSession::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const { - SessionMap::const_iterator i = incomingSessions.find(JIDSession(jid, id)); - return i != incomingSessions.end() ? i->second : JingleSession::ref(); +JingleSessionImpl::ref JingleSessionManager::getSession(const JID& jid, const std::string& id) const { + SessionMap::const_iterator i = sessions.find(JIDSession(jid, id)); + return i != sessions.end() ? i->second : JingleSessionImpl::ref(); } void JingleSessionManager::addIncomingSessionHandler(IncomingJingleSessionHandler* handler) { @@ -28,13 +32,18 @@ void JingleSessionManager::addIncomingSessionHandler(IncomingJingleSessionHandle } void JingleSessionManager::removeIncomingSessionHandler(IncomingJingleSessionHandler* handler) { - incomingSessionHandlers.erase(std::remove(incomingSessionHandlers.begin(), incomingSessionHandlers.end(), handler), incomingSessionHandlers.end()); + erase(incomingSessionHandlers, handler); } -void JingleSessionManager::handleIncomingSession(const JID& from, IncomingJingleSession::ref session) { - incomingSessions.insert(std::make_pair(JIDSession(from, session->getID()), session)); +void JingleSessionManager::registerOutgoingSession(const JID& initiator, JingleSessionImpl::ref session) { + sessions.insert(std::make_pair(JIDSession(initiator, session->getID()), session)); + SWIFT_LOG(debug) << "Added session " << session->getID() << " for initiator " << initiator.toString() << std::endl; +} + +void JingleSessionManager::handleIncomingSession(const JID& initiator, const JID& recipient, JingleSessionImpl::ref session, const std::vector<JingleContentPayload::ref>& contents) { + sessions.insert(std::make_pair(JIDSession(initiator, session->getID()), session)); foreach (IncomingJingleSessionHandler* handler, incomingSessionHandlers) { - if (handler->handleIncomingJingleSession(session)) { + if (handler->handleIncomingJingleSession(session, contents, recipient)) { return; } } diff --git a/Swiften/Jingle/JingleSessionManager.h b/Swiften/Jingle/JingleSessionManager.h index 3e99656..b4f2846 100644 --- a/Swiften/Jingle/JingleSessionManager.h +++ b/Swiften/Jingle/JingleSessionManager.h @@ -10,7 +10,7 @@ #include <map> #include <Swiften/Base/boost_bsignals.h> -#include <Swiften/Jingle/IncomingJingleSession.h> +#include <Swiften/Jingle/JingleSessionImpl.h> namespace Swift { class IQRouter; @@ -23,27 +23,28 @@ namespace Swift { JingleSessionManager(IQRouter* router); ~JingleSessionManager(); - JingleSession::ref getSession(const JID& jid, const std::string& id) const; + JingleSessionImpl::ref getSession(const JID& jid, const std::string& id) const; void addIncomingSessionHandler(IncomingJingleSessionHandler* handler); void removeIncomingSessionHandler(IncomingJingleSessionHandler* handler); + void registerOutgoingSession(const JID& initiator, JingleSessionImpl::ref); protected: - void handleIncomingSession(const JID& from, IncomingJingleSession::ref); + void handleIncomingSession(const JID& initiator, const JID& recipient, JingleSessionImpl::ref, const std::vector<JingleContentPayload::ref>& contents); private: IQRouter* router; JingleResponder* responder; std::vector<IncomingJingleSessionHandler*> incomingSessionHandlers; struct JIDSession { - JIDSession(const JID& jid, const std::string& session) : jid(jid), session(session) {} + JIDSession(const JID& initiator, const std::string& session) : initiator(initiator), session(session) {} bool operator<(const JIDSession& o) const { - return jid == o.jid ? session < o.session : jid < o.jid; + return initiator == o.initiator ? session < o.session : initiator < o.initiator; } - JID jid; + JID initiator; std::string session; }; - typedef std::map<JIDSession, JingleSession::ref> SessionMap; - SessionMap incomingSessions; + typedef std::map<JIDSession, JingleSessionImpl::ref> SessionMap; + SessionMap sessions; }; } diff --git a/Swiften/Jingle/SConscript b/Swiften/Jingle/SConscript index a8890b7..5dcf293 100644 --- a/Swiften/Jingle/SConscript +++ b/Swiften/Jingle/SConscript @@ -1,11 +1,12 @@ Import("swiften_env") sources = [ - "IncomingJingleSession.cpp", + "JingleSession.cpp", + "JingleSessionImpl.cpp", "IncomingJingleSessionHandler.cpp", "JingleSessionManager.cpp", "JingleResponder.cpp", - "JingleSession.cpp", + "FakeJingleSession.cpp", ] swiften_env.Append(SWIFTEN_OBJECTS = swiften_env.SwiftenObject(sources)) diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp new file mode 100644 index 0000000..e31bf87 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h> + +#include <boost/bind.hpp> +#include <iostream> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> + +namespace Swift { + +void AvahiBrowseQuery::startBrowsing() { + std::cout << "Start browsing" << std::endl; + assert(!browser); + avahi_threaded_poll_lock(querier->getThreadedPoll()); + browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0), &handleServiceDiscoveredStatic, this); + if (!browser) { + std::cout << "Error" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + } + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiBrowseQuery::stopBrowsing() { + std::cout << "Stop browsing" << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + avahi_service_browser_free(browser); + browser = NULL; + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiBrowseQuery::handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) { + switch (event) { + case AVAHI_BROWSER_FAILURE: + std::cout << "Service browse error" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); + break; + case AVAHI_BROWSER_NEW: { + DNSSDServiceID service(name, domain, type, interfaceIndex); + std::cout << "Service discovered " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); + break; + } + case AVAHI_BROWSER_REMOVE: { + std::cout << "Service went away " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; + DNSSDServiceID service(name, domain, type, interfaceIndex); + eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); + break; + } + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; + } +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h index 163a5f6..38e796d 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h @@ -6,11 +6,11 @@ #pragma once -#include <boost/bind.hpp> +#include <avahi-client/lookup.h> -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class AvahiQuerier; @@ -20,54 +20,15 @@ namespace Swift { AvahiBrowseQuery(boost::shared_ptr<AvahiQuerier> q, EventLoop* eventLoop) : AvahiQuery(q, eventLoop), browser(NULL) { } - void startBrowsing() { - std::cout << "Start browsing" << std::endl; - assert(!browser); - avahi_threaded_poll_lock(querier->getThreadedPoll()); - browser = avahi_service_browser_new(querier->getClient(), AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_presence._tcp", NULL, static_cast<AvahiLookupFlags>(0), &handleServiceDiscoveredStatic, this); - if (!browser) { - std::cout << "Error" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); - } - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } - - void stopBrowsing() { - std::cout << "Stop browsing" << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - avahi_service_browser_free(browser); - browser = NULL; - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } + void startBrowsing(); + void stopBrowsing(); private: static void handleServiceDiscoveredStatic(AvahiServiceBrowser *b, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, void* context) { static_cast<AvahiBrowseQuery*>(context)->handleServiceDiscovered(b, interfaceIndex, protocol, event, name, type, domain, flags); } - void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags) { - switch (event) { - case AVAHI_BROWSER_FAILURE: - std::cout << "Service browse error" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onError)), shared_from_this()); - break; - case AVAHI_BROWSER_NEW: { - DNSSDServiceID service(name, domain, type, interfaceIndex); - std::cout << "Service discovered " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onServiceAdded), service), shared_from_this()); - break; - } - case AVAHI_BROWSER_REMOVE: { - std::cout << "Service went away " << name << " " << domain << " " << type << " " << interfaceIndex << std::endl; - DNSSDServiceID service(name, domain, type, interfaceIndex); - eventLoop->postEvent(boost::bind(boost::ref(onServiceRemoved), service), shared_from_this()); - break; - } - case AVAHI_BROWSER_ALL_FOR_NOW: - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - } - } + void handleServiceDiscovered(AvahiServiceBrowser *, AvahiIfIndex interfaceIndex, AvahiProtocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags); private: AvahiServiceBrowser* browser; diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp index dd189d9..e9f5564 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> #include <iostream> -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h" -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h" -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h" -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiBrowseQuery.h> +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h> +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h> +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h index bfb017e..6ddd23d 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h @@ -15,10 +15,10 @@ #include <avahi-common/malloc.h> #include <avahi-common/error.h> -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { - class ByteArray; class EventLoop; class AvahiQuerier : diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp index 1b40dfd..3b0e8da 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h> +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h index f5df032..047e1cd 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { class AvahiQuerier; diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp new file mode 100644 index 0000000..8a7ed3b --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h> + +#include <iostream> +#include <boost/bind.hpp> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> + +namespace Swift { + +void AvahiRegisterQuery::registerService() { + std::cout << "Registering service " << name << ":" << port << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + if (!group) { + std::cout << "Creating entry group" << std::endl; + group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this); + if (!group) { + std::cout << "Error ceating entry group" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } + } + + doRegisterService(); + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiRegisterQuery::unregisterService() { + if (group) { + avahi_entry_group_free(group); + group = NULL; + } +} + +void AvahiRegisterQuery::updateServiceInfo(const ByteArray& txtRecord) { + this->txtRecord = txtRecord; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + assert(group); + avahi_entry_group_reset(group); + doRegisterService(); + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiRegisterQuery::doRegisterService() { + AvahiStringList* txtList; + avahi_string_list_parse(vecptr(txtRecord), txtRecord.size(), &txtList); + + int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList); + if (result < 0) { + std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } + result = avahi_entry_group_commit(group); + if (result < 0) { + std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; + } +} + +void AvahiRegisterQuery::handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) { + std::cout << "ENtry group callback: " << state << std::endl; + switch (state) { + case AVAHI_ENTRY_GROUP_ESTABLISHED : + // Domain is a hack! + eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this()); + std::cout << "Entry group established" << std::endl; + break; + case AVAHI_ENTRY_GROUP_COLLISION : { + std::cout << "Entry group collision" << std::endl; + /*char *n; + n = avahi_alternative_service_name(name); + avahi_free(name); + name = n;*/ + break; + } + + case AVAHI_ENTRY_GROUP_FAILURE : + std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl; + break; + + case AVAHI_ENTRY_GROUP_UNCOMMITED: + case AVAHI_ENTRY_GROUP_REGISTERING: + ; + + /* + DNSServiceErrorType result = DNSServiceRegister( + &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, + txtRecord.getSize(), txtRecord.getData(), + &AvahiRegisterQuery::handleServiceRegisteredStatic, this); + if (result != kDNSServiceErr_NoError) { + sdRef = NULL; + }*/ + //eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); + } +} + + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h index 07966af..b47ed12 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiRegisterQuery.h @@ -8,10 +8,10 @@ #include <avahi-client/publish.h> -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class AvahiQuerier; @@ -21,94 +21,18 @@ namespace Swift { AvahiRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), name(name), port(port), txtRecord(txtRecord), group(0) { } - void registerService() { - std::cout << "Registering service " << name << ":" << port << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - if (!group) { - std::cout << "Creating entry group" << std::endl; - group = avahi_entry_group_new(querier->getClient(), handleEntryGroupChange, this); - if (!group) { - std::cout << "Error ceating entry group" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); - } - } - - doRegisterService(); - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } - - void unregisterService() { - if (group) { - avahi_entry_group_free(group); - group = NULL; - } - } - - void updateServiceInfo(const ByteArray& txtRecord) { - this->txtRecord = txtRecord; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - assert(group); - avahi_entry_group_reset(group); - doRegisterService(); - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } + void registerService(); + void unregisterService(); + void updateServiceInfo(const ByteArray& txtRecord); private: - void doRegisterService() { - AvahiStringList* txtList; - avahi_string_list_parse(txtRecord.getData(), txtRecord.getSize(), &txtList); - - int result = avahi_entry_group_add_service_strlst(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, static_cast<AvahiPublishFlags>(0), name.c_str(), "_presence._tcp", NULL, NULL, port, txtList); - if (result < 0) { - std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); - } - result = avahi_entry_group_commit(group); - if (result < 0) { - std::cout << "Error registering service: " << avahi_strerror(result) << std::endl; - } - } + void doRegisterService(); static void handleEntryGroupChange(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata) { static_cast<AvahiRegisterQuery*>(userdata)->handleEntryGroupChange(g, state); } - void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state) { - std::cout << "ENtry group callback: " << state << std::endl; - switch (state) { - case AVAHI_ENTRY_GROUP_ESTABLISHED : - // Domain is a hack! - eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>(DNSSDServiceID(name, "local", "_presence._tcp", 0))), shared_from_this()); - std::cout << "Entry group established" << std::endl; - break; - case AVAHI_ENTRY_GROUP_COLLISION : { - std::cout << "Entry group collision" << std::endl; - /*char *n; - n = avahi_alternative_service_name(name); - avahi_free(name); - name = n;*/ - break; - } - - case AVAHI_ENTRY_GROUP_FAILURE : - std::cout << "Entry group failure " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << std::endl; - break; - - case AVAHI_ENTRY_GROUP_UNCOMMITED: - case AVAHI_ENTRY_GROUP_REGISTERING: - ; - - /* - DNSServiceErrorType result = DNSServiceRegister( - &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, - txtRecord.getSize(), txtRecord.getData(), - &AvahiRegisterQuery::handleServiceRegisteredStatic, this); - if (result != kDNSServiceErr_NoError) { - sdRef = NULL; - }*/ - //eventLoop->postEvent(boost::bind(boost::ref(onRegisterFinished), boost::optional<DNSSDServiceID>()), shared_from_this()); - } - } + void handleEntryGroupChange(AvahiEntryGroup* g, AvahiEntryGroupState state); /* static void handleServiceRegisteredStatic(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context) { diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp new file mode 100644 index 0000000..d9a1c5c --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +AvahiResolveHostnameQuery::AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) { + std::cout << "Resolving hostname " << hostname << std::endl; +} + +void AvahiResolveHostnameQuery::run() { + eventLoop->postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this()); +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h index 00712f1..5ee6346 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveHostnameQuery.h @@ -7,10 +7,10 @@ #pragma once #include <string> -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Network/HostAddress.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Network/HostAddress.h> #include <netinet/in.h> @@ -19,13 +19,9 @@ namespace Swift { class AvahiResolveHostnameQuery : public DNSSDResolveHostnameQuery, public AvahiQuery { public: - AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), hostname(hostname) { - std::cout << "Resolving hostname " << hostname << std::endl; - } + AvahiResolveHostnameQuery(const std::string& hostname, int, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop); - void run() { - eventLoop->postEvent(boost::bind(boost::ref(onHostnameResolved), boost::optional<HostAddress>(HostAddress(hostname))), shared_from_this()); - } + void run(); void finish() { } diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp new file mode 100644 index 0000000..ebd2329 --- /dev/null +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h> + +#include <boost/bind.hpp> +#include <iostream> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> + +namespace Swift { + +void AvahiResolveServiceQuery::start() { + std::cout << "Start resolving " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + assert(!resolver); + resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), handleServiceResolvedStatic, this); + if (!resolver) { + std::cout << "Error starting resolver" << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); + } + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiResolveServiceQuery::stop() { + std::cout << "Stop resolving" << std::endl; + avahi_threaded_poll_lock(querier->getThreadedPoll()); + avahi_service_resolver_free(resolver); + resolver = NULL; + avahi_threaded_poll_unlock(querier->getThreadedPoll()); +} + +void AvahiResolveServiceQuery::handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) { + std::cout << "Resolve finished" << std::endl; + switch(event) { + case AVAHI_RESOLVER_FAILURE: + std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl; + eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); + break; + case AVAHI_RESOLVER_FOUND: { + std::cout << "Success" << std::endl; + char a[AVAHI_ADDRESS_STR_MAX]; + avahi_address_snprint(a, sizeof(a), address); + + ByteArray txtRecord; + txtRecord.resize(1024); + avahi_string_list_serialize(txt, vecptr(txtRecord), txtRecord.size()); + + // FIXME: Probably not accurate + std::string fullname = std::string(name) + "." + std::string(type) + "." + std::string(domain) + "."; + std::cout << "Result: " << fullname << "->" << std::string(a) << ":" << port << std::endl; + eventLoop->postEvent( + boost::bind( + boost::ref(onServiceResolved), + Result(fullname, std::string(a), port, txtRecord)), + shared_from_this()); + break; + } + } +} + +} diff --git a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h index e9c4db1..a39d732 100644 --- a/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Avahi/AvahiResolveServiceQuery.h @@ -6,11 +6,13 @@ #pragma once -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <avahi-client/lookup.h> + +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> +#include <Swiften/LinkLocal/LinkLocalServiceInfo.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class AvahiQuerier; @@ -20,59 +22,15 @@ namespace Swift { AvahiResolveServiceQuery(const DNSSDServiceID& service, boost::shared_ptr<AvahiQuerier> querier, EventLoop* eventLoop) : AvahiQuery(querier, eventLoop), service(service), resolver(NULL) { } - void start() { - std::cout << "Start resolving " << service.getName() << " " << service.getType() << " " << service.getDomain() << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - assert(!resolver); - resolver = avahi_service_resolver_new(querier->getClient(), service.getNetworkInterfaceID(), AVAHI_PROTO_UNSPEC, service.getName().c_str(), service.getType().c_str(), service.getDomain().c_str(), AVAHI_PROTO_UNSPEC, static_cast<AvahiLookupFlags>(0), handleServiceResolvedStatic, this); - if (!resolver) { - std::cout << "Error starting resolver" << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); - } - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } - - void stop() { - std::cout << "Stop resolving" << std::endl; - avahi_threaded_poll_lock(querier->getThreadedPoll()); - avahi_service_resolver_free(resolver); - resolver = NULL; - avahi_threaded_poll_unlock(querier->getThreadedPoll()); - } + void start(); + void stop(); private: static void handleServiceResolvedStatic(AvahiServiceResolver* resolver, AvahiIfIndex interfaceIndex, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void* context) { static_cast<AvahiResolveServiceQuery*>(context)->handleServiceResolved(resolver, interfaceIndex, protocol, event, name, type, domain, host_name, address, port, txt, flags); } - void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags) { - std::cout << "Resolve finished" << std::endl; - switch(event) { - case AVAHI_RESOLVER_FAILURE: - std::cout << "Resolve error " << avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(resolver))) << std::endl; - eventLoop->postEvent(boost::bind(boost::ref(onServiceResolved), boost::optional<Result>()), shared_from_this()); - break; - case AVAHI_RESOLVER_FOUND: { - std::cout << "Success" << std::endl; - char a[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(a, sizeof(a), address); - - ByteArray txtRecord; - txtRecord.resize(1024); - avahi_string_list_serialize(txt, txtRecord.getData(), txtRecord.getSize()); - - // FIXME: Probably not accurate - std::string fullname = std::string(name) + "." + std::string(type) + "." + std::string(domain) + "."; - std::cout << "Result: " << fullname << "->" << std::string(a) << ":" << port << std::endl; - eventLoop->postEvent( - boost::bind( - boost::ref(onServiceResolved), - Result(fullname, std::string(a), port, txtRecord)), - shared_from_this()); - break; - } - } - } + void handleServiceResolved(AvahiServiceResolver* resolver, AvahiIfIndex, AvahiProtocol, AvahiResolverEvent event, const char *name, const char * type, const char* domain, const char * /*host_name*/, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags); private: DNSSDServiceID service; diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h index 52c47d7..6e79290 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourBrowseQuery.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class BonjourQuerier; diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp index 2d346d9..530e066 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.cpp @@ -4,17 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h" +#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" +#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> +#include <Swiften/Base/Algorithm.h> namespace Swift { @@ -22,6 +23,7 @@ BonjourQuerier::BonjourQuerier(EventLoop* eventLoop) : eventLoop(eventLoop), sto int fds[2]; int result = pipe(fds); assert(result == 0); + (void) result; interruptSelectReadSocket = fds[0]; fcntl(interruptSelectReadSocket, F_SETFL, fcntl(interruptSelectReadSocket, F_GETFL)|O_NONBLOCK); interruptSelectWriteSocket = fds[1]; @@ -59,8 +61,7 @@ void BonjourQuerier::addRunningQuery(boost::shared_ptr<BonjourQuery> query) { 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()); + erase(runningQueries, query); } } diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h index edd3056..57fde49 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h @@ -9,15 +9,14 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> #include <list> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { - class ByteArray; - class BonjourQuerier : public DNSSDQuerier, public boost::enable_shared_from_this<BonjourQuerier> { diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp index d7ff5d5..9ff4b9f 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h index e3cd9a5..d91c57c 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h @@ -11,7 +11,7 @@ #include <boost/enable_shared_from_this.hpp> #include <boost/thread/mutex.hpp> -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { class BonjourQuerier; diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h index 7eb7ae1..fd0e9d0 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourRegisterQuery.h @@ -6,10 +6,10 @@ #pragma once -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class BonjourQuerier; @@ -19,7 +19,7 @@ namespace Swift { BonjourRegisterQuery(const std::string& name, int port, const ByteArray& txtRecord, boost::shared_ptr<BonjourQuerier> querier, EventLoop* eventLoop) : BonjourQuery(querier, eventLoop) { DNSServiceErrorType result = DNSServiceRegister( &sdRef, 0, 0, name.c_str(), "_presence._tcp", NULL, NULL, port, - txtRecord.getSize(), txtRecord.getData(), + txtRecord.size(), vecptr(txtRecord), &BonjourRegisterQuery::handleServiceRegisteredStatic, this); if (result != kDNSServiceErr_NoError) { sdRef = NULL; @@ -41,7 +41,7 @@ namespace Swift { void updateServiceInfo(const ByteArray& txtRecord) { boost::lock_guard<boost::mutex> lock(sdRefMutex); - DNSServiceUpdateRecord(sdRef, NULL, NULL, txtRecord.getSize(), txtRecord.getData(), 0); + DNSServiceUpdateRecord(sdRef, NULL, NULL, txtRecord.size(), vecptr(txtRecord), 0); } private: diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h index b08b0b7..9fdd3d5 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveHostnameQuery.h @@ -9,10 +9,10 @@ #pragma GCC diagnostic ignored "-Wold-style-cast" #include <string> -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Network/HostAddress.h" +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Network/HostAddress.h> #include <netinet/in.h> diff --git a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h index 0501b56..1fb050c 100644 --- a/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Bonjour/BonjourResolveServiceQuery.h @@ -6,11 +6,11 @@ #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/EventLoop.h" +#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/EventLoop.h> namespace Swift { class BonjourQuerier; @@ -56,7 +56,7 @@ namespace Swift { boost::bind( boost::ref(onServiceResolved), Result(std::string(fullName), std::string(host), port, - ByteArray(reinterpret_cast<const char*>(txtRecord), txtLen))), + createByteArray(reinterpret_cast<const char*>(txtRecord), txtLen))), shared_from_this()); } } diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp index 4e00692..10edb0c 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h index 5871866..c2b3be7 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> namespace Swift { class DNSSDBrowseQuery { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp index 3bc0cf6..0f32aa6 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h index cd55fb7..e6d548b 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDQuerier.h @@ -8,9 +8,9 @@ #include <boost/shared_ptr.hpp> +#include <Swiften/Base/ByteArray.h> + namespace Swift { - - class ByteArray; class DNSSDServiceID; class DNSSDBrowseQuery; class DNSSDRegisterQuery; diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp index 2f931ed..9a807a4 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h index ceff862..e794a90 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h @@ -6,14 +6,13 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> -#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { - class ByteArray; - class DNSSDRegisterQuery { public: virtual ~DNSSDRegisterQuery(); diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp index 0c072bb..dd34e3d 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h index cfaf28f..ee8ffb9 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h @@ -6,10 +6,10 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> -#include "Swiften/Network/HostAddress.h" +#include <Swiften/Network/HostAddress.h> namespace Swift { class DNSSDResolveHostnameQuery { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp index a2f18a6..feb1712 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h index ad73663..c8d78aa 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h @@ -6,11 +6,11 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> -#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class DNSSDResolveServiceQuery { diff --git a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp index 76bd2b7..2f2784c 100644 --- a/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp +++ b/Swiften/LinkLocal/DNSSD/DNSSDServiceID.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" +#include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h index 462e471..b2a6d61 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDBrowseQuery.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> namespace Swift { class FakeDNSSDQuerier; diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp index d7d0228..1ddeffa 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.cpp @@ -4,15 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h> #include <boost/bind.hpp> +#include <iostream> -#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/EventLoop.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Algorithm.h> +#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/EventLoop.h> namespace Swift { @@ -72,8 +75,7 @@ void FakeDNSSDQuerier::addRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) } void FakeDNSSDQuerier::removeRunningQuery(boost::shared_ptr<FakeDNSSDQuery> query) { - runningQueries.erase(std::remove( - runningQueries.begin(), runningQueries.end(), query), runningQueries.end()); + erase(runningQueries, query); } void FakeDNSSDQuerier::addService(const DNSSDServiceID& id) { diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h index b2871c9..f5166ee 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h @@ -11,15 +11,14 @@ #include <list> #include <set> -#include "Swiften/Base/foreach.h" #include <string> -#include "Swiften/EventLoop/EventOwner.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" -#include "Swiften/Network/HostAddress.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/EventOwner.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> +#include <Swiften/Network/HostAddress.h> namespace Swift { - class ByteArray; class FakeDNSSDQuery; class FakeDNSSDBrowseQuery; class EventLoop; @@ -63,8 +62,8 @@ namespace Swift { template<typename T> std::vector< boost::shared_ptr<T> > getAllQueriesEverRun() const { std::vector< boost::shared_ptr<T> > result; - foreach(const boost::shared_ptr<FakeDNSSDQuery>& query, allQueriesEverRun) { - if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(query)) { + for (QueryList::const_iterator i = allQueriesEverRun.begin(); i != allQueriesEverRun.end(); ++i) { + if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(*i)) { result.push_back(resultQuery); } } @@ -75,8 +74,8 @@ namespace Swift { 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)) { + for (QueryList::const_iterator i = runningQueries.begin(); i != runningQueries.end(); ++i) { + if (boost::shared_ptr<T> resultQuery = boost::dynamic_pointer_cast<T>(*i)) { result.push_back(resultQuery); } } @@ -86,8 +85,9 @@ namespace Swift { private: std::string domain; EventLoop* eventLoop; - std::list< boost::shared_ptr<FakeDNSSDQuery> > runningQueries; - std::list< boost::shared_ptr<FakeDNSSDQuery> > allQueriesEverRun; + typedef std::list< boost::shared_ptr<FakeDNSSDQuery> > QueryList; + QueryList runningQueries; + QueryList allQueriesEverRun; 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 index a27f61c..99f55fa 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h> +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h index 479c41f..b6d5c98 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { class FakeDNSSDQuerier; diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h index a6ae17a..c568f5b 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDRegisterQuery.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> +#include <Swiften/Base/ByteArray.h> #include <string> namespace Swift { diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h index cbaa6e6..aa427cc 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveHostnameQuery.h @@ -7,9 +7,9 @@ #pragma once #include <string> -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" -#include "Swiften/Network/HostAddress.h" +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h> +#include <Swiften/Network/HostAddress.h> namespace Swift { class FakeDNSSDQuerier; diff --git a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h index 3d4a3b9..5c69843 100644 --- a/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h +++ b/Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> +#include <Swiften/LinkLocal/LinkLocalServiceInfo.h> namespace Swift { class FakeDNSSDQuerier; diff --git a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp index 7a42129..cc12573 100644 --- a/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp +++ b/Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h" +#include <Swiften/LinkLocal/DNSSD/PlatformDNSSDQuerierFactory.h> #if defined(HAVE_BONJOUR) -#include "Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Bonjour/BonjourQuerier.h> #elif defined(HAVE_AVAHI) -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> #endif diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp index 3af6d4c..c4dea64 100644 --- a/Swiften/LinkLocal/IncomingLinkLocalSession.cpp +++ b/Swiften/LinkLocal/IncomingLinkLocalSession.cpp @@ -4,17 +4,17 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/IncomingLinkLocalSession.h" +#include <Swiften/LinkLocal/IncomingLinkLocalSession.h> #include <boost/bind.hpp> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/StreamStack/StreamStack.h" -#include "Swiften/StreamStack/ConnectionLayer.h" -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/Elements/StreamFeatures.h" -#include "Swiften/Elements/IQ.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/StreamStack/StreamStack.h> +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/Elements/StreamFeatures.h> +#include <Swiften/Elements/IQ.h> namespace Swift { diff --git a/Swiften/LinkLocal/IncomingLinkLocalSession.h b/Swiften/LinkLocal/IncomingLinkLocalSession.h index a586a2e..68e21a5 100644 --- a/Swiften/LinkLocal/IncomingLinkLocalSession.h +++ b/Swiften/LinkLocal/IncomingLinkLocalSession.h @@ -7,11 +7,11 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Session/Session.h" -#include "Swiften/JID/JID.h" -#include "Swiften/Network/Connection.h" +#include <Swiften/Session/Session.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Network/Connection.h> namespace Swift { class ProtocolHeader; diff --git a/Swiften/LinkLocal/LinkLocalConnector.cpp b/Swiften/LinkLocal/LinkLocalConnector.cpp index 42366e8..af96e65 100644 --- a/Swiften/LinkLocal/LinkLocalConnector.cpp +++ b/Swiften/LinkLocal/LinkLocalConnector.cpp @@ -4,16 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/LinkLocalConnector.h" +#include <Swiften/LinkLocal/LinkLocalConnector.h> #include <boost/bind.hpp> -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/ConnectionFactory.h" -#include "Swiften/Network/HostAddress.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h> namespace Swift { diff --git a/Swiften/LinkLocal/LinkLocalConnector.h b/Swiften/LinkLocal/LinkLocalConnector.h index 0fbb7ec..0acdc51 100644 --- a/Swiften/LinkLocal/LinkLocalConnector.h +++ b/Swiften/LinkLocal/LinkLocalConnector.h @@ -7,12 +7,12 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/enable_shared_from_this.hpp> #include <vector> -#include "Swiften/Network/Connection.h" -#include "Swiften/LinkLocal/LinkLocalService.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/LinkLocal/LinkLocalService.h> namespace Swift { class ConnectionFactory; diff --git a/Swiften/LinkLocal/LinkLocalService.cpp b/Swiften/LinkLocal/LinkLocalService.cpp index c8d707d..7c6538c 100644 --- a/Swiften/LinkLocal/LinkLocalService.cpp +++ b/Swiften/LinkLocal/LinkLocalService.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/LinkLocalService.h" +#include <Swiften/LinkLocal/LinkLocalService.h> namespace Swift { diff --git a/Swiften/LinkLocal/LinkLocalService.h b/Swiften/LinkLocal/LinkLocalService.h index 2e74338..2b7f7b2 100644 --- a/Swiften/LinkLocal/LinkLocalService.h +++ b/Swiften/LinkLocal/LinkLocalService.h @@ -7,10 +7,10 @@ #pragma once #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include <Swiften/JID/JID.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> +#include <Swiften/LinkLocal/LinkLocalServiceInfo.h> namespace Swift { class LinkLocalService { diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp index 8393ade..4b68a33 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.cpp @@ -7,9 +7,9 @@ #include <boost/bind.hpp> #include <iostream> -#include "Swiften/LinkLocal/LinkLocalServiceBrowser.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" -#include "Swiften/Network/HostAddress.h" +#include <Swiften/LinkLocal/LinkLocalServiceBrowser.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> +#include <Swiften/Network/HostAddress.h> namespace Swift { diff --git a/Swiften/LinkLocal/LinkLocalServiceBrowser.h b/Swiften/LinkLocal/LinkLocalServiceBrowser.h index 56b4aa4..57ed969 100644 --- a/Swiften/LinkLocal/LinkLocalServiceBrowser.h +++ b/Swiften/LinkLocal/LinkLocalServiceBrowser.h @@ -6,19 +6,19 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> #include <map> #include <vector> #include <string> -#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" +#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 { diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp index bec2e97..516d303 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.cpp +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.cpp @@ -4,40 +4,43 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include <Swiften/LinkLocal/LinkLocalServiceInfo.h> #include <boost/lexical_cast.hpp> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/Concat.h> + namespace Swift { ByteArray LinkLocalServiceInfo::toTXTRecord() const { ByteArray result(getEncoded("txtvers=1")); if (!firstName.empty()) { - result += getEncoded("1st=" + firstName); + append(result, getEncoded("1st=" + firstName)); } if (!lastName.empty()) { - result += getEncoded("last=" + lastName); + append(result, getEncoded("last=" + lastName)); } if (!email.empty()) { - result += getEncoded("email=" + email); + append(result, getEncoded("email=" + email)); } if (jid.isValid()) { - result += getEncoded("jid=" + jid.toString()); + append(result, getEncoded("jid=" + jid.toString())); } if (!message.empty()) { - result += getEncoded("msg=" + message); + append(result, getEncoded("msg=" + message)); } if (!nick.empty()) { - result += getEncoded("nick=" + nick); + append(result, getEncoded("nick=" + nick)); } if (port) { - result += getEncoded("port.p2pj=" + std::string(boost::lexical_cast<std::string>(*port))); + append(result, getEncoded("port.p2pj=" + std::string(boost::lexical_cast<std::string>(*port)))); } switch (status) { - case Available: result += getEncoded("status=avail"); break; - case Away: result += getEncoded("status=away"); break; - case DND: result += getEncoded("status=dnd"); break; + case Available: append(result, getEncoded("status=avail")); break; + case Away: append(result, getEncoded("status=away")); break; + case DND: append(result, getEncoded("status=dnd")); break; } return result; @@ -47,13 +50,14 @@ ByteArray LinkLocalServiceInfo::getEncoded(const std::string& s) { ByteArray sizeByte; sizeByte.resize(1); sizeByte[0] = s.size(); - return sizeByte + ByteArray(s); + return concat(sizeByte, createByteArray(s)); } LinkLocalServiceInfo LinkLocalServiceInfo::createFromTXTRecord(const ByteArray& record) { LinkLocalServiceInfo info; size_t i = 0; - while (i < record.getSize()) { + size_t recordCount = record.size(); + while (i < recordCount) { std::pair<std::string,std::string> entry = readEntry(record, &i); if (entry.first.empty()) { break; @@ -99,7 +103,7 @@ std::pair<std::string,std::string> LinkLocalServiceInfo::readEntry(const ByteArr size_t entryEnd = i + 1 + record[i]; ++i; bool inKey = true; - while (i < entryEnd && i < record.getSize()) { + while (i < entryEnd && i < record.size()) { if (inKey) { if (record[i] == '=') { inKey = false; diff --git a/Swiften/LinkLocal/LinkLocalServiceInfo.h b/Swiften/LinkLocal/LinkLocalServiceInfo.h index a166c64..79a8cb8 100644 --- a/Swiften/LinkLocal/LinkLocalServiceInfo.h +++ b/Swiften/LinkLocal/LinkLocalServiceInfo.h @@ -8,9 +8,9 @@ #include <boost/optional.hpp> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> #include <string> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> namespace Swift { diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp index 65542d2..9d712f8 100644 --- a/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp +++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.cpp @@ -4,14 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/LinkLocal/OutgoingLinkLocalSession.h" +#include <Swiften/LinkLocal/OutgoingLinkLocalSession.h> #include <boost/bind.hpp> -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Elements/StreamFeatures.h" -#include "Swiften/Elements/IQ.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Elements/StreamFeatures.h> +#include <Swiften/Elements/IQ.h> namespace Swift { diff --git a/Swiften/LinkLocal/OutgoingLinkLocalSession.h b/Swiften/LinkLocal/OutgoingLinkLocalSession.h index 34ea411..430c446 100644 --- a/Swiften/LinkLocal/OutgoingLinkLocalSession.h +++ b/Swiften/LinkLocal/OutgoingLinkLocalSession.h @@ -7,12 +7,12 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/enable_shared_from_this.hpp> #include <vector> -#include "Swiften/Session/Session.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Session/Session.h> +#include <Swiften/JID/JID.h> namespace Swift { class ConnectionFactory; diff --git a/Swiften/LinkLocal/SConscript b/Swiften/LinkLocal/SConscript index 6edf993..29ea692 100644 --- a/Swiften/LinkLocal/SConscript +++ b/Swiften/LinkLocal/SConscript @@ -31,7 +31,11 @@ elif myenv.get("HAVE_AVAHI", 0) : myenv.Append(CPPDEFINES = ["HAVE_AVAHI"]) sources += [ "DNSSD/Avahi/AvahiQuerier.cpp", - "DNSSD/Avahi/AvahiQuery.cpp" + "DNSSD/Avahi/AvahiQuery.cpp", + "DNSSD/Avahi/AvahiResolveHostnameQuery.cpp", + "DNSSD/Avahi/AvahiResolveServiceQuery.cpp", + "DNSSD/Avahi/AvahiRegisterQuery.cpp", + "DNSSD/Avahi/AvahiBrowseQuery.cpp", ] objects = myenv.SwiftenObject(sources) diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp index 98deed1..474c772 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalConnectorTest.cpp @@ -7,13 +7,15 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/LinkLocal/LinkLocalConnector.h" -#include "Swiften/LinkLocal/LinkLocalService.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDServiceID.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h" -#include "Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h" -#include "Swiften/EventLoop/DummyEventLoop.h" -#include "Swiften/Network/FakeConnection.h" +#include <boost/bind.hpp> + +#include <Swiften/LinkLocal/LinkLocalConnector.h> +#include <Swiften/LinkLocal/LinkLocalService.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDServiceID.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveHostnameQuery.h> +#include <Swiften/LinkLocal/DNSSD/Fake/FakeDNSSDQuerier.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/Network/FakeConnection.h> using namespace Swift; diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp index 9c4c288..c0fd248 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceBrowserTest.cpp @@ -9,13 +9,13 @@ #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/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h" -#include "Swiften/EventLoop/DummyEventLoop.h" +#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/LinkLocal/DNSSD/Fake/FakeDNSSDResolveServiceQuery.h> +#include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp index 3943e31..314b46a 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceInfoTest.cpp @@ -4,12 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" +#include <Swiften/LinkLocal/LinkLocalServiceInfo.h> using namespace Swift; @@ -28,11 +29,11 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture { info.setLastName("Tron\xc3\xe7on"); info.setStatus(LinkLocalServiceInfo::Away); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x09txtvers=1\x09" + std::string("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away")), info.toTXTRecord()); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x09txtvers=1\x09" + std::string("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away")), info.toTXTRecord()); } void testCreateFromTXTRecord() { - LinkLocalServiceInfo info = LinkLocalServiceInfo::createFromTXTRecord(ByteArray("\x09txtvers=1\x09" + std::string("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away"))); + LinkLocalServiceInfo info = LinkLocalServiceInfo::createFromTXTRecord(createByteArray("\x09txtvers=1\x09" + std::string("1st=Remko\x0dlast=Tron\xc3\xe7on\x0bstatus=away"))); CPPUNIT_ASSERT_EQUAL(std::string("Remko"), info.getFirstName()); CPPUNIT_ASSERT_EQUAL(std::string("Tron\xc3\xe7on"), info.getLastName()); @@ -40,7 +41,7 @@ class LinkLocalServiceInfoTest : public CppUnit::TestFixture { } void testCreateFromTXTRecord_InvalidSize() { - LinkLocalServiceInfo info = LinkLocalServiceInfo::createFromTXTRecord(ByteArray("\x10last=a")); + LinkLocalServiceInfo info = LinkLocalServiceInfo::createFromTXTRecord(createByteArray("\x10last=a")); CPPUNIT_ASSERT_EQUAL(std::string("a"), info.getLastName()); } diff --git a/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp index 4835bde..2e3e1bb 100644 --- a/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp +++ b/Swiften/LinkLocal/UnitTest/LinkLocalServiceTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/LinkLocal/LinkLocalService.h" +#include <Swiften/LinkLocal/LinkLocalService.h> using namespace Swift; diff --git a/Swiften/MUC/MUC.cpp b/Swiften/MUC/MUC.cpp index 68a5a86..6fe8f19 100644 --- a/Swiften/MUC/MUC.cpp +++ b/Swiften/MUC/MUC.cpp @@ -4,21 +4,25 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/MUC/MUC.h" +#include <Swiften/MUC/MUC.h> #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> #include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Presence/DirectedPresenceSender.h" -#include "Swiften/Client/StanzaChannel.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Elements/Form.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/MUCUserPayload.h" -#include "Swiften/Elements/MUCPayload.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/Queries/GenericRequest.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/Client/StanzaChannel.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/MUCUserPayload.h> +#include <Swiften/Elements/MUCAdminPayload.h> +#include <Swiften/Elements/MUCPayload.h> +#include <Swiften/Elements/MUCDestroyPayload.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Queries/GenericRequest.h> namespace Swift { @@ -93,7 +97,7 @@ void MUC::handleIncomingPresence(Presence::ref presence) { MUCUserPayload::ref mucPayload; foreach (MUCUserPayload::ref payload, presence->getPayloads<MUCUserPayload>()) { - if (payload->getItems().size() > 0 || payload->getStatusCodes().size() > 0) { + if (!payload->getItems().empty() || !payload->getStatusCodes().empty()) { mucPayload = payload; } } @@ -120,8 +124,8 @@ void MUC::handleIncomingPresence(Presence::ref presence) { MUCOccupant::Affiliation affiliation(MUCOccupant::NoAffiliation); boost::optional<JID> realJID; if (mucPayload && mucPayload->getItems().size() > 0) { - role = mucPayload->getItems()[0].role; - affiliation = mucPayload->getItems()[0].affiliation; + role = mucPayload->getItems()[0].role ? mucPayload->getItems()[0].role.get() : MUCOccupant::NoRole; + affiliation = mucPayload->getItems()[0].affiliation ? mucPayload->getItems()[0].affiliation.get() : MUCOccupant::NoAffiliation; realJID = mucPayload->getItems()[0].realJID; } @@ -196,7 +200,6 @@ void MUC::handleIncomingPresence(Presence::ref presence) { } } } - } void MUC::handleCreationConfigResponse(MUCOwnerPayload::ref /*unused*/, ErrorPayload::ref error) { @@ -216,7 +219,72 @@ MUCOccupant MUC::getOccupant(const std::string& nick) { return occupants.find(nick)->second; } -//FIXME: Recognise Topic changes +void MUC::kickUser(const JID& jid) { + MUCAdminPayload::ref mucPayload = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.role = MUCOccupant::NoRole; + item.nick = jid.getResource(); + mucPayload->addItem(item); + GenericRequest<MUCAdminPayload>* request = new GenericRequest<MUCAdminPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUC::handleKickResponse, this, _1, _2, jid)); + request->send(); +} + +void MUC::handleKickResponse(MUCAdminPayload::ref /*unused*/, ErrorPayload::ref error, const JID& jid) { + if (error) { + onKickFailed(error, jid); + } +} + +void MUC::changeSubject(const std::string& subject) { + Message::ref message = boost::make_shared<Message>(); + message->setSubject(subject); + message->setType(Message::Groupchat); + message->setTo(ownMUCJID.toBare()); + stanzaChannel->sendMessage(message); +} + +void MUC::requestConfigurationForm() { + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Get, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUC::handleConfigurationFormReceived, this, _1, _2)); + request->send(); +} + +void MUC::handleConfigurationFormReceived(MUCOwnerPayload::ref payload, ErrorPayload::ref error) { + Form::ref form; + if (payload) { + form = payload->getForm(); + } + if (error || !form) { + onConfigurationFailed(error); + } else { + onConfigurationFormReceived(form); + } +} + +void MUC::handleConfigurationResultReceived(MUCOwnerPayload::ref /*payload*/, ErrorPayload::ref error) { + if (error) { + onConfigurationFailed(error); + } +} + +void MUC::configureRoom(Form::ref form) { + MUCOwnerPayload::ref mucPayload(new MUCOwnerPayload()); + mucPayload->setPayload(form); + GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUC::handleConfigurationResultReceived, this, _1, _2)); + request->send(); +} + +void MUC::destroyRoom() { + MUCOwnerPayload::ref mucPayload = boost::make_shared<MUCOwnerPayload>(); + MUCDestroyPayload::ref mucDestroyPayload = boost::make_shared<MUCDestroyPayload>(); + mucPayload->setPayload(mucDestroyPayload); + GenericRequest<MUCOwnerPayload>* request = new GenericRequest<MUCOwnerPayload>(IQ::Set, getJID(), mucPayload, iqRouter_); + request->onResponse.connect(boost::bind(&MUC::handleConfigurationResultReceived, this, _1, _2)); + request->send(); +} //TODO: Invites(direct/mediated) diff --git a/Swiften/MUC/MUC.h b/Swiften/MUC/MUC.h index 278ef95..b99c4b4 100644 --- a/Swiften/MUC/MUC.h +++ b/Swiften/MUC/MUC.h @@ -6,16 +6,18 @@ #pragma once -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> #include <string> -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/MUCOccupant.h" -#include "Swiften/MUC/MUCRegistry.h" -#include "Swiften/Elements/MUCOwnerPayload.h" +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Elements/MUCOwnerPayload.h> +#include <Swiften/Elements/MUCAdminPayload.h> +#include <Swiften/Elements/Form.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/signals/connection.hpp> #include <map> @@ -54,14 +56,22 @@ namespace Swift { /** Get occupant information*/ MUCOccupant getOccupant(const std::string& nick); bool hasOccupant(const std::string& nick); + void kickUser(const JID& jid); + void changeSubject(const std::string& subject); + void requestConfigurationForm(); + void configureRoom(Form::ref); + void destroyRoom(); public: boost::signal<void (const std::string& /*nick*/)> onJoinComplete; boost::signal<void (ErrorPayload::ref)> onJoinFailed; + boost::signal<void (ErrorPayload::ref, const JID&)> onKickFailed; + boost::signal<void (ErrorPayload::ref)> onConfigurationFailed; boost::signal<void (Presence::ref)> onOccupantPresenceChange; boost::signal<void (const std::string&, const MUCOccupant& /*now*/, const MUCOccupant::Role& /*old*/)> onOccupantRoleChanged; boost::signal<void (const std::string&, const MUCOccupant::Affiliation& /*new*/, const MUCOccupant::Affiliation& /*old*/)> onOccupantAffiliationChanged; boost::signal<void (const MUCOccupant&)> onOccupantJoined; boost::signal<void (const MUCOccupant&, LeavingType, const std::string& /*reason*/)> onOccupantLeft; + boost::signal<void (Form::ref)> onConfigurationFormReceived; /* boost::signal<void (const MUCInfo&)> onInfoResult; */ /* boost::signal<void (const blah&)> onItemsResult; */ @@ -79,6 +89,9 @@ namespace Swift { void handleIncomingPresence(Presence::ref presence); void internalJoin(const std::string& nick); void handleCreationConfigResponse(MUCOwnerPayload::ref, ErrorPayload::ref); + void handleKickResponse(MUCAdminPayload::ref, ErrorPayload::ref, const JID&); + void handleConfigurationFormReceived(MUCOwnerPayload::ref, ErrorPayload::ref); + void handleConfigurationResultReceived(MUCOwnerPayload::ref, ErrorPayload::ref); private: JID ownMUCJID; diff --git a/Swiften/MUC/MUCBookmark.h b/Swiften/MUC/MUCBookmark.h index 10e1b78..3f612c4 100644 --- a/Swiften/MUC/MUCBookmark.h +++ b/Swiften/MUC/MUCBookmark.h @@ -9,8 +9,8 @@ #include <boost/optional.hpp> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/Storage.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Storage.h> namespace Swift { class MUCBookmark { diff --git a/Swiften/MUC/MUCBookmarkManager.cpp b/Swiften/MUC/MUCBookmarkManager.cpp index d0855cd..643a8c4 100644 --- a/Swiften/MUC/MUCBookmarkManager.cpp +++ b/Swiften/MUC/MUCBookmarkManager.cpp @@ -9,9 +9,10 @@ #include <boost/bind.hpp> #include <iostream> -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/Requests/GetPrivateStorageRequest.h" -#include "Swiften/Queries/Requests/SetPrivateStorageRequest.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/Requests/GetPrivateStorageRequest.h> +#include <Swiften/Queries/Requests/SetPrivateStorageRequest.h> namespace Swift { @@ -85,7 +86,7 @@ void MUCBookmarkManager::addBookmark(const MUCBookmark& bookmark) { void MUCBookmarkManager::removeBookmark(const MUCBookmark& bookmark) { if (!ready_) return; std::vector<MUCBookmark>::iterator it; - for (it = bookmarks_.begin(); it != bookmarks_.end(); it++) { + for (it = bookmarks_.begin(); it != bookmarks_.end(); ++it) { if ((*it) == bookmark) { bookmarks_.erase(it); onBookmarkRemoved(bookmark); diff --git a/Swiften/MUC/MUCBookmarkManager.h b/Swiften/MUC/MUCBookmarkManager.h index 39699df..ccea46c 100644 --- a/Swiften/MUC/MUCBookmarkManager.h +++ b/Swiften/MUC/MUCBookmarkManager.h @@ -9,12 +9,12 @@ #include <vector> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> -#include "Swiften/MUC/MUCBookmark.h" -#include "Swiften/Elements/Storage.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/MUC/MUCBookmark.h> +#include <Swiften/Elements/Storage.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { class IQRouter; diff --git a/Swiften/MUC/MUCManager.cpp b/Swiften/MUC/MUCManager.cpp index 8950029..6e9b820 100644 --- a/Swiften/MUC/MUCManager.cpp +++ b/Swiften/MUC/MUCManager.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/MUC/MUCManager.h" +#include <Swiften/MUC/MUCManager.h> namespace Swift { diff --git a/Swiften/MUC/MUCManager.h b/Swiften/MUC/MUCManager.h index 0efdf9a..36ae61e 100644 --- a/Swiften/MUC/MUCManager.h +++ b/Swiften/MUC/MUCManager.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/MUC/MUC.h" +#include <Swiften/MUC/MUC.h> namespace Swift { class IQRouter; diff --git a/Swiften/MUC/MUCRegistry.cpp b/Swiften/MUC/MUCRegistry.cpp index e433165..f4d061e 100644 --- a/Swiften/MUC/MUCRegistry.cpp +++ b/Swiften/MUC/MUCRegistry.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/MUC/MUCRegistry.h" +#include <Swiften/MUC/MUCRegistry.h> -#include <algorithm> +#include <Swiften/Base/Algorithm.h> namespace Swift { @@ -22,7 +22,7 @@ void MUCRegistry::addMUC(const JID& j) { } void MUCRegistry::removeMUC(const JID& j) { - mucs.erase(std::remove(mucs.begin(), mucs.end(), j), mucs.end()); + erase(mucs, j); } diff --git a/Swiften/MUC/MUCRegistry.h b/Swiften/MUC/MUCRegistry.h index 6356931..0ed2d2e 100644 --- a/Swiften/MUC/MUCRegistry.h +++ b/Swiften/MUC/MUCRegistry.h @@ -8,7 +8,7 @@ #include <vector> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> namespace Swift { class JID; diff --git a/Swiften/MUC/UnitTest/MUCTest.cpp b/Swiften/MUC/UnitTest/MUCTest.cpp index 117760c..427e938 100644 --- a/Swiften/MUC/UnitTest/MUCTest.cpp +++ b/Swiften/MUC/UnitTest/MUCTest.cpp @@ -15,6 +15,11 @@ #include <Swiften/Presence/StanzaChannelPresenceSender.h> #include <Swiften/Presence/DirectedPresenceSender.h> #include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/MUCUserPayload.h> +#include <Swiften/Elements/MUCOwnerPayload.h> +#include <Swiften/Elements/VCard.h> +#include <Swiften/Elements/CapsInfo.h> + using namespace Swift; @@ -23,6 +28,8 @@ class MUCTest : public CppUnit::TestFixture { CPPUNIT_TEST(testJoin); CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinDoesNotSendPresenceBeforeJoinSuccess); CPPUNIT_TEST(testJoin_ChangePresenceDuringJoinResendsPresenceAfterJoinSuccess); + CPPUNIT_TEST(testCreateInstant); + CPPUNIT_TEST(testReplicateBug); /*CPPUNIT_TEST(testJoin_Success); CPPUNIT_TEST(testJoin_Fail);*/ CPPUNIT_TEST_SUITE_END(); @@ -76,6 +83,64 @@ class MUCTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Test"), p->getStatus()); } + void testCreateInstant() { + MUC::ref testling = createMUC(JID("rabbithole@wonderland.lit")); + testling->joinAs("Alice"); + Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); + serverRespondsLocked->setFrom(JID("rabbithole@wonderland.lit/Alice")); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Owner; + myItem.role = MUCOccupant::Moderator; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(MUCUserPayload::StatusCode(110)); + mucPayload->addStatusCode(MUCUserPayload::StatusCode(201)); + serverRespondsLocked->addPayload(mucPayload); + channel->onPresenceReceived(serverRespondsLocked); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(channel->sentStanzas.size())); + IQ::ref iq = channel->getStanzaAtIndex<IQ>(1); + CPPUNIT_ASSERT(iq); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm()); + CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); + } + + void testReplicateBug() { + Presence::ref initialPresence = boost::make_shared<Presence>(); + initialPresence->setStatus(""); + VCard::ref vcard = boost::make_shared<VCard>(); + vcard->setPhoto(createByteArray("15c30080ae98ec48be94bf0e191d43edd06e500a")); + initialPresence->addPayload(vcard); + CapsInfo::ref caps = boost::make_shared<CapsInfo>(); + caps->setNode("http://swift.im"); + caps->setVersion("p2UP0DrcVgKM6jJqYN/B92DKK0o="); + initialPresence->addPayload(caps); + channel->sendPresence(initialPresence); + + MUC::ref testling = createMUC(JID("test@rooms.swift.im")); + testling->joinAs("Test"); + Presence::ref serverRespondsLocked = boost::make_shared<Presence>(); + serverRespondsLocked->setFrom(JID("test@rooms.swift.im/Test")); + serverRespondsLocked->setTo(JID("test@swift.im/6913d576d55f0b67")); + serverRespondsLocked->addPayload(vcard); + serverRespondsLocked->addPayload(caps); + serverRespondsLocked->setStatus(""); + MUCUserPayload::ref mucPayload(new MUCUserPayload()); + MUCItem myItem; + myItem.affiliation = MUCOccupant::Owner; + myItem.role = MUCOccupant::Moderator; + mucPayload->addItem(myItem); + mucPayload->addStatusCode(MUCUserPayload::StatusCode(201)); + serverRespondsLocked->addPayload(mucPayload); + channel->onPresenceReceived(serverRespondsLocked); + CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(channel->sentStanzas.size())); + IQ::ref iq = channel->getStanzaAtIndex<IQ>(2); + CPPUNIT_ASSERT(iq); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()); + CPPUNIT_ASSERT(iq->getPayload<MUCOwnerPayload>()->getForm()); + CPPUNIT_ASSERT_EQUAL(Form::SubmitType, iq->getPayload<MUCOwnerPayload>()->getForm()->getType()); + } + /*void testJoin_Success() { MUC::ref testling = createMUC(JID("foo@bar.com")); testling->onJoinFinished.connect(boost::bind(&MUCTest::handleJoinFinished, this, _1, _2)); diff --git a/Swiften/Network/BoostConnection.cpp b/Swiften/Network/BoostConnection.cpp index f7ff8c4..043743e 100644 --- a/Swiften/Network/BoostConnection.cpp +++ b/Swiften/Network/BoostConnection.cpp @@ -4,18 +4,24 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostConnection.h" +#include <Swiften/Network/BoostConnection.h> #include <iostream> +#include <string> +#include <algorithm> #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <boost/asio/placeholders.hpp> +#include <boost/asio/write.hpp> +#include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Base/Log.h> -#include "Swiften/EventLoop/EventLoop.h" -#include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/Base/sleep.h" +#include <Swiften/Base/Algorithm.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Base/sleep.h> +#include <Swiften/Base/SafeAllocator.h> namespace Swift { @@ -26,8 +32,8 @@ static const size_t BUFFER_SIZE = 4096; // A reference-counted non-modifiable buffer class. class SharedBuffer { public: - SharedBuffer(const ByteArray& data) : - data_(new std::vector<char>(data.begin(), data.end())), + SharedBuffer(const SafeByteArray& data) : + data_(new std::vector<char, SafeAllocator<char> >(data.begin(), data.end())), buffer_(boost::asio::buffer(*data_)) { } @@ -38,14 +44,14 @@ class SharedBuffer { const boost::asio::const_buffer* end() const { return &buffer_ + 1; } private: - boost::shared_ptr< std::vector<char> > data_; + boost::shared_ptr< std::vector<char, SafeAllocator<char> > > data_; boost::asio::const_buffer buffer_; }; // ----------------------------------------------------------------------------- BoostConnection::BoostConnection(boost::shared_ptr<boost::asio::io_service> ioService, EventLoop* eventLoop) : - eventLoop(eventLoop), ioService(ioService), socket_(*ioService), readBuffer_(BUFFER_SIZE), writing_(false) { + eventLoop(eventLoop), ioService(ioService), socket_(*ioService), writing_(false) { } BoostConnection::~BoostConnection() { @@ -75,18 +81,18 @@ void BoostConnection::disconnect() { socket_.close(); } -void BoostConnection::write(const ByteArray& data) { +void BoostConnection::write(const SafeByteArray& data) { boost::lock_guard<boost::mutex> lock(writeMutex_); if (!writing_) { writing_ = true; doWrite(data); } else { - writeQueue_ += data; + append(writeQueue_, data); } } -void BoostConnection::doWrite(const ByteArray& data) { +void BoostConnection::doWrite(const SafeByteArray& data) { boost::asio::async_write(socket_, SharedBuffer(data), boost::bind(&BoostConnection::handleDataWritten, shared_from_this(), boost::asio::placeholders::error)); } @@ -103,15 +109,17 @@ void BoostConnection::handleConnectFinished(const boost::system::error_code& err } void BoostConnection::doRead() { + readBuffer_ = boost::make_shared<SafeByteArray>(BUFFER_SIZE); socket_.async_read_some( - boost::asio::buffer(readBuffer_), + boost::asio::buffer(*readBuffer_), boost::bind(&BoostConnection::handleSocketRead, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } void BoostConnection::handleSocketRead(const boost::system::error_code& error, size_t bytesTransferred) { SWIFT_LOG(debug) << "Socket read " << error << std::endl; if (!error) { - eventLoop->postEvent(boost::bind(boost::ref(onDataRead), ByteArray(&readBuffer_[0], bytesTransferred)), shared_from_this()); + readBuffer_->resize(bytesTransferred); + eventLoop->postEvent(boost::bind(boost::ref(onDataRead), readBuffer_), shared_from_this()); doRead(); } else if (/*error == boost::asio::error::eof ||*/ error == boost::asio::error::operation_aborted) { @@ -135,7 +143,7 @@ void BoostConnection::handleDataWritten(const boost::system::error_code& error) } { boost::lock_guard<boost::mutex> lock(writeMutex_); - if (writeQueue_.isEmpty()) { + if (writeQueue_.empty()) { writing_ = false; } else { diff --git a/Swiften/Network/BoostConnection.h b/Swiften/Network/BoostConnection.h index 506eedf..7d5ec60 100644 --- a/Swiften/Network/BoostConnection.h +++ b/Swiften/Network/BoostConnection.h @@ -6,12 +6,14 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/ip/tcp.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/thread/mutex.hpp> -#include "Swiften/Network/Connection.h" -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/EventLoop/EventOwner.h> +#include <Swiften/Base/SafeByteArray.h> namespace boost { class thread; @@ -36,7 +38,7 @@ namespace Swift { virtual void listen(); virtual void connect(const HostAddressPort& address); virtual void disconnect(); - virtual void write(const ByteArray& data); + virtual void write(const SafeByteArray& data); boost::asio::ip::tcp::socket& getSocket() { return socket_; @@ -51,15 +53,15 @@ namespace Swift { void handleSocketRead(const boost::system::error_code& error, size_t bytesTransferred); void handleDataWritten(const boost::system::error_code& error); void doRead(); - void doWrite(const ByteArray& data); + void doWrite(const SafeByteArray& data); private: EventLoop* eventLoop; boost::shared_ptr<boost::asio::io_service> ioService; boost::asio::ip::tcp::socket socket_; - std::vector<char> readBuffer_; + boost::shared_ptr<SafeByteArray> readBuffer_; boost::mutex writeMutex_; bool writing_; - ByteArray writeQueue_; + SafeByteArray writeQueue_; }; } diff --git a/Swiften/Network/BoostConnectionFactory.cpp b/Swiften/Network/BoostConnectionFactory.cpp index 743bb61..d5f9fad 100644 --- a/Swiften/Network/BoostConnectionFactory.cpp +++ b/Swiften/Network/BoostConnectionFactory.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostConnectionFactory.h" -#include "Swiften/Network/BoostConnection.h" +#include <Swiften/Network/BoostConnectionFactory.h> +#include <Swiften/Network/BoostConnection.h> namespace Swift { diff --git a/Swiften/Network/BoostConnectionFactory.h b/Swiften/Network/BoostConnectionFactory.h index ea9d656..c0a105b 100644 --- a/Swiften/Network/BoostConnectionFactory.h +++ b/Swiften/Network/BoostConnectionFactory.h @@ -6,10 +6,10 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> -#include "Swiften/Network/ConnectionFactory.h" -#include "Swiften/Network/BoostConnection.h" +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/BoostConnection.h> namespace Swift { class BoostConnection; diff --git a/Swiften/Network/BoostConnectionServer.cpp b/Swiften/Network/BoostConnectionServer.cpp index 27a1008..eccffc6 100644 --- a/Swiften/Network/BoostConnectionServer.cpp +++ b/Swiften/Network/BoostConnectionServer.cpp @@ -4,12 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostConnectionServer.h" +#include <Swiften/Network/BoostConnectionServer.h> #include <boost/bind.hpp> #include <boost/system/system_error.hpp> +#include <boost/asio/placeholders.hpp> -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { diff --git a/Swiften/Network/BoostConnectionServer.h b/Swiften/Network/BoostConnectionServer.h index aba9e3e..56dc8bd 100644 --- a/Swiften/Network/BoostConnectionServer.h +++ b/Swiften/Network/BoostConnectionServer.h @@ -7,13 +7,14 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/ip/tcp.hpp> #include <boost/enable_shared_from_this.hpp> -#include <boost/asio.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Network/BoostConnection.h" -#include "Swiften/Network/ConnectionServer.h" -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/Network/BoostConnection.h> +#include <Swiften/Network/ConnectionServer.h> +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { class BoostConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<BoostConnectionServer> { diff --git a/Swiften/Network/BoostIOServiceThread.cpp b/Swiften/Network/BoostIOServiceThread.cpp index 031e7b5..c98a653 100644 --- a/Swiften/Network/BoostIOServiceThread.cpp +++ b/Swiften/Network/BoostIOServiceThread.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostIOServiceThread.h" +#include <Swiften/Network/BoostIOServiceThread.h> #include <boost/smart_ptr/make_shared.hpp> diff --git a/Swiften/Network/BoostIOServiceThread.h b/Swiften/Network/BoostIOServiceThread.h index 1f72049..00fb397 100644 --- a/Swiften/Network/BoostIOServiceThread.h +++ b/Swiften/Network/BoostIOServiceThread.h @@ -6,8 +6,8 @@ #pragma once -#include <boost/asio.hpp> -#include <boost/thread.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/thread/thread.hpp> #include <boost/shared_ptr.hpp> namespace Swift { @@ -16,7 +16,7 @@ namespace Swift { BoostIOServiceThread(); ~BoostIOServiceThread(); - boost::shared_ptr<boost::asio::io_service> getIOService() { + boost::shared_ptr<boost::asio::io_service> getIOService() const { return ioService_; } diff --git a/Swiften/Network/BoostNetworkFactories.cpp b/Swiften/Network/BoostNetworkFactories.cpp index 1d9479a..315290c 100644 --- a/Swiften/Network/BoostNetworkFactories.cpp +++ b/Swiften/Network/BoostNetworkFactories.cpp @@ -4,11 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostNetworkFactories.h" -#include "Swiften/Network/BoostTimerFactory.h" -#include "Swiften/Network/BoostConnectionFactory.h" +#include <Swiften/Network/BoostNetworkFactories.h> +#include <Swiften/Network/BoostTimerFactory.h> +#include <Swiften/Network/BoostConnectionFactory.h> #include <Swiften/Network/PlatformDomainNameResolver.h> #include <Swiften/Network/BoostConnectionServerFactory.h> +#include <Swiften/Network/PlatformNATTraversalWorker.h> +#include <Swiften/Network/NullNATTraverser.h> namespace Swift { @@ -17,9 +19,15 @@ BoostNetworkFactories::BoostNetworkFactories(EventLoop* eventLoop) { connectionFactory = new BoostConnectionFactory(ioServiceThread.getIOService(), eventLoop); domainNameResolver = new PlatformDomainNameResolver(eventLoop); connectionServerFactory = new BoostConnectionServerFactory(ioServiceThread.getIOService(), eventLoop); +#ifdef SWIFT_EXPERIMENTAL_FT + natTraverser = new PlatformNATTraversalWorker(eventLoop); +#else + natTraverser = new NullNATTraverser(eventLoop); +#endif } BoostNetworkFactories::~BoostNetworkFactories() { + delete natTraverser; delete connectionServerFactory; delete domainNameResolver; delete connectionFactory; diff --git a/Swiften/Network/BoostNetworkFactories.h b/Swiften/Network/BoostNetworkFactories.h index e4d3128..bc7a963 100644 --- a/Swiften/Network/BoostNetworkFactories.h +++ b/Swiften/Network/BoostNetworkFactories.h @@ -6,11 +6,12 @@ #pragma once -#include "Swiften/Network/NetworkFactories.h" -#include "Swiften/Network/BoostIOServiceThread.h" +#include <Swiften/Network/NetworkFactories.h> +#include <Swiften/Network/BoostIOServiceThread.h> namespace Swift { class EventLoop; + class NATTraverser; class BoostNetworkFactories : public NetworkFactories { public: @@ -37,11 +38,16 @@ namespace Swift { return connectionServerFactory; } + NATTraverser* getNATTraverser() const { + return natTraverser; + } + private: BoostIOServiceThread ioServiceThread; TimerFactory* timerFactory; ConnectionFactory* connectionFactory; DomainNameResolver* domainNameResolver; ConnectionServerFactory* connectionServerFactory; + NATTraverser* natTraverser; }; } diff --git a/Swiften/Network/BoostTimer.cpp b/Swiften/Network/BoostTimer.cpp index 12d06c1..bf042d6 100644 --- a/Swiften/Network/BoostTimer.cpp +++ b/Swiften/Network/BoostTimer.cpp @@ -4,12 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostTimer.h" +#include <Swiften/Network/BoostTimer.h> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/asio.hpp> +#include <boost/bind.hpp> -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { diff --git a/Swiften/Network/BoostTimer.h b/Swiften/Network/BoostTimer.h index 1139dcf..bfe631b 100644 --- a/Swiften/Network/BoostTimer.h +++ b/Swiften/Network/BoostTimer.h @@ -6,12 +6,12 @@ #pragma once -#include <boost/asio.hpp> -#include <boost/thread.hpp> +#include <boost/asio/io_service.hpp> +#include <boost/asio/deadline_timer.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/EventLoop/EventOwner.h" -#include "Swiften/Network/Timer.h" +#include <Swiften/EventLoop/EventOwner.h> +#include <Swiften/Network/Timer.h> namespace Swift { class EventLoop; diff --git a/Swiften/Network/BoostTimerFactory.cpp b/Swiften/Network/BoostTimerFactory.cpp index b8e628f..c0bdb56 100644 --- a/Swiften/Network/BoostTimerFactory.cpp +++ b/Swiften/Network/BoostTimerFactory.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/BoostTimerFactory.h" -#include "Swiften/Network/BoostTimer.h" +#include <Swiften/Network/BoostTimerFactory.h> +#include <Swiften/Network/BoostTimer.h> namespace Swift { diff --git a/Swiften/Network/BoostTimerFactory.h b/Swiften/Network/BoostTimerFactory.h index c0e9ef7..6093db0 100644 --- a/Swiften/Network/BoostTimerFactory.h +++ b/Swiften/Network/BoostTimerFactory.h @@ -6,10 +6,10 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/BoostTimer.h" +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/BoostTimer.h> namespace Swift { class BoostTimer; diff --git a/Swiften/Network/CAresDomainNameResolver.cpp b/Swiften/Network/CAresDomainNameResolver.cpp index dd49139..da0f49e 100644 --- a/Swiften/Network/CAresDomainNameResolver.cpp +++ b/Swiften/Network/CAresDomainNameResolver.cpp @@ -7,8 +7,8 @@ // TODO: Check the second param of postEvent. We sometimes omit it. Same // goes for the PlatformDomainNameResolver. -#include "Swiften/Network/CAresDomainNameResolver.h" -#include "Swiften/Base/Platform.h" +#include <Swiften/Network/CAresDomainNameResolver.h> +#include <Swiften/Base/Platform.h> #ifndef SWIFTEN_PLATFORM_WINDOWS #include <netdb.h> @@ -16,11 +16,11 @@ #endif #include <algorithm> -#include "Swiften/Network/DomainNameServiceQuery.h" -#include "Swiften/Network/DomainNameAddressQuery.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Base/foreach.h> namespace Swift { diff --git a/Swiften/Network/CAresDomainNameResolver.h b/Swiften/Network/CAresDomainNameResolver.h index a630b61..d0ff82c 100644 --- a/Swiften/Network/CAresDomainNameResolver.h +++ b/Swiften/Network/CAresDomainNameResolver.h @@ -7,11 +7,11 @@ #pragma once #include <ares.h> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <list> -#include "Swiften/Network/DomainNameResolver.h" +#include <Swiften/Network/DomainNameResolver.h> namespace Swift { class CAresQuery; diff --git a/Swiften/Network/ChainedConnector.cpp b/Swiften/Network/ChainedConnector.cpp new file mode 100644 index 0000000..1a38e53 --- /dev/null +++ b/Swiften/Network/ChainedConnector.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/ChainedConnector.h> + +#include <boost/bind.hpp> +#include <typeinfo> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/Connector.h> +#include <Swiften/Network/ConnectionFactory.h> + +using namespace Swift; + +ChainedConnector::ChainedConnector( + const std::string& hostname, + DomainNameResolver* resolver, + const std::vector<ConnectionFactory*>& connectionFactories, + TimerFactory* timerFactory) : + hostname(hostname), + resolver(resolver), + connectionFactories(connectionFactories), + timerFactory(timerFactory), + timeoutMilliseconds(0) { +} + +void ChainedConnector::setTimeoutMilliseconds(int milliseconds) { + timeoutMilliseconds = milliseconds; +} + +void ChainedConnector::start() { + SWIFT_LOG(debug) << "Starting queued connector for " << hostname << std::endl; + + connectionFactoryQueue = std::deque<ConnectionFactory*>(connectionFactories.begin(), connectionFactories.end()); + tryNextConnectionFactory(); +} + +void ChainedConnector::stop() { + if (currentConnector) { + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->stop(); + currentConnector.reset(); + } + finish(boost::shared_ptr<Connection>()); +} + +void ChainedConnector::tryNextConnectionFactory() { + assert(!currentConnector); + if (connectionFactoryQueue.empty()) { + SWIFT_LOG(debug) << "No more connection factories" << std::endl; + finish(boost::shared_ptr<Connection>()); + } + else { + ConnectionFactory* connectionFactory = connectionFactoryQueue.front(); + SWIFT_LOG(debug) << "Trying next connection factory: " << typeid(*connectionFactory).name() << std::endl; + connectionFactoryQueue.pop_front(); + currentConnector = Connector::create(hostname, resolver, connectionFactory, timerFactory); + currentConnector->setTimeoutMilliseconds(timeoutMilliseconds); + currentConnector->onConnectFinished.connect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector->start(); + } +} + +void ChainedConnector::handleConnectorFinished(boost::shared_ptr<Connection> connection) { + SWIFT_LOG(debug) << "Connector finished" << std::endl; + currentConnector->onConnectFinished.disconnect(boost::bind(&ChainedConnector::handleConnectorFinished, this, _1)); + currentConnector.reset(); + if (connection) { + finish(connection); + } + else { + tryNextConnectionFactory(); + } +} + +void ChainedConnector::finish(boost::shared_ptr<Connection> connection) { + onConnectFinished(connection); +} diff --git a/Swiften/Network/ChainedConnector.h b/Swiften/Network/ChainedConnector.h new file mode 100644 index 0000000..15b17f3 --- /dev/null +++ b/Swiften/Network/ChainedConnector.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <vector> +#include <deque> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> + +namespace Swift { + class Connection; + class Connector; + class ConnectionFactory; + class TimerFactory; + class DomainNameResolver; + + class ChainedConnector { + public: + ChainedConnector(const std::string& hostname, DomainNameResolver*, const std::vector<ConnectionFactory*>&, TimerFactory*); + + void setTimeoutMilliseconds(int milliseconds); + void start(); + void stop(); + + boost::signal<void (boost::shared_ptr<Connection>)> onConnectFinished; + + private: + void finish(boost::shared_ptr<Connection> connection); + void tryNextConnectionFactory(); + void handleConnectorFinished(boost::shared_ptr<Connection>); + + private: + std::string hostname; + DomainNameResolver* resolver; + std::vector<ConnectionFactory*> connectionFactories; + TimerFactory* timerFactory; + int timeoutMilliseconds; + std::deque<ConnectionFactory*> connectionFactoryQueue; + boost::shared_ptr<Connector> currentConnector; + }; +}; diff --git a/Swiften/Network/Connection.cpp b/Swiften/Network/Connection.cpp new file mode 100644 index 0000000..9bb29e1 --- /dev/null +++ b/Swiften/Network/Connection.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/Connection.h> + +using namespace Swift; + +Connection::Connection() { +} + +Connection::~Connection() { +} diff --git a/Swiften/Network/Connection.h b/Swiften/Network/Connection.h index 529dd82..6ad2999 100644 --- a/Swiften/Network/Connection.h +++ b/Swiften/Network/Connection.h @@ -7,13 +7,13 @@ #pragma once #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Base/ByteArray.h" -#include <string> -#include "Swiften/Network/HostAddressPort.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { + class HostAddressPort; + class Connection { public: typedef boost::shared_ptr<Connection> ref; @@ -23,20 +23,20 @@ namespace Swift { WriteError }; - Connection() {} - virtual ~Connection() {} + Connection(); + virtual ~Connection(); virtual void listen() = 0; virtual void connect(const HostAddressPort& address) = 0; virtual void disconnect() = 0; - virtual void write(const ByteArray& data) = 0; + virtual void write(const SafeByteArray& data) = 0; virtual HostAddressPort getLocalAddress() const = 0; public: boost::signal<void (bool /* error */)> onConnectFinished; boost::signal<void (const boost::optional<Error>&)> onDisconnected; - boost::signal<void (const ByteArray&)> onDataRead; + boost::signal<void (boost::shared_ptr<SafeByteArray>)> onDataRead; boost::signal<void ()> onDataWritten; }; } diff --git a/Swiften/Network/ConnectionFactory.cpp b/Swiften/Network/ConnectionFactory.cpp index dc322a4..2e38b21 100644 --- a/Swiften/Network/ConnectionFactory.cpp +++ b/Swiften/Network/ConnectionFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/ConnectionFactory.h" +#include <Swiften/Network/ConnectionFactory.h> namespace Swift { diff --git a/Swiften/Network/ConnectionServer.cpp b/Swiften/Network/ConnectionServer.cpp index 9631efc..78312e7 100644 --- a/Swiften/Network/ConnectionServer.cpp +++ b/Swiften/Network/ConnectionServer.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/ConnectionServer.h" +#include <Swiften/Network/ConnectionServer.h> namespace Swift { diff --git a/Swiften/Network/ConnectionServer.h b/Swiften/Network/ConnectionServer.h index b90f73d..00703a4 100644 --- a/Swiften/Network/ConnectionServer.h +++ b/Swiften/Network/ConnectionServer.h @@ -7,10 +7,10 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/HostAddressPort.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> namespace Swift { class ConnectionServer { diff --git a/Swiften/Network/Connector.cpp b/Swiften/Network/Connector.cpp index 868bd50..8f35aba 100644 --- a/Swiften/Network/Connector.cpp +++ b/Swiften/Network/Connector.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/Connector.h" +#include <Swiften/Network/Connector.h> #include <boost/bind.hpp> #include <iostream> -#include "Swiften/Network/ConnectionFactory.h" -#include "Swiften/Network/DomainNameResolver.h" -#include "Swiften/Network/DomainNameAddressQuery.h" -#include "Swiften/Network/TimerFactory.h" +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/TimerFactory.h> #include <Swiften/Base/Log.h> namespace Swift { diff --git a/Swiften/Network/Connector.h b/Swiften/Network/Connector.h index b3e7d83..8336299 100644 --- a/Swiften/Network/Connector.h +++ b/Swiften/Network/Connector.h @@ -7,15 +7,15 @@ #pragma once #include <deque> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Network/DomainNameServiceQuery.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/Timer.h" -#include "Swiften/Network/HostAddressPort.h" +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/Timer.h> +#include <Swiften/Network/HostAddressPort.h> #include <string> -#include "Swiften/Network/DomainNameResolveError.h" +#include <Swiften/Network/DomainNameResolveError.h> namespace Swift { class DomainNameAddressQuery; @@ -28,7 +28,7 @@ namespace Swift { typedef boost::shared_ptr<Connector> ref; static Connector::ref create(const std::string& hostname, DomainNameResolver* resolver, ConnectionFactory* connectionFactory, TimerFactory* timerFactory) { - return Connector::ref(new Connector(hostname, resolver, connectionFactory, timerFactory)); + return ref(new Connector(hostname, resolver, connectionFactory, timerFactory)); } void setTimeoutMilliseconds(int milliseconds); diff --git a/Swiften/Network/DomainNameAddressQuery.cpp b/Swiften/Network/DomainNameAddressQuery.cpp index fd36964..856f301 100644 --- a/Swiften/Network/DomainNameAddressQuery.cpp +++ b/Swiften/Network/DomainNameAddressQuery.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/DomainNameAddressQuery.h" +#include <Swiften/Network/DomainNameAddressQuery.h> namespace Swift { diff --git a/Swiften/Network/DomainNameAddressQuery.h b/Swiften/Network/DomainNameAddressQuery.h index 5bac350..c8ed981 100644 --- a/Swiften/Network/DomainNameAddressQuery.h +++ b/Swiften/Network/DomainNameAddressQuery.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> #include <boost/shared_ptr.hpp> -#include "Swiften/Network/DomainNameResolveError.h" -#include "Swiften/Network/HostAddress.h" +#include <Swiften/Network/DomainNameResolveError.h> +#include <Swiften/Network/HostAddress.h> namespace Swift { class DomainNameAddressQuery { diff --git a/Swiften/Network/DomainNameResolveError.h b/Swiften/Network/DomainNameResolveError.h index 632ba77..aa4441d 100644 --- a/Swiften/Network/DomainNameResolveError.h +++ b/Swiften/Network/DomainNameResolveError.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Base/Error.h" +#include <Swiften/Base/Error.h> namespace Swift { class DomainNameResolveError : public Error { diff --git a/Swiften/Network/DomainNameResolver.cpp b/Swiften/Network/DomainNameResolver.cpp index 96c5165..56a9d72 100644 --- a/Swiften/Network/DomainNameResolver.cpp +++ b/Swiften/Network/DomainNameResolver.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/DomainNameResolver.h" +#include <Swiften/Network/DomainNameResolver.h> namespace Swift { diff --git a/Swiften/Network/DomainNameServiceQuery.cpp b/Swiften/Network/DomainNameServiceQuery.cpp index 423330c..5713b63 100644 --- a/Swiften/Network/DomainNameServiceQuery.cpp +++ b/Swiften/Network/DomainNameServiceQuery.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/DomainNameServiceQuery.h" +#include <Swiften/Network/DomainNameServiceQuery.h> namespace Swift { diff --git a/Swiften/Network/DomainNameServiceQuery.h b/Swiften/Network/DomainNameServiceQuery.h index 63d5841..0bd1569 100644 --- a/Swiften/Network/DomainNameServiceQuery.h +++ b/Swiften/Network/DomainNameServiceQuery.h @@ -6,13 +6,13 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> #include <vector> #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Network/DomainNameResolveError.h" +#include <Swiften/Network/DomainNameResolveError.h> namespace Swift { class DomainNameServiceQuery { diff --git a/Swiften/Network/DummyConnection.cpp b/Swiften/Network/DummyConnection.cpp new file mode 100644 index 0000000..09bd06d --- /dev/null +++ b/Swiften/Network/DummyConnection.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/DummyConnection.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <cassert> + +namespace Swift { + +DummyConnection::DummyConnection(EventLoop* eventLoop) : eventLoop(eventLoop) { +} + +void DummyConnection::receive(const SafeByteArray& data) { + eventLoop->postEvent(boost::bind(boost::ref(onDataRead), boost::make_shared<SafeByteArray>(data)), shared_from_this()); +} + +void DummyConnection::listen() { + assert(false); +} + +void DummyConnection::connect(const HostAddressPort&) { + assert(false); +} + + +} diff --git a/Swiften/Network/DummyConnection.h b/Swiften/Network/DummyConnection.h index 6b426b1..5191e30 100644 --- a/Swiften/Network/DummyConnection.h +++ b/Swiften/Network/DummyConnection.h @@ -6,45 +6,37 @@ #pragma once -#include <cassert> -#include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/Network/Connection.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/EventLoop/EventOwner.h> namespace Swift { class DummyConnection : public Connection, public EventOwner, public boost::enable_shared_from_this<DummyConnection> { public: - DummyConnection(EventLoop* eventLoop) : eventLoop(eventLoop) {} + DummyConnection(EventLoop* eventLoop); - void listen() { - assert(false); - } - - void connect(const HostAddressPort&) { - assert(false); - } + void listen(); + void connect(const HostAddressPort&); void disconnect() { //assert(false); } - void write(const ByteArray& data) { + void write(const SafeByteArray& data) { eventLoop->postEvent(boost::ref(onDataWritten), shared_from_this()); onDataSent(data); } - void receive(const ByteArray& data) { - eventLoop->postEvent(boost::bind(boost::ref(onDataRead), ByteArray(data)), shared_from_this()); - } + void receive(const SafeByteArray& data); HostAddressPort getLocalAddress() const { return localAddress; } - boost::signal<void (const ByteArray&)> onDataSent; + boost::signal<void (const SafeByteArray&)> onDataSent; EventLoop* eventLoop; HostAddressPort localAddress; diff --git a/Swiften/Network/DummyConnectionFactory.h b/Swiften/Network/DummyConnectionFactory.h new file mode 100644 index 0000000..e8a294e --- /dev/null +++ b/Swiften/Network/DummyConnectionFactory.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/DummyConnection.h> + +namespace Swift { + +class EventLoop; + +class DummyConnectionFactory : public ConnectionFactory { +public: + DummyConnectionFactory(EventLoop *eventLoop) : eventLoop(eventLoop) {} + virtual ~DummyConnectionFactory() {} + virtual boost::shared_ptr<Connection> createConnection() { + return boost::make_shared<DummyConnection>(eventLoop); + } +private: + EventLoop* eventLoop; +}; + +} diff --git a/Swiften/Network/DummyTimerFactory.cpp b/Swiften/Network/DummyTimerFactory.cpp index 105b103..16428b7 100644 --- a/Swiften/Network/DummyTimerFactory.cpp +++ b/Swiften/Network/DummyTimerFactory.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/DummyTimerFactory.h" +#include <Swiften/Network/DummyTimerFactory.h> #include <algorithm> -#include "Swiften/Base/foreach.h" -#include "Swiften/Network/Timer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/Timer.h> namespace Swift { diff --git a/Swiften/Network/DummyTimerFactory.h b/Swiften/Network/DummyTimerFactory.h index 408b647..0c49f3d 100644 --- a/Swiften/Network/DummyTimerFactory.h +++ b/Swiften/Network/DummyTimerFactory.h @@ -8,7 +8,7 @@ #include <list> -#include "Swiften/Network/TimerFactory.h" +#include <Swiften/Network/TimerFactory.h> namespace Swift { class DummyTimerFactory : public TimerFactory { diff --git a/Swiften/Network/EnvironmentProxyProvider.cpp b/Swiften/Network/EnvironmentProxyProvider.cpp new file mode 100644 index 0000000..7701da1 --- /dev/null +++ b/Swiften/Network/EnvironmentProxyProvider.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include <Swiften/Base/Log.h> +#include <Swiften/Network/EnvironmentProxyProvider.h> + +namespace Swift { + +EnvironmentProxyProvider::EnvironmentProxyProvider() { + socksProxy = getFromEnv("all_proxy", "socks"); + httpProxy = getFromEnv("http_proxy", "http"); + SWIFT_LOG(debug) << "Environment: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; +} + +HostAddressPort EnvironmentProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort EnvironmentProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort EnvironmentProxyProvider::getFromEnv(const char* envVarName, std::string proxyProtocol) { + char* envVar = NULL; + std::string address; + int port = 0; + + envVar = getenv(envVarName); + + proxyProtocol += "://"; + address = envVar != NULL ? envVar : "0.0.0.0"; + if(envVar != NULL && address.compare(0, proxyProtocol.length(), proxyProtocol) == 0) { + address = address.substr(proxyProtocol.length(), address.length()); + port = atoi(address.substr(address.find(':') + 1, address.length()).c_str()); + address = address.substr(0, address.find(':')); + } + + return HostAddressPort(HostAddress(address), port); +} + +} diff --git a/Swiften/Network/EnvironmentProxyProvider.h b/Swiften/Network/EnvironmentProxyProvider.h new file mode 100644 index 0000000..224d301 --- /dev/null +++ b/Swiften/Network/EnvironmentProxyProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ProxyProvider.h> + +namespace Swift { + class EnvironmentProxyProvider : public ProxyProvider { + public: + EnvironmentProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getFromEnv(const char* envVarName, std::string proxyProtocol); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} + + diff --git a/Swiften/Network/FakeConnection.cpp b/Swiften/Network/FakeConnection.cpp new file mode 100644 index 0000000..be5555c --- /dev/null +++ b/Swiften/Network/FakeConnection.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/FakeConnection.h> + +#include <boost/bind.hpp> + +namespace Swift { + +FakeConnection::FakeConnection(EventLoop* eventLoop) : eventLoop(eventLoop), state(Initial), delayConnect(false) { +} + +FakeConnection::~FakeConnection() { +} + +void FakeConnection::listen() { + assert(false); +} + +void FakeConnection::setError(const Error& e) { + error = boost::optional<Error>(e); + state = DisconnectedWithError; + if (connectedTo) { + eventLoop->postEvent( + boost::bind(boost::ref(onDisconnected), error), + shared_from_this()); + } +} + +void FakeConnection::connect(const HostAddressPort& address) { + if (delayConnect) { + state = Connecting; + } + else { + if (!error) { + connectedTo = address; + state = Connected; + } + else { + state = DisconnectedWithError; + } + eventLoop->postEvent( + boost::bind(boost::ref(onConnectFinished), error), + shared_from_this()); + } +} + +void FakeConnection::disconnect() { + if (!error) { + state = Disconnected; + } + else { + state = DisconnectedWithError; + } + connectedTo.reset(); + eventLoop->postEvent( + boost::bind(boost::ref(onDisconnected), error), + shared_from_this()); +} + +} diff --git a/Swiften/Network/FakeConnection.h b/Swiften/Network/FakeConnection.h index 4e2e960..99cb584 100644 --- a/Swiften/Network/FakeConnection.h +++ b/Swiften/Network/FakeConnection.h @@ -7,14 +7,13 @@ #pragma once #include <boost/optional.hpp> -#include <boost/bind.hpp> #include <boost/enable_shared_from_this.hpp> #include <vector> -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/EventLoop/EventOwner.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/EventLoop/EventOwner.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { class FakeConnection : @@ -30,58 +29,19 @@ namespace Swift { DisconnectedWithError }; - FakeConnection(EventLoop* eventLoop) : eventLoop(eventLoop), state(Initial), delayConnect(false) {} - - virtual void listen() { - assert(false); - } + FakeConnection(EventLoop* eventLoop); + ~FakeConnection(); + virtual void listen(); virtual HostAddressPort getLocalAddress() const { return HostAddressPort(); } - void setError(const Error& e) { - error = boost::optional<Error>(e); - state = DisconnectedWithError; - if (connectedTo) { - eventLoop->postEvent( - boost::bind(boost::ref(onDisconnected), error), - shared_from_this()); - } - } - - virtual void connect(const HostAddressPort& address) { - if (delayConnect) { - state = Connecting; - } - else { - if (!error) { - connectedTo = address; - state = Connected; - } - else { - state = DisconnectedWithError; - } - eventLoop->postEvent( - boost::bind(boost::ref(onConnectFinished), error), - shared_from_this()); - } - } - - virtual void disconnect() { - if (!error) { - state = Disconnected; - } - else { - state = DisconnectedWithError; - } - connectedTo.reset(); - eventLoop->postEvent( - boost::bind(boost::ref(onDisconnected), error), - shared_from_this()); - } + void setError(const Error& e); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); - virtual void write(const ByteArray& data) { + virtual void write(const SafeByteArray& data) { dataWritten.push_back(data); } @@ -91,7 +51,7 @@ namespace Swift { EventLoop* eventLoop; boost::optional<HostAddressPort> connectedTo; - std::vector<ByteArray> dataWritten; + std::vector<SafeByteArray> dataWritten; boost::optional<Error> error; State state; bool delayConnect; diff --git a/Swiften/Network/GConfProxyProvider.cpp b/Swiften/Network/GConfProxyProvider.cpp new file mode 100644 index 0000000..8d97c68 --- /dev/null +++ b/Swiften/Network/GConfProxyProvider.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include <gconf/gconf-client.h> + +#include <Swiften/Base/Log.h> +#include <Swiften/Network/GConfProxyProvider.h> + +namespace Swift { + +GConfProxyProvider::GConfProxyProvider() { + // Ensure static GLib initialization methods are called + static bool glibInitialized = false; + if (!glibInitialized) { + g_type_init(); + glibInitialized = true; + } + + socksProxy = getFromGConf("/system/proxy/socks_host", "/system/proxy/socks_port"); + httpProxy = getFromGConf("/system/http_proxy/host", "/system/http_proxy/port"); + SWIFT_LOG(debug) << "GConf: SOCKS5 => " << socksProxy.toString() << "; HTTP Connect => " << httpProxy.toString() << std::endl; +} + +HostAddressPort GConfProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort GConfProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort GConfProxyProvider::getFromGConf(const char* gcHost, const char* gcPort) { + std::string address; + int port = 0; + gchar* str; + + GConfClient* client = gconf_client_get_default(); + + str = gconf_client_get_string(client, gcHost, NULL); + port = static_cast<int> (gconf_client_get_int(client, gcPort, NULL)); + + if(str) { + address = static_cast<char*> (str); + g_free(str); + } + + g_object_unref(client); + return HostAddressPort(HostAddress(address), port); +} + +} diff --git a/Swiften/Network/GConfProxyProvider.h b/Swiften/Network/GConfProxyProvider.h new file mode 100644 index 0000000..31f38a9 --- /dev/null +++ b/Swiften/Network/GConfProxyProvider.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ProxyProvider.h> + +namespace Swift { + class GConfProxyProvider : public ProxyProvider { + public: + GConfProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getFromGConf(const char* gcHost, const char* gcPort); + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} + + diff --git a/Swiften/Network/HTTPConnectProxiedConnection.cpp b/Swiften/Network/HTTPConnectProxiedConnection.cpp new file mode 100644 index 0000000..e05a933 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnection.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/HTTPConnectProxiedConnection.h> + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/thread.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Base/String.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/ConnectionFactory.h> + +using namespace Swift; + +HTTPConnectProxiedConnection::HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy) : connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { + connected_ = false; +} + +HTTPConnectProxiedConnection::~HTTPConnectProxiedConnection() { + if (connection_) { + connection_->onDataRead.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); + } + + if (connected_) { + std::cerr << "Warning: Connection was still established." << std::endl; + } +} + +void HTTPConnectProxiedConnection::connect(const HostAddressPort& server) { + server_ = server; + connection_ = connectionFactory_->createConnection(); + connection_->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + connection_->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnection::handleDisconnected, shared_from_this(), _1)); + connection_->connect(proxy_); +} + +void HTTPConnectProxiedConnection::listen() { + assert(false); + connection_->listen(); +} + +void HTTPConnectProxiedConnection::disconnect() { + connected_ = false; + connection_->disconnect(); +} + +void HTTPConnectProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); +} + +void HTTPConnectProxiedConnection::write(const SafeByteArray& data) { + connection_->write(data); +} + +void HTTPConnectProxiedConnection::handleConnectionConnectFinished(bool error) { + connection_->onConnectFinished.disconnect(boost::bind(&HTTPConnectProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + if (!error) { + std::stringstream connect; + connect << "CONNECT " << server_.getAddress().toString() << ":" << server_.getPort() << " HTTP/1.1\r\n\r\n"; + connection_->write(createSafeByteArray(connect.str())); + } + else { + onConnectFinished(true); + } +} + +void HTTPConnectProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + if (!connected_) { + SWIFT_LOG(debug) << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl; + std::vector<std::string> tmp = String::split(byteArrayToString(ByteArray(data->begin(), data->end())), ' '); + if(tmp.size() > 1) { + int status = boost::lexical_cast<int> (tmp[1].c_str()); + SWIFT_LOG(debug) << "Proxy Status: " << status << std::endl; + if (status / 100 == 2) { // all 2XX states are OK + connected_ = true; + onConnectFinished(false); + return; + } + SWIFT_LOG(debug) << "HTTP Proxy returned an error: " << byteArrayToString(ByteArray(data->begin(), data->end())) << std::endl; + } + disconnect(); + onConnectFinished(true); + } + else { + onDataRead(data); + } +} + +HostAddressPort HTTPConnectProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} diff --git a/Swiften/Network/HTTPConnectProxiedConnection.h b/Swiften/Network/HTTPConnectProxiedConnection.h new file mode 100644 index 0000000..d3f5b7a --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnection.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> + +namespace boost { + class thread; + namespace system { + class error_code; + } +} + +namespace Swift { + class ConnectionFactory; + + class HTTPConnectProxiedConnection : public Connection, public boost::enable_shared_from_this<HTTPConnectProxiedConnection> { + public: + typedef boost::shared_ptr<HTTPConnectProxiedConnection> ref; + + ~HTTPConnectProxiedConnection(); + + static ref create(ConnectionFactory* connectionFactory, HostAddressPort proxy) { + return ref(new HTTPConnectProxiedConnection(connectionFactory, proxy)); + } + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const SafeByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + private: + HTTPConnectProxiedConnection(ConnectionFactory* connectionFactory, HostAddressPort proxy); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(boost::shared_ptr<SafeByteArray> data); + void handleDisconnected(const boost::optional<Error>& error); + + private: + bool connected_; + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + HostAddressPort server_; + boost::shared_ptr<Connection> connection_; + }; +} diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp new file mode 100644 index 0000000..ab7f18e --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/HTTPConnectProxiedConnectionFactory.h> + +#include <Swiften/Network/HTTPConnectProxiedConnection.h> + +namespace Swift { + +HTTPConnectProxiedConnectionFactory::HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy) { +} + +boost::shared_ptr<Connection> HTTPConnectProxiedConnectionFactory::createConnection() { + return HTTPConnectProxiedConnection::create(connectionFactory_, proxy_); +} + +} diff --git a/Swiften/Network/HTTPConnectProxiedConnectionFactory.h b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h new file mode 100644 index 0000000..b475586 --- /dev/null +++ b/Swiften/Network/HTTPConnectProxiedConnectionFactory.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> + +namespace Swift { + class HTTPConnectProxiedConnectionFactory : public ConnectionFactory { + public: + HTTPConnectProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + }; +} diff --git a/Swiften/Network/HostAddress.cpp b/Swiften/Network/HostAddress.cpp index 2ca1414..7ba2a7f 100644 --- a/Swiften/Network/HostAddress.cpp +++ b/Swiften/Network/HostAddress.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/HostAddress.h" +#include <Swiften/Network/HostAddress.h> #include <boost/numeric/conversion/cast.hpp> #include <boost/lexical_cast.hpp> @@ -12,7 +12,7 @@ #include <stdexcept> #include <boost/array.hpp> -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/foreach.h> #include <string> namespace Swift { @@ -24,7 +24,7 @@ HostAddress::HostAddress(const std::string& address) { try { address_ = boost::asio::ip::address::from_string(address); } - catch (const std::exception& t) { + catch (const std::exception&) { } } diff --git a/Swiften/Network/HostAddress.h b/Swiften/Network/HostAddress.h index 4b05c32..0b3bdda 100644 --- a/Swiften/Network/HostAddress.h +++ b/Swiften/Network/HostAddress.h @@ -3,16 +3,12 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ - #pragma once #include <string> -#include <vector> -#include <boost/asio.hpp> +#include <boost/asio/ip/address.hpp> namespace Swift { - - class HostAddress { public: HostAddress(); diff --git a/Swiften/Network/HostAddressPort.cpp b/Swiften/Network/HostAddressPort.cpp new file mode 100644 index 0000000..e2e6012 --- /dev/null +++ b/Swiften/Network/HostAddressPort.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/HostAddressPort.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +HostAddressPort::HostAddressPort(const HostAddress& address, int port) : address_(address), port_(port) { +} + +HostAddressPort::HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint) { + address_ = HostAddress(endpoint.address()); + port_ = endpoint.port(); +} + +std::string HostAddressPort::toString() const { + return getAddress().toString() + ":" + boost::lexical_cast<std::string>(getPort()); +} diff --git a/Swiften/Network/HostAddressPort.h b/Swiften/Network/HostAddressPort.h index 6883380..e3c0413 100644 --- a/Swiften/Network/HostAddressPort.h +++ b/Swiften/Network/HostAddressPort.h @@ -6,21 +6,15 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/ip/tcp.hpp> -#include "Swiften/Network/HostAddress.h" +#include <Swiften/Network/HostAddress.h> namespace Swift { class HostAddressPort { public: - HostAddressPort(const HostAddress& address = HostAddress(), int port = -1) : address_(address), port_(port) { - } - - HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint) { - address_ = HostAddress(endpoint.address()); - port_ = endpoint.port(); - } - + HostAddressPort(const HostAddress& address = HostAddress(), int port = -1); + HostAddressPort(const boost::asio::ip::tcp::endpoint& endpoint); const HostAddress& getAddress() const { return address_; @@ -37,6 +31,8 @@ namespace Swift { bool isValid() const { return address_.isValid() && port_ > 0; } + + std::string toString() const; private: HostAddress address_; diff --git a/Swiften/Network/MacOSXProxyProvider.cpp b/Swiften/Network/MacOSXProxyProvider.cpp new file mode 100644 index 0000000..eaadd28 --- /dev/null +++ b/Swiften/Network/MacOSXProxyProvider.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Base/Platform.h> +#include <Swiften/Network/MacOSXProxyProvider.h> + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> +#include <utility> + +#ifndef SWIFTEN_PLATFORM_IPHONE +#include <SystemConfiguration/SystemConfiguration.h> +#endif + +using namespace Swift; + +#ifndef SWIFTEN_PLATFORM_IPHONE +static HostAddressPort getFromDictionary(CFDictionaryRef dict, CFStringRef enabledKey, CFStringRef hostKey, CFStringRef portKey) { + CFNumberRef numberValue = NULL; + HostAddressPort ret = HostAddressPort(HostAddress(), 0); + + if(CFDictionaryGetValueIfPresent(dict, reinterpret_cast<const void*> (enabledKey), reinterpret_cast<const void**> (&numberValue)) == true) { + const int i = 0; + CFNumberRef zero = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &i); + CFComparisonResult result = CFNumberCompare(numberValue, zero, NULL); + CFRelease(numberValue); + + if(result != kCFCompareEqualTo) { + int port = 0; + std::string host = ""; + + try { + CFNumberRef numberValue = reinterpret_cast<CFNumberRef> (CFDictionaryGetValue(dict, portKey)); + if(numberValue != NULL) { + CFNumberGetValue(numberValue, kCFNumberIntType, &port); + CFRelease(numberValue); + } + + CFStringRef stringValue = reinterpret_cast<CFStringRef> (CFDictionaryGetValue(dict, hostKey)); + if(stringValue != NULL) { + std::vector<char> buffer; + // length must be +1 for the ending zero; and the Docu of CFStringGetCString tells it like + // if the string is toby the length must be at least 5. + CFIndex length = CFStringGetLength(stringValue) + 1; + buffer.resize(length); + if(CFStringGetCString(stringValue, &buffer[0], length, kCFStringEncodingMacRoman)) { + for(std::vector<char>::iterator iter = buffer.begin(); iter != buffer.end(); ++iter) { + host += *iter; + } + } + CFRelease(stringValue); + } + } + catch(...) { + std::cerr << "Exception caught ... " << std::endl; + } + + if(host != "" && port != 0) { + ret = HostAddressPort(HostAddress(host), port); + } + } + } + return ret; +} +#endif +namespace Swift { + +MacOSXProxyProvider::MacOSXProxyProvider() { +} + +HostAddressPort MacOSXProxyProvider::getHTTPConnectProxy() const { + HostAddressPort result; +#ifndef SWIFTEN_PLATFORM_IPHONE + CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); + if(proxies != NULL) { + result = getFromDictionary(proxies, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort); + } +#endif + return result; +} + +HostAddressPort MacOSXProxyProvider::getSOCKS5Proxy() const { + HostAddressPort result; +#ifndef SWIFTEN_PLATFORM_IPHONE + CFDictionaryRef proxies = SCDynamicStoreCopyProxies(NULL); + if(proxies != NULL) { + result = getFromDictionary(proxies, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort); + } +#endif + return result; +} + +} diff --git a/Swiften/Network/MacOSXProxyProvider.h b/Swiften/Network/MacOSXProxyProvider.h new file mode 100644 index 0000000..6666d30 --- /dev/null +++ b/Swiften/Network/MacOSXProxyProvider.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include <Swiften/Network/ProxyProvider.h> +#include <CoreFoundation/CoreFoundation.h> + +namespace Swift { + class MacOSXProxyProvider : public ProxyProvider { + public: + MacOSXProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + }; +} diff --git a/Swiften/Network/MiniUPnPInterface.cpp b/Swiften/Network/MiniUPnPInterface.cpp new file mode 100644 index 0000000..f6e3b5d --- /dev/null +++ b/Swiften/Network/MiniUPnPInterface.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/MiniUPnPInterface.h> + +#include <upnpcommands.h> +#include <upnperrors.h> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/Log.h> + +namespace Swift { + +MiniUPnPInterface::MiniUPnPInterface() : isValid(false) { + int error = 0; + deviceList = upnpDiscover(1500 /* timeout in ms */, 0, 0, 0, 0 /* do IPv6? */, &error); + if (!deviceList) { + return; + } + + char lanAddress[64]; + if (!UPNP_GetValidIGD(deviceList, &urls, &data, lanAddress, sizeof(lanAddress))) { + return; + } + localAddress = std::string(lanAddress); + isValid = true; +} + +MiniUPnPInterface::~MiniUPnPInterface() { + if (isValid) { + FreeUPNPUrls(&urls); + } + freeUPNPDevlist(deviceList); +} + +boost::optional<HostAddress> MiniUPnPInterface::getPublicIP() { + if (!isValid) { + return boost::optional<HostAddress>(); + } + char externalIPAddress[40]; + int ret = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); + if (ret != UPNPCOMMAND_SUCCESS) { + return boost::optional<HostAddress>(); + } + else { + return HostAddress(std::string(externalIPAddress)); + } +} + +boost::optional<NATPortMapping> MiniUPnPInterface::addPortForward(int actualLocalPort, int actualPublicPort) { + if (!isValid) { + return boost::optional<NATPortMapping>(); + } + + NATPortMapping mapping(actualLocalPort, actualPublicPort, NATPortMapping::TCP); + + std::string publicPort = boost::lexical_cast<std::string>(mapping.publicPort); + std::string localPort = boost::lexical_cast<std::string>(mapping.localPort); + std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.leaseInSeconds); + + int ret = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), localPort.c_str(), localAddress.c_str(), 0, mapping.protocol == NATPortMapping::TCP ? "TCP" : "UDP", 0, leaseSeconds.c_str()); + if (ret == UPNPCOMMAND_SUCCESS) { + return mapping; + } + else { + return boost::optional<NATPortMapping>(); + } +} + +bool MiniUPnPInterface::removePortForward(const NATPortMapping& mapping) { + if (!isValid) { + return false; + } + + std::string publicPort = boost::lexical_cast<std::string>(mapping.publicPort); + std::string localPort = boost::lexical_cast<std::string>(mapping.localPort); + std::string leaseSeconds = boost::lexical_cast<std::string>(mapping.leaseInSeconds); + + int ret = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, publicPort.c_str(), mapping.protocol == NATPortMapping::TCP ? "TCP" : "UDP", 0); + return ret == UPNPCOMMAND_SUCCESS; +} + +} diff --git a/Swiften/Network/MiniUPnPInterface.h b/Swiften/Network/MiniUPnPInterface.h new file mode 100644 index 0000000..ae9be66 --- /dev/null +++ b/Swiften/Network/MiniUPnPInterface.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <miniupnpc.h> + +#include <Swiften/Network/NATPortMapping.h> +#include <Swiften/Network/NATTraversalInterface.h> + +namespace Swift { + class MiniUPnPInterface : public NATTraversalInterface { + public: + MiniUPnPInterface(); + ~MiniUPnPInterface(); + + virtual bool isAvailable() { + return isValid; + } + + boost::optional<HostAddress> getPublicIP(); + boost::optional<NATPortMapping> addPortForward(int localPort, int publicPort); + bool removePortForward(const NATPortMapping&); + + private: + bool isValid; + std::string localAddress; + UPNPDev* deviceList; + UPNPUrls urls; + IGDdatas data; + }; +} diff --git a/Swiften/Network/NATPMPInterface.cpp b/Swiften/Network/NATPMPInterface.cpp new file mode 100644 index 0000000..298240a --- /dev/null +++ b/Swiften/Network/NATPMPInterface.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NATPMPInterface.h> + +#include <Swiften/Base/Log.h> + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +namespace Swift { + +NATPMPInterface::NATPMPInterface() { + initnatpmp(&natpmp, 0, 0); +} + +NATPMPInterface::~NATPMPInterface() { + closenatpmp(&natpmp); +} + +bool NATPMPInterface::isAvailable() { + return getPublicIP(); +} + +boost::optional<HostAddress> NATPMPInterface::getPublicIP() { + if (sendpublicaddressrequest(&natpmp) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP public address request!" << std::endl; + return boost::optional<HostAddress>(); + } + + int r = 0; + natpmpresp_t response; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + } while (r == NATPMP_TRYAGAIN); + + if (r == 0) { + return boost::optional<HostAddress>(HostAddress(reinterpret_cast<const unsigned char*>(&(response.pnu.publicaddress.addr)), 4)); + } + else { + SWIFT_LOG(debug) << "Inavlid NAT-PMP response." << std::endl; + return boost::optional<HostAddress>(); + } +} + +boost::optional<NATPortMapping> NATPMPInterface::addPortForward(int localPort, int publicPort) { + NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); + if (sendnewportmappingrequest(&natpmp, mapping.protocol == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, mapping.leaseInSeconds, mapping.publicPort, mapping.localPort) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP port forwarding request!" << std::endl; + return boost::optional<NATPortMapping>(); + } + + int r = 0; + natpmpresp_t response; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + } while(r == NATPMP_TRYAGAIN); + + if (r == 0) { + mapping.localPort = response.pnu.newportmapping.privateport; + mapping.publicPort = response.pnu.newportmapping.mappedpublicport; + mapping.leaseInSeconds = response.pnu.newportmapping.lifetime; + return mapping; + } + else { + SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; + return boost::optional<NATPortMapping>(); + } +} + +bool NATPMPInterface::removePortForward(const NATPortMapping& mapping) { + if (sendnewportmappingrequest(&natpmp, mapping.protocol == NATPortMapping::TCP ? NATPMP_PROTOCOL_TCP : NATPMP_PROTOCOL_UDP, 0, 0, mapping.localPort) < 0) { + SWIFT_LOG(debug) << "Failed to send NAT-PMP remove forwarding request!" << std::endl; + return false; + } + + int r = 0; + natpmpresp_t response; + do { + fd_set fds; + struct timeval timeout; + FD_ZERO(&fds); + FD_SET(natpmp.s, &fds); + getnatpmprequesttimeout(&natpmp, &timeout); + select(FD_SETSIZE, &fds, NULL, NULL, &timeout); + r = readnatpmpresponseorretry(&natpmp, &response); + } while(r == NATPMP_TRYAGAIN); + + if (r == 0) { + return true; + } + else { + SWIFT_LOG(debug) << "Invalid NAT-PMP response." << std::endl; + return false; + } +} + + +} diff --git a/Swiften/Network/NATPMPInterface.h b/Swiften/Network/NATPMPInterface.h new file mode 100644 index 0000000..6e7fb73 --- /dev/null +++ b/Swiften/Network/NATPMPInterface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <Swiften/Network/NATPortMapping.h> +#include <Swiften/Network/NATTraversalInterface.h> + +// This has to be included after the previous headers, because of WIN32 macro +// being defined somewhere. +#include <natpmp.h> + +namespace Swift { + class NATPMPInterface : public NATTraversalInterface { + public: + NATPMPInterface(); + ~NATPMPInterface(); + + virtual bool isAvailable(); + + virtual boost::optional<HostAddress> getPublicIP(); + virtual boost::optional<NATPortMapping> addPortForward(int localPort, int publicPort); + virtual bool removePortForward(const NATPortMapping&); + + private: + natpmp_t natpmp; + }; +} diff --git a/Swiften/Network/NATPortMapping.h b/Swiften/Network/NATPortMapping.h new file mode 100644 index 0000000..82f62bb --- /dev/null +++ b/Swiften/Network/NATPortMapping.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/HostAddress.h> + +namespace Swift { + struct NATPortMapping { + enum Protocol { + TCP, + UDP, + }; + + NATPortMapping(int localPort, int publicPort, Protocol protocol = TCP, int leaseInSeconds = 60 * 60 * 24) : publicPort(publicPort), localPort(localPort), protocol(protocol), leaseInSeconds(leaseInSeconds) { + + } + + int publicPort; + int localPort; + Protocol protocol; + int leaseInSeconds; + }; +} diff --git a/Swiften/Network/NATTraversalForwardPortRequest.cpp b/Swiften/Network/NATTraversalForwardPortRequest.cpp new file mode 100644 index 0000000..c364b8f --- /dev/null +++ b/Swiften/Network/NATTraversalForwardPortRequest.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NATTraversalForwardPortRequest.h> + +namespace Swift { + +NATTraversalForwardPortRequest::~NATTraversalForwardPortRequest() { +} + +} diff --git a/Swiften/Network/NATTraversalForwardPortRequest.h b/Swiften/Network/NATTraversalForwardPortRequest.h new file mode 100644 index 0000000..1bbc9ca --- /dev/null +++ b/Swiften/Network/NATTraversalForwardPortRequest.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/Network/NATPortMapping.h> + +namespace Swift { + class NATTraversalForwardPortRequest { + public: + virtual ~NATTraversalForwardPortRequest(); + + virtual void run() = 0; + + boost::signal<void (boost::optional<NATPortMapping>)> onResult; + }; +} diff --git a/Swiften/Network/NATTraversalGetPublicIPRequest.cpp b/Swiften/Network/NATTraversalGetPublicIPRequest.cpp new file mode 100644 index 0000000..d8219d5 --- /dev/null +++ b/Swiften/Network/NATTraversalGetPublicIPRequest.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> + +namespace Swift { + +NATTraversalGetPublicIPRequest::~NATTraversalGetPublicIPRequest() { +} + +} diff --git a/Swiften/Network/NATTraversalGetPublicIPRequest.h b/Swiften/Network/NATTraversalGetPublicIPRequest.h new file mode 100644 index 0000000..db1f005 --- /dev/null +++ b/Swiften/Network/NATTraversalGetPublicIPRequest.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddress.h> + +namespace Swift { + class NATTraversalGetPublicIPRequest { + public: + virtual ~NATTraversalGetPublicIPRequest(); + + virtual void run() = 0; + + boost::signal<void (boost::optional<HostAddress>)> onResult; + }; +} diff --git a/Swiften/Network/NATTraversalInterface.cpp b/Swiften/Network/NATTraversalInterface.cpp new file mode 100644 index 0000000..f8a0cc2 --- /dev/null +++ b/Swiften/Network/NATTraversalInterface.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NATTraversalInterface.h> + +#include <Swiften/Base/Log.h> + + +namespace Swift { + +NATTraversalInterface::~NATTraversalInterface() { +} + +} diff --git a/Swiften/Network/NATTraversalInterface.h b/Swiften/Network/NATTraversalInterface.h new file mode 100644 index 0000000..c84deba --- /dev/null +++ b/Swiften/Network/NATTraversalInterface.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include <Swiften/Network/NATPortMapping.h> + +namespace Swift { + class NATTraversalInterface { + public: + virtual ~NATTraversalInterface(); + + virtual bool isAvailable() = 0; + + virtual boost::optional<HostAddress> getPublicIP() = 0; + virtual boost::optional<NATPortMapping> addPortForward(int localPort, int publicPort) = 0; + virtual bool removePortForward(const NATPortMapping&) = 0; + }; +} diff --git a/Swiften/Network/NATTraversalRemovePortForwardingRequest.cpp b/Swiften/Network/NATTraversalRemovePortForwardingRequest.cpp new file mode 100644 index 0000000..04ec715 --- /dev/null +++ b/Swiften/Network/NATTraversalRemovePortForwardingRequest.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> + +namespace Swift { + +NATTraversalRemovePortForwardingRequest::~NATTraversalRemovePortForwardingRequest() { +} + +} diff --git a/Swiften/Network/NATTraversalRemovePortForwardingRequest.h b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h new file mode 100644 index 0000000..cf349b1 --- /dev/null +++ b/Swiften/Network/NATTraversalRemovePortForwardingRequest.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddress.h> + +namespace Swift { + class NATTraversalRemovePortForwardingRequest { + public: + struct PortMapping { + enum Protocol { + TCP, + UDP, + }; + + unsigned int publicPort; + unsigned int localPort; + Protocol protocol; + unsigned long leaseInSeconds; + }; + + public: + virtual ~NATTraversalRemovePortForwardingRequest(); + + virtual void run() = 0; + + boost::signal<void (boost::optional<bool> /* failure */)> onResult; + }; +} diff --git a/Swiften/Network/NATTraverser.cpp b/Swiften/Network/NATTraverser.cpp new file mode 100644 index 0000000..8c628ee --- /dev/null +++ b/Swiften/Network/NATTraverser.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/NATTraverser.h> + +namespace Swift { + +NATTraverser::~NATTraverser() { +} + +} diff --git a/Swiften/Network/NATTraverser.h b/Swiften/Network/NATTraverser.h new file mode 100644 index 0000000..e48ce26 --- /dev/null +++ b/Swiften/Network/NATTraverser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +namespace Swift { + class NATTraversalGetPublicIPRequest; + class NATTraversalForwardPortRequest; + class NATTraversalRemovePortForwardingRequest; + + class NATTraverser { + public: + virtual ~NATTraverser(); + + virtual boost::shared_ptr<NATTraversalGetPublicIPRequest> createGetPublicIPRequest() = 0; + virtual boost::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(int localPort, int publicPort) = 0; + virtual boost::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(int localPort, int publicPort) = 0; + }; +} diff --git a/Swiften/Network/NetworkEnvironment.cpp b/Swiften/Network/NetworkEnvironment.cpp new file mode 100644 index 0000000..52ceb01 --- /dev/null +++ b/Swiften/Network/NetworkEnvironment.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/NetworkEnvironment.h> + +#include <Swiften/Network/NetworkInterface.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Base/foreach.h> + +namespace Swift { + +NetworkEnvironment::~NetworkEnvironment() { +} + +HostAddress NetworkEnvironment::getLocalAddress() const { + std::vector<NetworkInterface> networkInterfaces = getNetworkInterfaces(); + foreach (const NetworkInterface& iface, networkInterfaces) { + if (!iface.isLoopback()) { + foreach (const HostAddress& address, iface.getAddresses()) { + if (address.getRawAddress().is_v4()) { + return address; + } + } + } + } + return HostAddress(); +} + +} diff --git a/Swiften/Network/NetworkEnvironment.h b/Swiften/Network/NetworkEnvironment.h new file mode 100644 index 0000000..fbff0cb --- /dev/null +++ b/Swiften/Network/NetworkEnvironment.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/NetworkInterface.h> + +namespace Swift { + class NetworkEnvironment { + public: + virtual ~NetworkEnvironment(); + + virtual std::vector<NetworkInterface> getNetworkInterfaces() const = 0; + + HostAddress getLocalAddress() const; + }; +} diff --git a/Swiften/Network/NetworkFactories.cpp b/Swiften/Network/NetworkFactories.cpp index 361cb90..7046fd3 100644 --- a/Swiften/Network/NetworkFactories.cpp +++ b/Swiften/Network/NetworkFactories.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/NetworkFactories.h" +#include <Swiften/Network/NetworkFactories.h> namespace Swift { diff --git a/Swiften/Network/NetworkFactories.h b/Swiften/Network/NetworkFactories.h index d0d2299..05ddfe3 100644 --- a/Swiften/Network/NetworkFactories.h +++ b/Swiften/Network/NetworkFactories.h @@ -11,6 +11,7 @@ namespace Swift { class ConnectionFactory; class DomainNameResolver; class ConnectionServerFactory; + class NATTraverser; /** * An interface collecting network factories. @@ -23,5 +24,6 @@ namespace Swift { virtual ConnectionFactory* getConnectionFactory() const = 0; virtual DomainNameResolver* getDomainNameResolver() const = 0; virtual ConnectionServerFactory* getConnectionServerFactory() const = 0; + virtual NATTraverser* getNATTraverser() const = 0; }; } diff --git a/Swiften/Network/NetworkInterface.h b/Swiften/Network/NetworkInterface.h new file mode 100644 index 0000000..1d302cb --- /dev/null +++ b/Swiften/Network/NetworkInterface.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/Network/HostAddress.h> + +namespace Swift { + class NetworkInterface { + public: + NetworkInterface(const std::string& name, bool loopback) : name(name), loopback(loopback) { + } + + void addAddress(const HostAddress& address) { + addresses.push_back(address); + } + + const std::vector<HostAddress>& getAddresses() const { + return addresses; + } + + const std::string& getName() const { + return name; + } + + bool isLoopback() const { + return loopback; + } + + private: + std::string name; + bool loopback; + std::vector<HostAddress> addresses; + }; +} diff --git a/Swiften/Network/NullNATTraversalInterface.h b/Swiften/Network/NullNATTraversalInterface.h new file mode 100644 index 0000000..72a4a08 --- /dev/null +++ b/Swiften/Network/NullNATTraversalInterface.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include <Swiften/Network/NATTraversalInterface.h> + +namespace Swift { + class NullNATTraversalInterface : public NATTraversalInterface { + public: + virtual bool isAvailable() { + return true; + } + + virtual boost::optional<HostAddress> getPublicIP() { + return boost::optional<HostAddress>(); + } + + virtual boost::optional<NATPortMapping> addPortForward(int, int) { + return boost::optional<NATPortMapping>(); + } + + virtual bool removePortForward(const NATPortMapping&) { + return false; + } + }; +} diff --git a/Swiften/Network/NullNATTraverser.cpp b/Swiften/Network/NullNATTraverser.cpp new file mode 100644 index 0000000..8cb35cd --- /dev/null +++ b/Swiften/Network/NullNATTraverser.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Network/NullNATTraverser.h> + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/bind.hpp> + +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> +#include <Swiften/Network/NATTraversalForwardPortRequest.h> +#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> +#include <Swiften/EventLoop/EventLoop.h> + +namespace Swift { + +class NullNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest { + public: + NullNATTraversalGetPublicIPRequest(EventLoop* eventLoop) : eventLoop(eventLoop) { + } + + virtual void run() { + eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<HostAddress>())); + } + + private: + EventLoop* eventLoop; +}; + +class NullNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest { + public: + NullNATTraversalForwardPortRequest(EventLoop* eventLoop) : eventLoop(eventLoop) { + } + + virtual void run() { + eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<NATPortMapping>())); + } + + private: + EventLoop* eventLoop; +}; + +class NullNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest { + public: + NullNATTraversalRemovePortForwardingRequest(EventLoop* eventLoop) : eventLoop(eventLoop) { + } + + virtual void run() { + eventLoop->postEvent(boost::bind(boost::ref(onResult), boost::optional<bool>(true))); + } + + private: + EventLoop* eventLoop; +}; + +NullNATTraverser::NullNATTraverser(EventLoop* eventLoop) : eventLoop(eventLoop) { +} + +boost::shared_ptr<NATTraversalGetPublicIPRequest> NullNATTraverser::createGetPublicIPRequest() { + return boost::make_shared<NullNATTraversalGetPublicIPRequest>(eventLoop); +} + +boost::shared_ptr<NATTraversalForwardPortRequest> NullNATTraverser::createForwardPortRequest(int, int) { + return boost::make_shared<NullNATTraversalForwardPortRequest>(eventLoop); +} + +boost::shared_ptr<NATTraversalRemovePortForwardingRequest> NullNATTraverser::createRemovePortForwardingRequest(int, int) { + return boost::make_shared<NullNATTraversalRemovePortForwardingRequest>(eventLoop); +} + +} diff --git a/Swiften/Network/NullNATTraverser.h b/Swiften/Network/NullNATTraverser.h new file mode 100644 index 0000000..5775a9b --- /dev/null +++ b/Swiften/Network/NullNATTraverser.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/NATTraverser.h> + +namespace Swift { + class EventLoop; + + class NullNATTraverser : public NATTraverser { + public: + NullNATTraverser(EventLoop* eventLoop); + + boost::shared_ptr<NATTraversalGetPublicIPRequest> createGetPublicIPRequest(); + boost::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(int localPort, int publicPort); + boost::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(int localPort, int publicPort); + + private: + EventLoop* eventLoop; + }; +} diff --git a/Swiften/Network/NullProxyProvider.cpp b/Swiften/Network/NullProxyProvider.cpp new file mode 100644 index 0000000..3b9d94d --- /dev/null +++ b/Swiften/Network/NullProxyProvider.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/NullProxyProvider.h> + +using namespace Swift; + +NullProxyProvider::NullProxyProvider() { +} + +HostAddressPort NullProxyProvider::getHTTPConnectProxy() const { + return HostAddressPort(); +} + +HostAddressPort NullProxyProvider::getSOCKS5Proxy() const { + return HostAddressPort(); +} diff --git a/Swiften/Network/NullProxyProvider.h b/Swiften/Network/NullProxyProvider.h new file mode 100644 index 0000000..544bea2 --- /dev/null +++ b/Swiften/Network/NullProxyProvider.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ProxyProvider.h> + +namespace Swift { + class NullProxyProvider : public ProxyProvider { + public: + NullProxyProvider(); + + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + }; +} diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.cpp b/Swiften/Network/PlatformDomainNameAddressQuery.cpp index 1832255..ec7e663 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.cpp +++ b/Swiften/Network/PlatformDomainNameAddressQuery.cpp @@ -6,6 +6,8 @@ #include <Swiften/Network/PlatformDomainNameAddressQuery.h> +#include <boost/asio/ip/tcp.hpp> + #include <Swiften/Network/PlatformDomainNameResolver.h> #include <Swiften/EventLoop/EventLoop.h> diff --git a/Swiften/Network/PlatformDomainNameAddressQuery.h b/Swiften/Network/PlatformDomainNameAddressQuery.h index c2854ac..e1dc05f 100644 --- a/Swiften/Network/PlatformDomainNameAddressQuery.h +++ b/Swiften/Network/PlatformDomainNameAddressQuery.h @@ -6,7 +6,7 @@ #pragma once -#include <boost/asio.hpp> +#include <boost/asio/io_service.hpp> #include <boost/enable_shared_from_this.hpp> #include <Swiften/Network/DomainNameAddressQuery.h> diff --git a/Swiften/Network/PlatformDomainNameResolver.cpp b/Swiften/Network/PlatformDomainNameResolver.cpp index f2c1e36..63f7404 100644 --- a/Swiften/Network/PlatformDomainNameResolver.cpp +++ b/Swiften/Network/PlatformDomainNameResolver.cpp @@ -4,10 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/PlatformDomainNameResolver.h" +#include <Swiften/Network/PlatformDomainNameResolver.h> // Putting this early on, because some system types conflict with thread -#include "Swiften/Network/PlatformDomainNameServiceQuery.h" +#include <Swiften/Network/PlatformDomainNameServiceQuery.h> #include <string> #include <vector> @@ -16,11 +16,11 @@ #include <algorithm> #include <string> -#include "Swiften/IDN/IDNA.h" -#include "Swiften/Network/HostAddress.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/Network/DomainNameAddressQuery.h" +#include <Swiften/IDN/IDNA.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/DomainNameAddressQuery.h> #include <Swiften/Network/PlatformDomainNameAddressQuery.h> using namespace Swift; diff --git a/Swiften/Network/PlatformDomainNameResolver.h b/Swiften/Network/PlatformDomainNameResolver.h index e681331..295ecc5 100644 --- a/Swiften/Network/PlatformDomainNameResolver.h +++ b/Swiften/Network/PlatformDomainNameResolver.h @@ -7,7 +7,7 @@ #pragma once #include <deque> -#include <boost/thread.hpp> +#include <boost/thread/thread.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.cpp b/Swiften/Network/PlatformDomainNameServiceQuery.cpp index 7d8074d..5d076ac 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.cpp +++ b/Swiften/Network/PlatformDomainNameServiceQuery.cpp @@ -6,11 +6,11 @@ #include <boost/asio.hpp> -#include "Swiften/Network/PlatformDomainNameServiceQuery.h" +#include <Swiften/Network/PlatformDomainNameServiceQuery.h> #pragma GCC diagnostic ignored "-Wold-style-cast" -#include "Swiften/Base/Platform.h" +#include <Swiften/Base/Platform.h> #include <stdlib.h> #ifdef SWIFTEN_PLATFORM_WINDOWS #undef UNICODE @@ -26,9 +26,9 @@ #endif #include <boost/bind.hpp> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/Base/foreach.h> #include <Swiften/Base/Log.h> #include <Swiften/Network/PlatformDomainNameResolver.h> @@ -81,7 +81,7 @@ void PlatformDomainNameServiceQuery::runBlocking() { ByteArray response; response.resize(NS_PACKETSZ); - int responseLength = res_query(const_cast<char*>(service.c_str()), ns_c_in, ns_t_srv, reinterpret_cast<u_char*>(response.getData()), response.getSize()); + int responseLength = res_query(const_cast<char*>(service.c_str()), ns_c_in, ns_t_srv, reinterpret_cast<u_char*>(vecptr(response)), response.size()); if (responseLength == -1) { SWIFT_LOG(debug) << "Error" << std::endl; emitError(); @@ -89,8 +89,8 @@ void PlatformDomainNameServiceQuery::runBlocking() { } // Parse header - HEADER* header = reinterpret_cast<HEADER*>(response.getData()); - unsigned char* messageStart = reinterpret_cast<unsigned char*>(response.getData()); + HEADER* header = reinterpret_cast<HEADER*>(vecptr(response)); + unsigned char* messageStart = vecptr(response); unsigned char* messageEnd = messageStart + responseLength; unsigned char* currentEntry = messageStart + NS_HFIXEDSZ; @@ -146,12 +146,12 @@ void PlatformDomainNameServiceQuery::runBlocking() { } ByteArray entry; entry.resize(NS_MAXDNAME); - entryLength = dn_expand(messageStart, messageEnd, currentEntry, reinterpret_cast<char*>(entry.getData()), entry.getSize()); + entryLength = dn_expand(messageStart, messageEnd, currentEntry, reinterpret_cast<char*>(vecptr(entry)), entry.size()); if (entryLength < 0) { emitError(); return; } - record.hostname = std::string(reinterpret_cast<const char*>(entry.getData())); + record.hostname = std::string(reinterpret_cast<const char*>(vecptr(entry))); records.push_back(record); currentEntry += entryLength; answersCount--; diff --git a/Swiften/Network/PlatformDomainNameServiceQuery.h b/Swiften/Network/PlatformDomainNameServiceQuery.h index 52f8bc1..3372517 100644 --- a/Swiften/Network/PlatformDomainNameServiceQuery.h +++ b/Swiften/Network/PlatformDomainNameServiceQuery.h @@ -8,8 +8,8 @@ #include <boost/enable_shared_from_this.hpp> -#include "Swiften/Network/DomainNameServiceQuery.h" -#include "Swiften/EventLoop/EventOwner.h" +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/EventLoop/EventOwner.h> #include <string> #include <Swiften/Network/PlatformDomainNameQuery.h> diff --git a/Swiften/Network/PlatformNATTraversalWorker.cpp b/Swiften/Network/PlatformNATTraversalWorker.cpp new file mode 100644 index 0000000..c962b3b --- /dev/null +++ b/Swiften/Network/PlatformNATTraversalWorker.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "PlatformNATTraversalWorker.h" + +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/Network/NATTraversalGetPublicIPRequest.h> +#include <Swiften/Network/NATTraversalForwardPortRequest.h> +#include <Swiften/Network/NATTraversalRemovePortForwardingRequest.h> +#include <Swiften/Network/NATPMPInterface.h> +#include <Swiften/Network/MiniUPnPInterface.h> + +namespace Swift { + +class PlatformNATTraversalRequest : public boost::enable_shared_from_this<PlatformNATTraversalRequest> { + public: + typedef boost::shared_ptr<PlatformNATTraversalRequest> ref; + + public: + PlatformNATTraversalRequest(PlatformNATTraversalWorker* worker) : worker(worker) { + } + + virtual ~PlatformNATTraversalRequest() { + } + + virtual void doRun() { + worker->addRequestToQueue(shared_from_this()); + } + + NATTraversalInterface* getNATTraversalInterface() const { + return worker->getNATTraversalInterface(); + } + + + virtual void runBlocking() = 0; + + private: + PlatformNATTraversalWorker* worker; +}; + +class PlatformNATTraversalGetPublicIPRequest : public NATTraversalGetPublicIPRequest, public PlatformNATTraversalRequest { + public: + PlatformNATTraversalGetPublicIPRequest(PlatformNATTraversalWorker* worker) : PlatformNATTraversalRequest(worker) { + } + + virtual void run() { + doRun(); + } + + virtual void runBlocking() { + onResult(getNATTraversalInterface()->getPublicIP()); + } +}; + +class PlatformNATTraversalForwardPortRequest : public NATTraversalForwardPortRequest, public PlatformNATTraversalRequest { + public: + PlatformNATTraversalForwardPortRequest(PlatformNATTraversalWorker* worker, unsigned int localIP, unsigned int publicIP) : PlatformNATTraversalRequest(worker), localIP(localIP), publicIP(publicIP) { + } + + virtual void run() { + doRun(); + } + + virtual void runBlocking() { + onResult(getNATTraversalInterface()->addPortForward(localIP, publicIP)); + } + + private: + unsigned int localIP; + unsigned int publicIP; +}; + +class PlatformNATTraversalRemovePortForwardingRequest : public NATTraversalRemovePortForwardingRequest, public PlatformNATTraversalRequest { + public: + PlatformNATTraversalRemovePortForwardingRequest(PlatformNATTraversalWorker* worker, const NATPortMapping& mapping) : PlatformNATTraversalRequest(worker), mapping(mapping) { + } + + virtual void run() { + doRun(); + } + + virtual void runBlocking() { + onResult(getNATTraversalInterface()->removePortForward(mapping)); + } + + private: + NATPortMapping mapping; +}; + +PlatformNATTraversalWorker::PlatformNATTraversalWorker(EventLoop* eventLoop) : eventLoop(eventLoop), stopRequested(false), natPMPSupported(boost::logic::indeterminate), natPMPInterface(NULL), miniUPnPSupported(boost::logic::indeterminate), miniUPnPInterface(NULL) { + nullNATTraversalInterface = new NullNATTraversalInterface(); + thread = new boost::thread(boost::bind(&PlatformNATTraversalWorker::run, this)); +} + +PlatformNATTraversalWorker::~PlatformNATTraversalWorker() { + stopRequested = true; + addRequestToQueue(boost::shared_ptr<PlatformNATTraversalRequest>()); + thread->join(); + delete thread; + delete natPMPInterface; + delete miniUPnPInterface; + delete nullNATTraversalInterface; +} + +NATTraversalInterface* PlatformNATTraversalWorker::getNATTraversalInterface() const { + if (boost::logic::indeterminate(miniUPnPSupported)) { + miniUPnPInterface = new MiniUPnPInterface(); + miniUPnPSupported = miniUPnPInterface->isAvailable(); + } + if (miniUPnPSupported) { + return miniUPnPInterface; + } + + + if (boost::logic::indeterminate(natPMPSupported)) { + natPMPInterface = new NATPMPInterface(); + natPMPSupported = natPMPInterface->isAvailable(); + } + if (natPMPSupported) { + return natPMPInterface; + } + + return nullNATTraversalInterface; +} + +boost::shared_ptr<NATTraversalGetPublicIPRequest> PlatformNATTraversalWorker::createGetPublicIPRequest() { + return boost::make_shared<PlatformNATTraversalGetPublicIPRequest>(this); +} + +boost::shared_ptr<NATTraversalForwardPortRequest> PlatformNATTraversalWorker::createForwardPortRequest(int localPort, int publicPort) { + return boost::make_shared<PlatformNATTraversalForwardPortRequest>(this, localPort, publicPort); +} + +boost::shared_ptr<NATTraversalRemovePortForwardingRequest> PlatformNATTraversalWorker::createRemovePortForwardingRequest(int localPort, int publicPort) { + NATPortMapping mapping(localPort, publicPort, NATPortMapping::TCP); // FIXME + return boost::make_shared<PlatformNATTraversalRemovePortForwardingRequest>(this, mapping); +} + +void PlatformNATTraversalWorker::run() { + while (!stopRequested) { + PlatformNATTraversalRequest::ref request; + { + boost::unique_lock<boost::mutex> lock(queueMutex); + while (queue.empty()) { + queueNonEmpty.wait(lock); + } + request = queue.front(); + queue.pop_front(); + } + // Check whether we don't have a non-null request (used to stop the + // worker) + if (request) { + request->runBlocking(); + } + } +} + +void PlatformNATTraversalWorker::addRequestToQueue(PlatformNATTraversalRequest::ref request) { + { + boost::lock_guard<boost::mutex> lock(queueMutex); + queue.push_back(request); + } + queueNonEmpty.notify_one(); +} + +} diff --git a/Swiften/Network/PlatformNATTraversalWorker.h b/Swiften/Network/PlatformNATTraversalWorker.h new file mode 100644 index 0000000..94d3339 --- /dev/null +++ b/Swiften/Network/PlatformNATTraversalWorker.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <deque> +#include <boost/optional.hpp> +#include <boost/thread/thread.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/condition_variable.hpp> +#include <boost/logic/tribool.hpp> + +#include <Swiften/Network/NATTraverser.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/NullNATTraversalInterface.h> + +namespace Swift { + class EventLoop; + class NATTraversalGetPublicIPRequest; + class NATTraversalForwardPortRequest; + class NATTraversalRemovePortForwardingRequest; + class PlatformNATTraversalRequest; + class NATPMPInterface; + class MiniUPnPInterface; + class NATTraversalInterface; + class NATPortMapping; + + class PlatformNATTraversalWorker : public NATTraverser { + friend class PlatformNATTraversalRequest; + + public: + PlatformNATTraversalWorker(EventLoop* eventLoop); + ~PlatformNATTraversalWorker(); + + boost::shared_ptr<NATTraversalGetPublicIPRequest> createGetPublicIPRequest(); + boost::shared_ptr<NATTraversalForwardPortRequest> createForwardPortRequest(int localPort, int publicPort); + boost::shared_ptr<NATTraversalRemovePortForwardingRequest> createRemovePortForwardingRequest(int localPort, int publicPort); + + private: + NATTraversalInterface* getNATTraversalInterface() const; + void addRequestToQueue(boost::shared_ptr<PlatformNATTraversalRequest>); + void run(); + + private: + EventLoop* eventLoop; + bool stopRequested; + boost::thread* thread; + std::deque<boost::shared_ptr<PlatformNATTraversalRequest> > queue; + boost::mutex queueMutex; + boost::condition_variable queueNonEmpty; + + NullNATTraversalInterface* nullNATTraversalInterface; + mutable boost::logic::tribool natPMPSupported; + mutable NATPMPInterface* natPMPInterface; + mutable boost::logic::tribool miniUPnPSupported; + mutable MiniUPnPInterface* miniUPnPInterface; + }; +} diff --git a/Swiften/Network/PlatformNetworkEnvironment.h b/Swiften/Network/PlatformNetworkEnvironment.h new file mode 100644 index 0000000..c6b945e --- /dev/null +++ b/Swiften/Network/PlatformNetworkEnvironment.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Platform.h> + +#if defined(SWIFTEN_PLATFORM_MACOSX) +#include <Swiften/Network/UnixNetworkEnvironment.h> +namespace Swift { + typedef UnixNetworkEnvironment PlatformNetworkEnvironment; +} +#elif defined(SWIFTEN_PLATFORM_WIN32) +#include <Swiften/Network/WindowsNetworkEnvironment.h> +namespace Swift { + typedef WindowsNetworkEnvironment PlatformNetworkEnvironment; +} +#else +#include <Swiften/Network/UnixNetworkEnvironment.h> +namespace Swift { + typedef UnixNetworkEnvironment PlatformNetworkEnvironment; +} +#endif diff --git a/Swiften/Network/PlatformProxyProvider.h b/Swiften/Network/PlatformProxyProvider.h new file mode 100644 index 0000000..1a0a1c6 --- /dev/null +++ b/Swiften/Network/PlatformProxyProvider.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/Platform.h> + +#if defined(SWIFTEN_PLATFORM_MACOSX) +#include <Swiften/Network/MacOSXProxyProvider.h> +namespace Swift { + typedef MacOSXProxyProvider PlatformProxyProvider; +} +#elif defined(SWIFTEN_PLATFORM_WIN32) +#include <Swiften/Network/WindowsProxyProvider.h> +namespace Swift { + typedef WindowsProxyProvider PlatformProxyProvider; +} +#else +#include <Swiften/Network/UnixProxyProvider.h> +namespace Swift { + typedef UnixProxyProvider PlatformProxyProvider; +} +#endif diff --git a/Swiften/Network/ProxyProvider.cpp b/Swiften/Network/ProxyProvider.cpp new file mode 100644 index 0000000..fe235b1 --- /dev/null +++ b/Swiften/Network/ProxyProvider.cpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "ProxyProvider.h" + +namespace Swift { + +ProxyProvider::ProxyProvider() +{ +} + +ProxyProvider::~ProxyProvider() +{ +} + +} diff --git a/Swiften/Network/ProxyProvider.h b/Swiften/Network/ProxyProvider.h new file mode 100644 index 0000000..0b63d51 --- /dev/null +++ b/Swiften/Network/ProxyProvider.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include <map> + +#include <Swiften/Base/Log.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Base/String.h> + +namespace Swift { + class ProxyProvider { + public: + ProxyProvider(); + virtual ~ProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const = 0; + virtual HostAddressPort getSOCKS5Proxy() const = 0; + }; +} + diff --git a/Swiften/Network/SConscript b/Swiften/Network/SConscript index d5cc185..49df18f 100644 --- a/Swiften/Network/SConscript +++ b/Swiften/Network/SConscript @@ -6,6 +6,10 @@ if myenv.get("HAVE_CARES", False) : myenv.MergeFlags(myenv.get("CARES_FLAGS", {})) sourceList = [ + "HTTPConnectProxiedConnection.cpp", + "HTTPConnectProxiedConnectionFactory.cpp", + "SOCKS5ProxiedConnection.cpp", + "SOCKS5ProxiedConnectionFactory.cpp", "BoostConnection.cpp", "BoostConnectionFactory.cpp", "BoostConnectionServer.cpp", @@ -14,7 +18,11 @@ sourceList = [ "ConnectionFactory.cpp", "ConnectionServer.cpp", "ConnectionServerFactory.cpp", + "DummyConnection.cpp", + "FakeConnection.cpp", + "ChainedConnector.cpp", "Connector.cpp", + "Connection.cpp", "TimerFactory.cpp", "DummyTimerFactory.cpp", "BoostTimerFactory.cpp", @@ -26,13 +34,59 @@ sourceList = [ "PlatformDomainNameAddressQuery.cpp", "StaticDomainNameResolver.cpp", "HostAddress.cpp", + "HostAddressPort.cpp", "NetworkFactories.cpp", "BoostNetworkFactories.cpp", + "NetworkEnvironment.cpp", "Timer.cpp", - "BoostTimer.cpp"] + "BoostTimer.cpp", + "ProxyProvider.cpp", + "NullProxyProvider.cpp", + "NATTraverser.cpp", + "NullNATTraverser.cpp", + "NATTraversalGetPublicIPRequest.cpp", + "NATTraversalForwardPortRequest.cpp", + "NATTraversalRemovePortForwardingRequest.cpp", + "NATTraversalInterface.cpp", + ] + if myenv.get("HAVE_CARES", False) : sourceList.append("CAresDomainNameResolver.cpp") +if myenv["PLATFORM"] == "darwin" : + myenv.Append(FRAMEWORKS = ["CoreServices", "SystemConfiguration"]) + sourceList += [ "MacOSXProxyProvider.cpp" ] + sourceList += [ "UnixNetworkEnvironment.cpp" ] +elif myenv["PLATFORM"] == "win32" : + sourceList += [ "WindowsProxyProvider.cpp" ] + sourceList += [ "WindowsNetworkEnvironment.cpp" ] +else : + sourceList += [ "UnixNetworkEnvironment.cpp" ] + sourceList += [ "UnixProxyProvider.cpp" ] + sourceList += [ "EnvironmentProxyProvider.cpp" ] + if myenv.get("HAVE_GCONF", 0) : + myenv.Append(CPPDEFINES = "HAVE_GCONF") + myenv.MergeFlags(myenv["GCONF_FLAGS"]) + sourceList += [ "GConfProxyProvider.cpp" ] objects = myenv.SwiftenObject(sourceList) + +if myenv["experimental"] : + # LibNATPMP classes + natpmp_env = myenv.Clone() + natpmp_env.Append(CPPDEFINES = natpmp_env["LIBNATPMP_FLAGS"].get("INTERNAL_CPPDEFINES", [])) + objects += natpmp_env.SwiftenObject([ + "NATPMPInterface.cpp", + ]) + + # LibMINIUPnP classes + upnp_env = myenv.Clone() + upnp_env.Append(CPPDEFINES = upnp_env["LIBMINIUPNPC_FLAGS"].get("INTERNAL_CPPDEFINES", [])) + objects += upnp_env.SwiftenObject([ + "MiniUPnPInterface.cpp", + ]) + objects += myenv.SwiftenObject([ + "PlatformNATTraversalWorker.cpp", + ]) + swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/Network/SOCKS5ProxiedConnection.cpp b/Swiften/Network/SOCKS5ProxiedConnection.cpp new file mode 100644 index 0000000..163e23a --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnection.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/SOCKS5ProxiedConnection.h> + +#include <iostream> +#include <boost/bind.hpp> +#include <boost/thread.hpp> + +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/String.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/HostAddressPort.h> + +using namespace Swift; + +SOCKS5ProxiedConnection::SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy), server_(HostAddressPort(HostAddress("0.0.0.0"), 0)) { + connected_ = false; +} + +SOCKS5ProxiedConnection::~SOCKS5ProxiedConnection() { + if (connection_) { + connection_->onDataRead.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + } + + if (connected_) { + std::cerr << "Warning: Connection was still established." << std::endl; + } +} + +void SOCKS5ProxiedConnection::connect(const HostAddressPort& server) { + server_ = server; + connection_ = connectionFactory_->createConnection(); + connection_->onConnectFinished.connect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + connection_->onDataRead.connect(boost::bind(&SOCKS5ProxiedConnection::handleDataRead, shared_from_this(), _1)); + connection_->onDisconnected.connect(boost::bind(&SOCKS5ProxiedConnection::handleDisconnected, shared_from_this(), _1)); + SWIFT_LOG(debug) << "Trying to connect via proxy " << proxy_.getAddress().toString() << ":" << proxy_.getPort() << std::endl; + SWIFT_LOG(debug) << "to server " << server.getAddress().toString() << ":" << server.getPort() << std::endl; + connection_->connect(proxy_); +} + +void SOCKS5ProxiedConnection::listen() { + assert(false); + connection_->listen(); +} + +void SOCKS5ProxiedConnection::disconnect() { + connected_ = false; + if (connection_) { + connection_->disconnect(); + } +} + +void SOCKS5ProxiedConnection::handleDisconnected(const boost::optional<Error>& error) { + onDisconnected(error); +} + +void SOCKS5ProxiedConnection::write(const SafeByteArray& data) { + if (connection_) { + connection_->write(data); + } +} + +void SOCKS5ProxiedConnection::handleConnectionConnectFinished(bool error) { + connection_->onConnectFinished.disconnect(boost::bind(&SOCKS5ProxiedConnection::handleConnectionConnectFinished, shared_from_this(), _1)); + if (!error) { + SWIFT_LOG(debug) << "Connection to proxy established, now connect to the server via it." << std::endl; + + proxyState_ = ProxyAuthenticating; + SafeByteArray socksConnect; + socksConnect.push_back(0x05); // VER = SOCKS5 = 0x05 + socksConnect.push_back(0x01); // Number of authentication methods after this byte. + socksConnect.push_back(0x00); // 0x00 == no authentication + // buffer.push_back(0x01); // 0x01 == GSSAPI + // buffer.push_back(0x02); // 0x02 == Username/Password + // rest see RFC 1928 (http://tools.ietf.org/html/rfc1928) + connection_->write(socksConnect); + } + else { + onConnectFinished(true); + } +} + +void SOCKS5ProxiedConnection::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + SafeByteArray socksConnect; + boost::asio::ip::address rawAddress = server_.getAddress().getRawAddress(); + assert(rawAddress.is_v4() || rawAddress.is_v6()); + if (!connected_) { + if (proxyState_ == ProxyAuthenticating) { + SWIFT_LOG(debug) << "ProxyAuthenticating response received, reply with the connect BYTEs" << std::endl; + unsigned char choosenMethod = static_cast<unsigned char> ((*data)[1]); + if ((*data)[0] == 0x05 && choosenMethod != 0xFF) { + switch(choosenMethod) { // use the correct Method + case 0x00: + try { + proxyState_ = ProxyConnecting; + socksConnect.push_back(0x05); // VER = SOCKS5 = 0x05 + socksConnect.push_back(0x01); // Construct a TCP connection. (CMD) + socksConnect.push_back(0x00); // reserved. + socksConnect.push_back(rawAddress.is_v4() ? 0x01 : 0x04); // IPv4 == 0x01, Hostname == 0x02, IPv6 == 0x04. (ATYP) + size_t size = rawAddress.is_v4() ? rawAddress.to_v4().to_bytes().size() : rawAddress.to_v6().to_bytes().size(); + for (size_t s = 0; s < size; s++) { + unsigned char uc; + if(rawAddress.is_v4()) { + uc = rawAddress.to_v4().to_bytes()[s]; // the address. + } + else { + uc = rawAddress.to_v6().to_bytes()[s]; // the address. + } + socksConnect.push_back(static_cast<char>(uc)); + + } + socksConnect.push_back(static_cast<unsigned char> ((server_.getPort() >> 8) & 0xFF)); // highbyte of the port. + socksConnect.push_back(static_cast<unsigned char> (server_.getPort() & 0xFF)); // lowbyte of the port. + connection_->write(socksConnect); + return; + } + catch(...) { + std::cerr << "exception caught" << std::endl; + } + connection_->write(socksConnect); + break; + default: + onConnectFinished(true); + break; + } + return; + } + } + else if (proxyState_ == ProxyConnecting) { + SWIFT_LOG(debug) << "Connect response received, check if successfully." << std::endl; + SWIFT_LOG(debug) << "Errorbyte: 0x" << std::hex << static_cast<int> ((*data)[1]) << std::dec << std::endl; + /* + + data.at(1) can be one of the following: + 0x00 succeeded + 0x01 general SOCKS server failure + 0x02 connection not allowed by ruleset + 0x03 Network unreachable + 0x04 Host unreachable + 0x05 Connection refused + 0x06 TTL expired + 0x07 Command not supported (CMD) + 0x08 Address type not supported (ATYP) + 0x09 bis 0xFF unassigned + */ + if ((*data)[0] == 0x05 && (*data)[1] == 0x0) { + SWIFT_LOG(debug) << "Successfully connected the server via the proxy." << std::endl; + connected_ = true; + onConnectFinished(false); + return; + } + else { + std::cerr << "SOCKS Proxy returned an error: " << std::hex << (*data)[1] << std::endl; + } + return; + } + } + else { + onDataRead(data); + return; + } + disconnect(); + onConnectFinished(true); +} + +HostAddressPort SOCKS5ProxiedConnection::getLocalAddress() const { + return connection_->getLocalAddress(); +} diff --git a/Swiften/Network/SOCKS5ProxiedConnection.h b/Swiften/Network/SOCKS5ProxiedConnection.h new file mode 100644 index 0000000..592ce7d --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnection.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/HostAddressPort.h> + +namespace boost { + class thread; + namespace system { + class error_code; + } +} + +namespace Swift { + class ConnectionFactory; + + class SOCKS5ProxiedConnection : public Connection, public boost::enable_shared_from_this<SOCKS5ProxiedConnection> { + public: + typedef boost::shared_ptr<SOCKS5ProxiedConnection> ref; + + ~SOCKS5ProxiedConnection(); + + static ref create(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) { + return ref(new SOCKS5ProxiedConnection(connectionFactory, proxy)); + } + + virtual void listen(); + virtual void connect(const HostAddressPort& address); + virtual void disconnect(); + virtual void write(const SafeByteArray& data); + + virtual HostAddressPort getLocalAddress() const; + + private: + SOCKS5ProxiedConnection(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + + void handleConnectionConnectFinished(bool error); + void handleDataRead(boost::shared_ptr<SafeByteArray> data); + void handleDisconnected(const boost::optional<Error>& error); + + private: + enum { + ProxyAuthenticating = 0, + ProxyConnecting, + } proxyState_; + bool connected_; + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + HostAddressPort server_; + boost::shared_ptr<Connection> connection_; + }; +} diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp new file mode 100644 index 0000000..272ade9 --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.cpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/SOCKS5ProxiedConnectionFactory.h> + +#include <Swiften/Network/SOCKS5ProxiedConnection.h> + +namespace Swift { + +SOCKS5ProxiedConnectionFactory::SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy) : connectionFactory_(connectionFactory), proxy_(proxy) { +} + +boost::shared_ptr<Connection> SOCKS5ProxiedConnectionFactory::createConnection() { + return SOCKS5ProxiedConnection::create(connectionFactory_, proxy_); +} + +} diff --git a/Swiften/Network/SOCKS5ProxiedConnectionFactory.h b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h new file mode 100644 index 0000000..f36d42a --- /dev/null +++ b/Swiften/Network/SOCKS5ProxiedConnectionFactory.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> + +namespace Swift { + class SOCKS5ProxiedConnectionFactory : public ConnectionFactory { + public: + SOCKS5ProxiedConnectionFactory(ConnectionFactory* connectionFactory, const HostAddressPort& proxy); + + virtual boost::shared_ptr<Connection> createConnection(); + + private: + ConnectionFactory* connectionFactory_; + HostAddressPort proxy_; + }; +} diff --git a/Swiften/Network/StaticDomainNameResolver.cpp b/Swiften/Network/StaticDomainNameResolver.cpp index a338272..76ab411 100644 --- a/Swiften/Network/StaticDomainNameResolver.cpp +++ b/Swiften/Network/StaticDomainNameResolver.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/StaticDomainNameResolver.h" +#include <Swiften/Network/StaticDomainNameResolver.h> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> -#include "Swiften/Network/DomainNameResolveError.h" +#include <Swiften/Network/DomainNameResolveError.h> #include <string> using namespace Swift; diff --git a/Swiften/Network/StaticDomainNameResolver.h b/Swiften/Network/StaticDomainNameResolver.h index 2ef1295..a72db7c 100644 --- a/Swiften/Network/StaticDomainNameResolver.h +++ b/Swiften/Network/StaticDomainNameResolver.h @@ -9,12 +9,12 @@ #include <vector> #include <map> -#include "Swiften/Network/HostAddress.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/Network/DomainNameResolver.h" -#include "Swiften/Network/DomainNameServiceQuery.h" -#include "Swiften/Network/DomainNameAddressQuery.h" -#include "Swiften/EventLoop/EventLoop.h" +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/DomainNameResolver.h> +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/EventLoop/EventLoop.h> namespace Swift { diff --git a/Swiften/Network/Timer.cpp b/Swiften/Network/Timer.cpp index daa4490..3efbd3b 100644 --- a/Swiften/Network/Timer.cpp +++ b/Swiften/Network/Timer.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/Timer.h" +#include <Swiften/Network/Timer.h> namespace Swift { diff --git a/Swiften/Network/Timer.h b/Swiften/Network/Timer.h index d44a00d..b7578f2 100644 --- a/Swiften/Network/Timer.h +++ b/Swiften/Network/Timer.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> namespace Swift { /** diff --git a/Swiften/Network/TimerFactory.cpp b/Swiften/Network/TimerFactory.cpp index 502f669..3fb807c 100644 --- a/Swiften/Network/TimerFactory.cpp +++ b/Swiften/Network/TimerFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Network/TimerFactory.h" +#include <Swiften/Network/TimerFactory.h> namespace Swift { diff --git a/Swiften/Network/TimerFactory.h b/Swiften/Network/TimerFactory.h index 44c87b6..99903c3 100644 --- a/Swiften/Network/TimerFactory.h +++ b/Swiften/Network/TimerFactory.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Network/Timer.h" +#include <Swiften/Network/Timer.h> namespace Swift { class TimerFactory { diff --git a/Swiften/Network/UnitTest/ChainedConnectorTest.cpp b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp new file mode 100644 index 0000000..c7d23da --- /dev/null +++ b/Swiften/Network/UnitTest/ChainedConnectorTest.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Network/ChainedConnector.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/EventLoop/DummyEventLoop.h> + +using namespace Swift; + +class ChainedConnectorTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ChainedConnectorTest); + CPPUNIT_TEST(testConnect_FirstConnectorSucceeds); + CPPUNIT_TEST(testConnect_SecondConnectorSucceeds); + CPPUNIT_TEST(testConnect_NoConnectorSucceeds); + CPPUNIT_TEST(testStop); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + host = HostAddressPort(HostAddress("1.1.1.1"), 1234); + eventLoop = new DummyEventLoop(); + resolver = new StaticDomainNameResolver(eventLoop); + resolver->addXMPPClientService("foo.com", host); + connectionFactory1 = new MockConnectionFactory(eventLoop, 1); + connectionFactory2 = new MockConnectionFactory(eventLoop, 2); + timerFactory = new DummyTimerFactory(); + } + + void tearDown() { + delete timerFactory; + delete connectionFactory2; + delete connectionFactory1; + delete resolver; + delete eventLoop; + } + + void testConnect_FirstConnectorSucceeds() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = true; + connectionFactory2->connects = false; + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT_EQUAL(1, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + } + + void testConnect_SecondConnectorSucceeds() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = true; + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(connections[0]); + CPPUNIT_ASSERT_EQUAL(2, boost::dynamic_pointer_cast<MockConnection>(connections[0])->id); + } + + void testConnect_NoConnectorSucceeds() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = false; + connectionFactory2->connects = false; + + testling->start(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + } + + void testStop() { + boost::shared_ptr<ChainedConnector> testling(createConnector()); + connectionFactory1->connects = true; + connectionFactory2->connects = false; + + testling->start(); + testling->stop(); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connections.size())); + CPPUNIT_ASSERT(!connections[0]); + } + + private: + boost::shared_ptr<ChainedConnector> createConnector() { + std::vector<ConnectionFactory*> factories; + factories.push_back(connectionFactory1); + factories.push_back(connectionFactory2); + boost::shared_ptr<ChainedConnector> connector = boost::make_shared<ChainedConnector>("foo.com", resolver, factories, timerFactory); + connector->onConnectFinished.connect(boost::bind(&ChainedConnectorTest::handleConnectorFinished, this, _1)); + return connector; + } + + void handleConnectorFinished(boost::shared_ptr<Connection> connection) { + boost::shared_ptr<MockConnection> c(boost::dynamic_pointer_cast<MockConnection>(connection)); + if (connection) { + assert(c); + } + connections.push_back(c); + } + + struct MockConnection : public Connection { + public: + MockConnection(bool connects, int id, EventLoop* eventLoop) : connects(connects), id(id), eventLoop(eventLoop) { + } + + void listen() { assert(false); } + void connect(const HostAddressPort&) { + eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), !connects)); + } + + HostAddressPort getLocalAddress() const { return HostAddressPort(); } + void disconnect() { assert(false); } + void write(const SafeByteArray&) { assert(false); } + + bool connects; + int id; + EventLoop* eventLoop; + }; + + struct MockConnectionFactory : public ConnectionFactory { + MockConnectionFactory(EventLoop* eventLoop, int id) : eventLoop(eventLoop), connects(true), id(id) { + } + + boost::shared_ptr<Connection> createConnection() { + return boost::make_shared<MockConnection>(connects, id, eventLoop); + } + + EventLoop* eventLoop; + bool connects; + int id; + }; + + private: + HostAddressPort host; + DummyEventLoop* eventLoop; + StaticDomainNameResolver* resolver; + MockConnectionFactory* connectionFactory1; + MockConnectionFactory* connectionFactory2; + DummyTimerFactory* timerFactory; + std::vector< boost::shared_ptr<MockConnection> > connections; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ChainedConnectorTest); diff --git a/Swiften/Network/UnitTest/ConnectorTest.cpp b/Swiften/Network/UnitTest/ConnectorTest.cpp index c8aa9a9..6488e67 100644 --- a/Swiften/Network/UnitTest/ConnectorTest.cpp +++ b/Swiften/Network/UnitTest/ConnectorTest.cpp @@ -10,13 +10,13 @@ #include <boost/optional.hpp> #include <boost/bind.hpp> -#include "Swiften/Network/Connector.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/Network/ConnectionFactory.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/Network/StaticDomainNameResolver.h" -#include "Swiften/Network/DummyTimerFactory.h" -#include "Swiften/EventLoop/DummyEventLoop.h" +#include <Swiften/Network/Connector.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/StaticDomainNameResolver.h> +#include <Swiften/Network/DummyTimerFactory.h> +#include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; @@ -269,7 +269,7 @@ class ConnectorTest : public CppUnit::TestFixture { HostAddressPort getLocalAddress() const { return HostAddressPort(); } void disconnect() { assert(false); } - void write(const ByteArray&) { assert(false); } + void write(const SafeByteArray&) { assert(false); } EventLoop* eventLoop; boost::optional<HostAddressPort> hostAddressPort; diff --git a/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp new file mode 100644 index 0000000..133773f --- /dev/null +++ b/Swiften/Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ +#include <QA/Checker/IO.h> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/optional.hpp> +#include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Network/ConnectionFactory.h> +#include <Swiften/Network/HTTPConnectProxiedConnection.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/EventLoop/DummyEventLoop.h> + +using namespace Swift; + +class HTTPConnectProxiedConnectionTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(HTTPConnectProxiedConnectionTest); + CPPUNIT_TEST(testConnect_CreatesConnectionToProxy); + CPPUNIT_TEST(testConnect_SendsConnectRequest); + CPPUNIT_TEST(testConnect_ReceiveConnectResponse); + CPPUNIT_TEST(testConnect_ReceiveMalformedConnectResponse); + CPPUNIT_TEST(testConnect_ReceiveErrorConnectResponse); + CPPUNIT_TEST(testConnect_ReceiveDataAfterConnect); + CPPUNIT_TEST(testWrite_AfterConnect); + CPPUNIT_TEST(testDisconnect_AfterConnectRequest); + CPPUNIT_TEST(testDisconnect_AfterConnect); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + proxyHost = HostAddressPort(HostAddress("1.1.1.1"), 1234); + host = HostAddressPort(HostAddress("2.2.2.2"), 2345); + eventLoop = new DummyEventLoop(); + connectionFactory = new MockConnectionFactory(eventLoop); + connectFinished = false; + disconnected = false; + } + + void tearDown() { + delete connectionFactory; + delete eventLoop; + } + + void testConnect_CreatesConnectionToProxy() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + + testling->connect(host); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(connectionFactory->connections.size())); + CPPUNIT_ASSERT(connectionFactory->connections[0]->hostAddressPort); + CPPUNIT_ASSERT(proxyHost == *connectionFactory->connections[0]->hostAddressPort); + CPPUNIT_ASSERT(!connectFinished); + } + + void testConnect_SendsConnectRequest() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(createByteArray("CONNECT 2.2.2.2:2345 HTTP/1.1\r\n\r\n"), connectionFactory->connections[0]->dataWritten); + } + + void testConnect_ReceiveConnectResponse() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(connectFinished); + CPPUNIT_ASSERT(!connectFinishedWithError); + CPPUNIT_ASSERT(dataRead.empty()); + } + + void testConnect_ReceiveMalformedConnectResponse() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("FLOOP")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(connectFinished); + CPPUNIT_ASSERT(connectFinishedWithError); + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + } + + void testConnect_ReceiveErrorConnectResponse() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 401 Unauthorized\r\n\r\n")); + eventLoop->processEvents(); + + CPPUNIT_ASSERT(connectFinished); + CPPUNIT_ASSERT(connectFinishedWithError); + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + } + + void testConnect_ReceiveDataAfterConnect() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("abcdef")); + + CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), dataRead); + } + + void testWrite_AfterConnect() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + connectionFactory->connections[0]->dataWritten.clear(); + + testling->write(createSafeByteArray("abcdef")); + + CPPUNIT_ASSERT_EQUAL(createByteArray("abcdef"), connectionFactory->connections[0]->dataWritten); + } + + void testDisconnect_AfterConnectRequest() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + + testling->disconnect(); + + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + CPPUNIT_ASSERT(disconnected); + CPPUNIT_ASSERT(!disconnectedError); + } + + void testDisconnect_AfterConnect() { + HTTPConnectProxiedConnection::ref testling(createTestling()); + testling->connect(HostAddressPort(HostAddress("2.2.2.2"), 2345)); + eventLoop->processEvents(); + connectionFactory->connections[0]->onDataRead(createSafeByteArrayRef("HTTP/1.0 200 Connection established\r\n\r\n")); + eventLoop->processEvents(); + + testling->disconnect(); + + CPPUNIT_ASSERT(connectionFactory->connections[0]->disconnected); + CPPUNIT_ASSERT(disconnected); + CPPUNIT_ASSERT(!disconnectedError); + } + + private: + HTTPConnectProxiedConnection::ref createTestling() { + boost::shared_ptr<HTTPConnectProxiedConnection> c = HTTPConnectProxiedConnection::create(connectionFactory, proxyHost); + c->onConnectFinished.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleConnectFinished, this, _1)); + c->onDisconnected.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDisconnected, this, _1)); + c->onDataRead.connect(boost::bind(&HTTPConnectProxiedConnectionTest::handleDataRead, this, _1)); + return c; + } + + void handleConnectFinished(bool error) { + connectFinished = true; + connectFinishedWithError = error; + } + + void handleDisconnected(const boost::optional<Connection::Error>& e) { + disconnected = true; + disconnectedError = e; + } + + void handleDataRead(boost::shared_ptr<SafeByteArray> d) { + append(dataRead, *d); + } + + struct MockConnection : public Connection { + public: + MockConnection(const std::vector<HostAddressPort>& failingPorts, EventLoop* eventLoop) : eventLoop(eventLoop), failingPorts(failingPorts), disconnected(false) { + } + + void listen() { assert(false); } + + void connect(const HostAddressPort& address) { + hostAddressPort = address; + bool fail = std::find(failingPorts.begin(), failingPorts.end(), address) != failingPorts.end(); + eventLoop->postEvent(boost::bind(boost::ref(onConnectFinished), fail)); + } + + HostAddressPort getLocalAddress() const { return HostAddressPort(); } + + void disconnect() { + disconnected = true; + onDisconnected(boost::optional<Connection::Error>()); + } + + void write(const SafeByteArray& d) { + append(dataWritten, d); + } + + EventLoop* eventLoop; + boost::optional<HostAddressPort> hostAddressPort; + std::vector<HostAddressPort> failingPorts; + ByteArray dataWritten; + bool disconnected; + }; + + struct MockConnectionFactory : public ConnectionFactory { + MockConnectionFactory(EventLoop* eventLoop) : eventLoop(eventLoop) { + } + + boost::shared_ptr<Connection> createConnection() { + boost::shared_ptr<MockConnection> connection = boost::make_shared<MockConnection>(failingPorts, eventLoop); + connections.push_back(connection); + return connection; + } + + EventLoop* eventLoop; + std::vector< boost::shared_ptr<MockConnection> > connections; + std::vector<HostAddressPort> failingPorts; + }; + + private: + HostAddressPort proxyHost; + HostAddressPort host; + DummyEventLoop* eventLoop; + MockConnectionFactory* connectionFactory; + std::vector< boost::shared_ptr<MockConnection> > connections; + bool connectFinished; + bool connectFinishedWithError; + bool disconnected; + boost::optional<Connection::Error> disconnectedError; + ByteArray dataRead; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(HTTPConnectProxiedConnectionTest); diff --git a/Swiften/Network/UnitTest/HostAddressTest.cpp b/Swiften/Network/UnitTest/HostAddressTest.cpp index 7fb33ca..b2511a8 100644 --- a/Swiften/Network/UnitTest/HostAddressTest.cpp +++ b/Swiften/Network/UnitTest/HostAddressTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Network/HostAddress.h" +#include <Swiften/Network/HostAddress.h> #include <string> using namespace Swift; diff --git a/Swiften/Network/UnixNetworkEnvironment.cpp b/Swiften/Network/UnixNetworkEnvironment.cpp new file mode 100644 index 0000000..52c5cbe --- /dev/null +++ b/Swiften/Network/UnixNetworkEnvironment.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/UnixNetworkEnvironment.h> + +#include <string> +#include <vector> +#include <map> +#include <boost/optional.hpp> +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <ifaddrs.h> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/NetworkInterface.h> + +namespace Swift { + +std::vector<NetworkInterface> UnixNetworkEnvironment::getNetworkInterfaces() const { + std::map<std::string, NetworkInterface> interfaces; + + ifaddrs* addrs = 0; + int ret = getifaddrs(&addrs); + if (ret != 0) { + return std::vector<NetworkInterface>(); + } + + for (ifaddrs* a = addrs; a != 0; a = a->ifa_next) { + std::string name(a->ifa_name); + boost::optional<HostAddress> address; + if (a->ifa_addr->sa_family == PF_INET) { + sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(a->ifa_addr); + address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin_addr)), 4); + } + else if (a->ifa_addr->sa_family == PF_INET6) { + sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(a->ifa_addr); + address = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); + } + if (address) { + std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, a->ifa_flags & IFF_LOOPBACK))).first; + i->second.addAddress(*address); + } + } + + freeifaddrs(addrs); + + std::vector<NetworkInterface> result; + for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { + result.push_back(i->second); + } + return result; +} + +} diff --git a/Swiften/Network/UnixNetworkEnvironment.h b/Swiften/Network/UnixNetworkEnvironment.h new file mode 100644 index 0000000..8b51cae --- /dev/null +++ b/Swiften/Network/UnixNetworkEnvironment.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/Network/NetworkEnvironment.h> +#include <Swiften/Network/NetworkInterface.h> + +namespace Swift { + +class UnixNetworkEnvironment : public NetworkEnvironment { + public: + std::vector<NetworkInterface> getNetworkInterfaces() const; +}; + +} diff --git a/Swiften/Network/UnixProxyProvider.cpp b/Swiften/Network/UnixProxyProvider.cpp new file mode 100644 index 0000000..4ca9311 --- /dev/null +++ b/Swiften/Network/UnixProxyProvider.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <iostream> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/UnixProxyProvider.h> +#if defined(HAVE_GCONF) +# include "Swiften/Network/GConfProxyProvider.h" +#endif + +namespace Swift { + +UnixProxyProvider::UnixProxyProvider() : + gconfProxyProvider(0), + environmentProxyProvider() +{ +#if defined(HAVE_GCONF) + gconfProxyProvider = new GConfProxyProvider(); +#endif +} + +UnixProxyProvider::~UnixProxyProvider() { +#if defined(HAVE_GCONF) + delete gconfProxyProvider; +#endif +} + +HostAddressPort UnixProxyProvider::getSOCKS5Proxy() const { + HostAddressPort proxy; +#if defined(HAVE_GCONF) + proxy = gconfProxyProvider->getSOCKS5Proxy(); + if(proxy.isValid()) { + return proxy; + } +#endif + proxy = environmentProxyProvider.getSOCKS5Proxy(); + if(proxy.isValid()) { + return proxy; + } + return HostAddressPort(HostAddress(), 0); +} + +HostAddressPort UnixProxyProvider::getHTTPConnectProxy() const { + HostAddressPort proxy; +#if defined(HAVE_GCONF) + proxy = gconfProxyProvider->getHTTPConnectProxy(); + if(proxy.isValid()) { + return proxy; + } +#endif + proxy = environmentProxyProvider.getHTTPConnectProxy(); + if(proxy.isValid()) { + return proxy; + } + return HostAddressPort(HostAddress(), 0); +} + + +} diff --git a/Swiften/Network/UnixProxyProvider.h b/Swiften/Network/UnixProxyProvider.h new file mode 100644 index 0000000..37a4d05 --- /dev/null +++ b/Swiften/Network/UnixProxyProvider.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Network/EnvironmentProxyProvider.h> + +namespace Swift { + class GConfProxyProvider; + + class UnixProxyProvider : public ProxyProvider { + public: + UnixProxyProvider(); + ~UnixProxyProvider(); + + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + + private: + GConfProxyProvider* gconfProxyProvider; + EnvironmentProxyProvider environmentProxyProvider; + }; +} diff --git a/Swiften/Network/WindowsNetworkEnvironment.cpp b/Swiften/Network/WindowsNetworkEnvironment.cpp new file mode 100644 index 0000000..20f559d --- /dev/null +++ b/Swiften/Network/WindowsNetworkEnvironment.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Network/WindowsNetworkEnvironment.h> + +#include <string> +#include <vector> +#include <map> +#include <boost/optional.hpp> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/NetworkInterface.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/ByteArray.h> + +#include <winsock2.h> +#include <iphlpapi.h> + +namespace Swift { + +std::vector<NetworkInterface> WindowsNetworkEnvironment::getNetworkInterfaces() const { + std::vector<NetworkInterface> result; + + ByteArray adapters; + ULONG bufferSize = 0; + ULONG ret; + ULONG flags = GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; + while ((ret = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, reinterpret_cast<IP_ADAPTER_ADDRESSES*>(vecptr(adapters)), &bufferSize)) == ERROR_BUFFER_OVERFLOW) { + adapters.resize(bufferSize); + }; + if (ret != ERROR_SUCCESS) { + return result; + } + + std::map<std::string,NetworkInterface> interfaces; + for (IP_ADAPTER_ADDRESSES* adapter = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(vecptr(adapters)); adapter; adapter = adapter->Next) { + std::string name(adapter->AdapterName); + if (adapter->OperStatus != IfOperStatusUp) { + continue; + } + for (IP_ADAPTER_UNICAST_ADDRESS* address = adapter->FirstUnicastAddress; address; address = address->Next) { + boost::optional<HostAddress> hostAddress; + if (address->Address.lpSockaddr->sa_family == PF_INET) { + sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(address->Address.lpSockaddr); + hostAddress = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin_addr)), 4); + } + else if (address->Address.lpSockaddr->sa_family == PF_INET6) { + sockaddr_in6* sa = reinterpret_cast<sockaddr_in6*>(address->Address.lpSockaddr); + hostAddress = HostAddress(reinterpret_cast<const unsigned char*>(&(sa->sin6_addr)), 16); + } + if (hostAddress) { + std::map<std::string, NetworkInterface>::iterator i = interfaces.insert(std::make_pair(name, NetworkInterface(name, false))).first; + i->second.addAddress(*hostAddress); + } + } + } + + for (std::map<std::string,NetworkInterface>::const_iterator i = interfaces.begin(); i != interfaces.end(); ++i) { + result.push_back(i->second); + } + return result; +} + +} diff --git a/Swiften/Network/WindowsNetworkEnvironment.h b/Swiften/Network/WindowsNetworkEnvironment.h new file mode 100644 index 0000000..f43b951 --- /dev/null +++ b/Swiften/Network/WindowsNetworkEnvironment.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <vector> +#include <Swiften/Base/boost_bsignals.h> + +#include <Swiften/Network/NetworkEnvironment.h> + +namespace Swift { + class WindowsNetworkEnvironment : public NetworkEnvironment { + public: + std::vector<NetworkInterface> getNetworkInterfaces() const; + }; +} diff --git a/Swiften/Network/WindowsProxyProvider.cpp b/Swiften/Network/WindowsProxyProvider.cpp new file mode 100644 index 0000000..3ae43e0 --- /dev/null +++ b/Swiften/Network/WindowsProxyProvider.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <iostream> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/log.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Network/WindowsProxyProvider.h> +#include <Swiften/Base/ByteArray.h> + +#include <windows.h> + +namespace Swift { + +WindowsProxyProvider::WindowsProxyProvider() +: ProxyProvider() +{ + HKEY hKey = (HKEY)INVALID_HANDLE_VALUE; + long result; + + result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", 0, KEY_READ, &hKey); + if (result == ERROR_SUCCESS && hKey != INVALID_HANDLE_VALUE && proxyEnabled(hKey)) { + DWORD dataType = REG_SZ; + DWORD dataSize = 0; + ByteArray dataBuffer; + + result = RegQueryValueEx(hKey, "ProxyServer", NULL, &dataType, NULL, &dataSize); + if(result != ERROR_SUCCESS) { + return; + } + dataBuffer.resize(dataSize); + result = RegQueryValueEx(hKey, "ProxyServer", NULL, &dataType, reinterpret_cast<BYTE*>(vecptr(dataBuffer)), &dataSize); + if(result == ERROR_SUCCESS) { + std::vector<std::string> proxies = String::split(byteArrayToString(dataBuffer), ';'); + std::pair<std::string, std::string> protocolAndProxy; + foreach(std::string proxy, proxies) { + if(proxy.find('=') != std::string::npos) { + protocolAndProxy = String::getSplittedAtFirst(proxy, '='); + SWIFT_LOG(debug) << "Found proxy: " << protocolAndProxy.first << " => " << protocolAndProxy.second << std::endl; + if(protocolAndProxy.first.compare("socks") == 0) { + socksProxy = getAsHostAddressPort(protocolAndProxy.second); + } + else if (protocolAndProxy.first.compare("http") == 0) { + httpProxy = getAsHostAddressPort(protocolAndProxy.second); + } + } + } + } + } +} + +HostAddressPort WindowsProxyProvider::getHTTPConnectProxy() const { + return httpProxy; +} + +HostAddressPort WindowsProxyProvider::getSOCKS5Proxy() const { + return socksProxy; +} + +HostAddressPort WindowsProxyProvider::getAsHostAddressPort(std::string proxy) { + HostAddressPort ret(HostAddress(), 0); + + try { + std::pair<std::string, std::string> tmp; + int port = 0; + tmp = String::getSplittedAtFirst(proxy, ':'); + // .c_str() is needed as tmp.second can include a \0 char which will end in an exception of the lexical cast. + // with .c_str() the \0 will not be part of the string which is to be casted + port = boost::lexical_cast<int> (tmp.second.c_str()); + ret = HostAddressPort(HostAddress(tmp.first), port); + } + catch(...) { + std::cerr << "Exception occured while parsing windows proxy \"getHostAddressPort\"." << std::endl; + } + + return ret; +} + + +bool WindowsProxyProvider::proxyEnabled(HKEY hKey) const { + bool ret = false; + long result; + DWORD dataType = REG_DWORD; + DWORD dataSize = 0; + DWORD data = 0; + ByteArray dataBuffer; + + if(hKey == INVALID_HANDLE_VALUE) + return ret; + + result = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dataType, NULL, &dataSize); + if(result != ERROR_SUCCESS) + return ret; + + dataBuffer.resize(dataSize); + result = RegQueryValueEx(hKey, "ProxyEnable", NULL, &dataType, reinterpret_cast<BYTE*>(vecptr(dataBuffer)), &dataSize); + if(result != ERROR_SUCCESS) + return ret; + + for(size_t t = 0; t < dataBuffer.size(); t++) { + data += static_cast<int> (dataBuffer[t]) * pow(256, static_cast<double>(t)); + } + return (data == 1); +} + +} diff --git a/Swiften/Network/WindowsProxyProvider.h b/Swiften/Network/WindowsProxyProvider.h new file mode 100644 index 0000000..c2d1f51 --- /dev/null +++ b/Swiften/Network/WindowsProxyProvider.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010-2011 Thilo Cestonaro + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once +#include <Swiften/Network/ProxyProvider.h> + +namespace Swift { + class WindowsProxyProvider : public ProxyProvider { + public: + WindowsProxyProvider(); + virtual HostAddressPort getHTTPConnectProxy() const; + virtual HostAddressPort getSOCKS5Proxy() const; + private: + HostAddressPort getAsHostAddressPort(std::string proxy); + bool proxyEnabled(HKEY hKey) const; + HostAddressPort socksProxy; + HostAddressPort httpProxy; + }; +} diff --git a/Swiften/Parser/Attribute.h b/Swiften/Parser/Attribute.h new file mode 100644 index 0000000..f1f9a83 --- /dev/null +++ b/Swiften/Parser/Attribute.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> + +namespace Swift { + class Attribute { + public: + Attribute(const std::string& name, const std::string& ns) : name(name), ns(ns) { + } + + const std::string& getName() const { + return name; + } + + const std::string& getNamespace() const { + return ns; + } + + bool operator==(const Attribute& o) const { + return o.name == name && o.ns == ns; + } + + private: + std::string name; + std::string ns; + }; +} diff --git a/Swiften/Parser/AttributeMap.cpp b/Swiften/Parser/AttributeMap.cpp new file mode 100644 index 0000000..1aeaf99 --- /dev/null +++ b/Swiften/Parser/AttributeMap.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/AttributeMap.h> + +#include <algorithm> +#include <boost/optional.hpp> + +using namespace Swift; + +namespace { + struct AttributeIs { + AttributeIs(const Attribute& attribute) : attribute(attribute) { + } + + bool operator()(const AttributeMap::Entry& o) const { + return o.getAttribute() == attribute; + } + + Attribute attribute; + }; +} + +AttributeMap::AttributeMap() { +} + +std::string AttributeMap::getAttribute(const std::string& attribute, const std::string& ns) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ns))); + if (i == attributes.end()) { + return ""; + } + else { + return i->getValue(); + } +} + +bool AttributeMap::getBoolAttribute(const std::string& attribute, bool defaultValue) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + if (i == attributes.end()) { + return defaultValue; + } + else { + return i->getValue() == "true" || i->getValue() == "1"; + } +} + +boost::optional<std::string> AttributeMap::getAttributeValue(const std::string& attribute) const { + AttributeValueMap::const_iterator i = std::find_if(attributes.begin(), attributes.end(), AttributeIs(Attribute(attribute, ""))); + if (i == attributes.end()) { + return boost::optional<std::string>(); + } + else { + return i->getValue(); + } +} + +void AttributeMap::addAttribute(const std::string& name, const std::string& ns, const std::string& value) { + attributes.push_back(Entry(Attribute(name, ns), value)); +} diff --git a/Swiften/Parser/AttributeMap.h b/Swiften/Parser/AttributeMap.h index c8b287b..31df606 100644 --- a/Swiften/Parser/AttributeMap.h +++ b/Swiften/Parser/AttributeMap.h @@ -4,38 +4,50 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef ATTRIBUTEMAP_H -#define ATTRIBUTEMAP_H +#pragma once +#include <vector> +#include <string> #include <map> +#include <boost/optional/optional_fwd.hpp> -#include <string> +#include <Swiften/Parser/Attribute.h> namespace Swift { - class AttributeMap : public std::map<std::string,std::string> { + class AttributeMap { public: - AttributeMap() {} - - std::string getAttribute(const std::string& attribute) const { - AttributeMap::const_iterator i = find(attribute); - if (i == end()) { - return ""; - } - else { - return i->second; - } - } + class Entry { + public: + Entry(const Attribute& attribute, const std::string& value) : attribute(attribute), value(value) { + } + + const Attribute& getAttribute() const { + return attribute; + } + + const std::string& getValue() const { + return value; + } + + private: + Attribute attribute; + std::string value; + }; - bool getBoolAttribute(const std::string& attribute, bool defaultValue = false) const { - AttributeMap::const_iterator i = find(attribute); - if (i == end()) { - return defaultValue; - } - else { - return i->second == "true" || i->second == "1"; - } + AttributeMap(); + + std::string getAttribute(const std::string& attribute, const std::string& ns = "") const; + bool getBoolAttribute(const std::string& attribute, bool defaultValue = false) const; + boost::optional<std::string> getAttributeValue(const std::string&) const; + + void addAttribute(const std::string& name, const std::string& ns, const std::string& value); + + const std::vector<Entry>& getEntries() const { + return attributes; } + + private: + typedef std::vector<Entry> AttributeValueMap; + AttributeValueMap attributes; }; } - -#endif diff --git a/Swiften/Parser/AuthChallengeParser.cpp b/Swiften/Parser/AuthChallengeParser.cpp index 1e5e0c4..7cb665a 100644 --- a/Swiften/Parser/AuthChallengeParser.cpp +++ b/Swiften/Parser/AuthChallengeParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/AuthChallengeParser.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Parser/AuthChallengeParser.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { diff --git a/Swiften/Parser/AuthChallengeParser.h b/Swiften/Parser/AuthChallengeParser.h index 39f7c57..31b6d89 100644 --- a/Swiften/Parser/AuthChallengeParser.h +++ b/Swiften/Parser/AuthChallengeParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/AuthChallenge.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/AuthChallenge.h> #include <string> namespace Swift { diff --git a/Swiften/Parser/AuthFailureParser.h b/Swiften/Parser/AuthFailureParser.h index af54794..1a71ea4 100644 --- a/Swiften/Parser/AuthFailureParser.h +++ b/Swiften/Parser/AuthFailureParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_AuthFailureParser_H -#define SWIFTEN_AuthFailureParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/AuthFailure.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/AuthFailure.h> namespace Swift { class AuthFailureParser : public GenericElementParser<AuthFailure> { @@ -16,5 +15,3 @@ namespace Swift { AuthFailureParser() : GenericElementParser<AuthFailure>() {} }; } - -#endif diff --git a/Swiften/Parser/AuthRequestParser.cpp b/Swiften/Parser/AuthRequestParser.cpp index 38af047..04d9e4f 100644 --- a/Swiften/Parser/AuthRequestParser.cpp +++ b/Swiften/Parser/AuthRequestParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/AuthRequestParser.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Parser/AuthRequestParser.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { @@ -22,7 +22,7 @@ void AuthRequestParser::handleStartElement(const std::string&, const std::string void AuthRequestParser::handleEndElement(const std::string&, const std::string&) { --depth_; if (depth_ == 0) { - getElementGeneric()->setMessage(Base64::decode(text_)); + getElementGeneric()->setMessage(createSafeByteArray(Base64::decode(text_))); } } diff --git a/Swiften/Parser/AuthRequestParser.h b/Swiften/Parser/AuthRequestParser.h index 5cc3694..1562df7 100644 --- a/Swiften/Parser/AuthRequestParser.h +++ b/Swiften/Parser/AuthRequestParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_AuthRequestParser_H -#define SWIFTEN_AuthRequestParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/AuthRequest.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/AuthRequest.h> #include <string> namespace Swift { @@ -25,5 +24,3 @@ namespace Swift { int depth_; }; } - -#endif diff --git a/Swiften/Parser/AuthResponseParser.cpp b/Swiften/Parser/AuthResponseParser.cpp index 0db6a2a..7f9a530 100644 --- a/Swiften/Parser/AuthResponseParser.cpp +++ b/Swiften/Parser/AuthResponseParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/AuthResponseParser.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Parser/AuthResponseParser.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { @@ -19,7 +19,7 @@ void AuthResponseParser::handleStartElement(const std::string&, const std::strin void AuthResponseParser::handleEndElement(const std::string&, const std::string&) { --depth; if (depth == 0) { - getElementGeneric()->setValue(Base64::decode(text)); + getElementGeneric()->setValue(createSafeByteArray(Base64::decode(text))); } } diff --git a/Swiften/Parser/AuthResponseParser.h b/Swiften/Parser/AuthResponseParser.h index aee2f9c..3dc2282 100644 --- a/Swiften/Parser/AuthResponseParser.h +++ b/Swiften/Parser/AuthResponseParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/AuthResponse.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/AuthResponse.h> #include <string> namespace Swift { diff --git a/Swiften/Parser/AuthSuccessParser.cpp b/Swiften/Parser/AuthSuccessParser.cpp index 0dee6ad..50246a4 100644 --- a/Swiften/Parser/AuthSuccessParser.cpp +++ b/Swiften/Parser/AuthSuccessParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/AuthSuccessParser.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Parser/AuthSuccessParser.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { diff --git a/Swiften/Parser/AuthSuccessParser.h b/Swiften/Parser/AuthSuccessParser.h index 30c89d2..b726b95 100644 --- a/Swiften/Parser/AuthSuccessParser.h +++ b/Swiften/Parser/AuthSuccessParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/AuthSuccess.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/AuthSuccess.h> #include <string> namespace Swift { diff --git a/Swiften/Parser/ComponentHandshakeParser.cpp b/Swiften/Parser/ComponentHandshakeParser.cpp index 4117a56..c58caf0 100644 --- a/Swiften/Parser/ComponentHandshakeParser.cpp +++ b/Swiften/Parser/ComponentHandshakeParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/ComponentHandshakeParser.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Parser/ComponentHandshakeParser.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { diff --git a/Swiften/Parser/ComponentHandshakeParser.h b/Swiften/Parser/ComponentHandshakeParser.h index 389bb6d..25cee6e 100644 --- a/Swiften/Parser/ComponentHandshakeParser.h +++ b/Swiften/Parser/ComponentHandshakeParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/ComponentHandshake.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/ComponentHandshake.h> #include <string> namespace Swift { diff --git a/Swiften/Parser/CompressFailureParser.h b/Swiften/Parser/CompressFailureParser.h index 7983a04..ed59324 100644 --- a/Swiften/Parser/CompressFailureParser.h +++ b/Swiften/Parser/CompressFailureParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_CompressFailureParser_H -#define SWIFTEN_CompressFailureParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/CompressFailure.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/CompressFailure.h> namespace Swift { class CompressFailureParser : public GenericElementParser<CompressFailure> { @@ -16,5 +15,3 @@ namespace Swift { CompressFailureParser() : GenericElementParser<CompressFailure>() {} }; } - -#endif diff --git a/Swiften/Parser/CompressParser.cpp b/Swiften/Parser/CompressParser.cpp index 5ce5204..d8f773b 100644 --- a/Swiften/Parser/CompressParser.cpp +++ b/Swiften/Parser/CompressParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/CompressParser.h" +#include <Swiften/Parser/CompressParser.h> namespace Swift { diff --git a/Swiften/Parser/CompressParser.h b/Swiften/Parser/CompressParser.h index 54257b6..51244c4 100644 --- a/Swiften/Parser/CompressParser.h +++ b/Swiften/Parser/CompressParser.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_CompressParser_H -#define SWIFTEN_CompressParser_H +#pragma once #include <string> -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/CompressRequest.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/CompressRequest.h> namespace Swift { class CompressParser : public GenericElementParser<CompressRequest> { @@ -27,5 +26,3 @@ namespace Swift { bool inMethod_; }; } - -#endif diff --git a/Swiften/Parser/CompressedParser.h b/Swiften/Parser/CompressedParser.h index af1f063..5ba80eb 100644 --- a/Swiften/Parser/CompressedParser.h +++ b/Swiften/Parser/CompressedParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_COMPRESSEDPARSER_H -#define SWIFTEN_COMPRESSEDPARSER_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/Compressed.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/Compressed.h> namespace Swift { class CompressedParser : public GenericElementParser<Compressed> { @@ -16,5 +15,3 @@ namespace Swift { CompressedParser() : GenericElementParser<Compressed>() {} }; } - -#endif diff --git a/Swiften/Parser/ElementParser.cpp b/Swiften/Parser/ElementParser.cpp index f669a01..1064f2e 100644 --- a/Swiften/Parser/ElementParser.cpp +++ b/Swiften/Parser/ElementParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/ElementParser.h" +#include <Swiften/Parser/ElementParser.h> namespace Swift { diff --git a/Swiften/Parser/ElementParser.h b/Swiften/Parser/ElementParser.h index 60f2395..a11b505 100644 --- a/Swiften/Parser/ElementParser.h +++ b/Swiften/Parser/ElementParser.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ElementParser_H -#define SWIFTEN_ElementParser_H +#pragma once #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Elements/Element.h" -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/Parser/AttributeMap.h> namespace Swift { class ElementParser { @@ -25,5 +24,3 @@ namespace Swift { virtual boost::shared_ptr<Element> getElement() const = 0; }; } - -#endif diff --git a/Swiften/Parser/EnableStreamManagementParser.h b/Swiften/Parser/EnableStreamManagementParser.h index bd86420..530efd9 100644 --- a/Swiften/Parser/EnableStreamManagementParser.h +++ b/Swiften/Parser/EnableStreamManagementParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/EnableStreamManagement.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/EnableStreamManagement.h> namespace Swift { class EnableStreamManagementParser : public GenericElementParser<EnableStreamManagement> { diff --git a/Swiften/Parser/ExpatParser.cpp b/Swiften/Parser/ExpatParser.cpp index f091f79..f3b5250 100644 --- a/Swiften/Parser/ExpatParser.cpp +++ b/Swiften/Parser/ExpatParser.cpp @@ -4,13 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/ExpatParser.h" +#include <Swiften/Parser/ExpatParser.h> #include <iostream> #include <string> #include <Swiften/Base/String.h> -#include "Swiften/Parser/XMLParserClient.h" +#include <Swiften/Parser/XMLParserClient.h> namespace Swift { @@ -30,7 +30,7 @@ static void handleStartElement(void* parser, const XML_Char* name, const XML_Cha nsAttributePair.second = nsAttributePair.first; nsAttributePair.first = ""; } - attributeValues[nsAttributePair.second] = std::string(*(currentAttribute+1)); + attributeValues.addAttribute(nsAttributePair.second, nsAttributePair.first, std::string(*(currentAttribute+1))); currentAttribute += 2; } diff --git a/Swiften/Parser/ExpatParser.h b/Swiften/Parser/ExpatParser.h index cd981ef..359f786 100644 --- a/Swiften/Parser/ExpatParser.h +++ b/Swiften/Parser/ExpatParser.h @@ -4,13 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ExpatParser_H -#define SWIFTEN_ExpatParser_H +#pragma once #include <expat.h> #include <boost/noncopyable.hpp> -#include "Swiften/Parser/XMLParser.h" +#include <Swiften/Parser/XMLParser.h> namespace Swift { class ExpatParser : public XMLParser, public boost::noncopyable { @@ -28,5 +27,3 @@ namespace Swift { XML_Parser parser_; }; } - -#endif diff --git a/Swiften/Parser/GenericPayloadParserFactory.h b/Swiften/Parser/GenericPayloadParserFactory.h index 9b108a0..43042a1 100644 --- a/Swiften/Parser/GenericPayloadParserFactory.h +++ b/Swiften/Parser/GenericPayloadParserFactory.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Parser/PayloadParserFactory.h" +#include <Swiften/Parser/PayloadParserFactory.h> #include <string> namespace Swift { diff --git a/Swiften/Parser/GenericPayloadTreeParser.h b/Swiften/Parser/GenericPayloadTreeParser.h new file mode 100644 index 0000000..df6d022 --- /dev/null +++ b/Swiften/Parser/GenericPayloadTreeParser.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <deque> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/Tree/ParserElement.h> + +namespace Swift { + /** + * Generic parser offering something a bit like a DOM to work with. + */ + template<typename PAYLOAD_TYPE> + class GenericPayloadTreeParser : public GenericPayloadParser<PAYLOAD_TYPE> { + public: + virtual void handleStartElement(const std::string& element, const std::string& xmlns, const AttributeMap& attributes) { + if (!root_) { + root_ = boost::make_shared<ParserElement>(element, xmlns, attributes); + elementStack_.push_back(root_); + } + else { + ParserElement::ref current = *elementStack_.rbegin(); + elementStack_.push_back(current->addChild(element, xmlns, attributes)); + } + } + + virtual void handleEndElement(const std::string& /*element*/, const std::string&) { + elementStack_.pop_back(); + if (elementStack_.empty()) { + handleTree(root_); + } + } + + virtual void handleCharacterData(const std::string& data) { + ParserElement::ref current = *elementStack_.rbegin(); + current->appendCharacterData(data); + } + + virtual void handleTree(ParserElement::ref root) = 0; + + private: + std::deque<ParserElement::ref> elementStack_; + ParserElement::ref root_; + }; +} diff --git a/Swiften/Parser/IQParser.cpp b/Swiften/Parser/IQParser.cpp index e0883f2..62d775f 100644 --- a/Swiften/Parser/IQParser.cpp +++ b/Swiften/Parser/IQParser.cpp @@ -5,8 +5,9 @@ */ #include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/IQParser.h" +#include <Swiften/Parser/IQParser.h> namespace Swift { @@ -15,22 +16,22 @@ IQParser::IQParser(PayloadParserFactoryCollection* factories) : } void IQParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "set") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "set") { getStanzaGeneric()->setType(IQ::Set); } - else if (type->second == "get") { + else if (*type == "get") { getStanzaGeneric()->setType(IQ::Get); } - else if (type->second == "result") { + else if (*type == "result") { getStanzaGeneric()->setType(IQ::Result); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(IQ::Error); } else { - std::cerr << "Unknown IQ type: " << type->second << std::endl; + std::cerr << "Unknown IQ type: " << *type << std::endl; getStanzaGeneric()->setType(IQ::Get); } } diff --git a/Swiften/Parser/IQParser.h b/Swiften/Parser/IQParser.h index e104dc4..a7aa967 100644 --- a/Swiften/Parser/IQParser.h +++ b/Swiften/Parser/IQParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IQParser_H -#define SWIFTEN_IQParser_H +#pragma once -#include "Swiften/Parser/GenericStanzaParser.h" -#include "Swiften/Elements/IQ.h" +#include <Swiften/Parser/GenericStanzaParser.h> +#include <Swiften/Elements/IQ.h> namespace Swift { class IQParser : public GenericStanzaParser<IQ> { @@ -19,5 +18,3 @@ namespace Swift { virtual void handleStanzaAttributes(const AttributeMap&); }; } - -#endif diff --git a/Swiften/Parser/LibXMLParser.cpp b/Swiften/Parser/LibXMLParser.cpp index c94a360..ae87f38 100644 --- a/Swiften/Parser/LibXMLParser.cpp +++ b/Swiften/Parser/LibXMLParser.cpp @@ -4,21 +4,29 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/LibXMLParser.h" +#include <Swiften/Parser/LibXMLParser.h> #include <iostream> #include <cassert> #include <cstring> #include <string> -#include "Swiften/Parser/XMLParserClient.h" +#include <Swiften/Parser/XMLParserClient.h> namespace Swift { -static void handleStartElement(void *parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int, const xmlChar ** attributes) { +static void handleStartElement(void* parser, const xmlChar* name, const xmlChar*, const xmlChar* xmlns, int, const xmlChar**, int nbAttributes, int nbDefaulted, const xmlChar ** attributes) { AttributeMap attributeValues; + if (nbDefaulted != 0) { + // Just because i don't understand what this means yet :-) + std::cerr << "Unexpected nbDefaulted on XML element" << std::endl; + } for (int i = 0; i < nbAttributes*5; i += 5) { - attributeValues[std::string(reinterpret_cast<const char*>(attributes[i]))] = std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3]); + std::string attributeNS = ""; + if (attributes[i+2]) { + attributeNS = std::string(reinterpret_cast<const char*>(attributes[i+2])); + } + attributeValues.addAttribute(std::string(reinterpret_cast<const char*>(attributes[i])), attributeNS, std::string(reinterpret_cast<const char*>(attributes[i+3]), attributes[i+4]-attributes[i+3])); } static_cast<XMLParser*>(parser)->getClient()->handleStartElement(reinterpret_cast<const char*>(name), (xmlns ? reinterpret_cast<const char*>(xmlns) : std::string()), attributeValues); } diff --git a/Swiften/Parser/LibXMLParser.h b/Swiften/Parser/LibXMLParser.h index d0dac8b..ba61ad9 100644 --- a/Swiften/Parser/LibXMLParser.h +++ b/Swiften/Parser/LibXMLParser.h @@ -9,7 +9,7 @@ #include <libxml/parser.h> #include <boost/noncopyable.hpp> -#include "Swiften/Parser/XMLParser.h" +#include <Swiften/Parser/XMLParser.h> namespace Swift { class LibXMLParser : public XMLParser, public boost::noncopyable { diff --git a/Swiften/Parser/MessageParser.cpp b/Swiften/Parser/MessageParser.cpp index 5f4d59c..7f5e6d4 100644 --- a/Swiften/Parser/MessageParser.cpp +++ b/Swiften/Parser/MessageParser.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/MessageParser.h" +#include <Swiften/Parser/MessageParser.h> namespace Swift { @@ -16,18 +16,18 @@ MessageParser::MessageParser(PayloadParserFactoryCollection* factories) : } void MessageParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "chat") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "chat") { getStanzaGeneric()->setType(Message::Chat); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(Message::Error); } - else if (type->second == "groupchat") { + else if (*type == "groupchat") { getStanzaGeneric()->setType(Message::Groupchat); } - else if (type->second == "headline") { + else if (*type == "headline") { getStanzaGeneric()->setType(Message::Headline); } else { diff --git a/Swiften/Parser/MessageParser.h b/Swiften/Parser/MessageParser.h index 70def0a..a8aaa99 100644 --- a/Swiften/Parser/MessageParser.h +++ b/Swiften/Parser/MessageParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_MESSAGEPARSER_H -#define SWIFTEN_MESSAGEPARSER_H +#pragma once -#include "Swiften/Parser/GenericStanzaParser.h" -#include "Swiften/Elements/Message.h" +#include <Swiften/Parser/GenericStanzaParser.h> +#include <Swiften/Elements/Message.h> namespace Swift { class MessageParser : public GenericStanzaParser<Message> { @@ -19,5 +18,3 @@ namespace Swift { virtual void handleStanzaAttributes(const AttributeMap&); }; } - -#endif diff --git a/Swiften/Parser/PayloadParser.cpp b/Swiften/Parser/PayloadParser.cpp index 42d36e0..3680d63 100644 --- a/Swiften/Parser/PayloadParser.cpp +++ b/Swiften/Parser/PayloadParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParser.h" +#include <Swiften/Parser/PayloadParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParser.h b/Swiften/Parser/PayloadParser.h index 423a2bb..8a9a290 100644 --- a/Swiften/Parser/PayloadParser.h +++ b/Swiften/Parser/PayloadParser.h @@ -7,9 +7,9 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Parser/AttributeMap.h> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { @@ -44,6 +44,6 @@ namespace Swift { /** * Retrieve a pointer to the payload. */ - virtual Payload::ref getPayload() const = 0; + virtual boost::shared_ptr<Payload> getPayload() const = 0; }; } diff --git a/Swiften/Parser/PayloadParserFactory.cpp b/Swiften/Parser/PayloadParserFactory.cpp index 29501d6..4dac217 100644 --- a/Swiften/Parser/PayloadParserFactory.cpp +++ b/Swiften/Parser/PayloadParserFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParserFactory.h" +#include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParserFactory.h b/Swiften/Parser/PayloadParserFactory.h index 2baa2ad..5619d21 100644 --- a/Swiften/Parser/PayloadParserFactory.h +++ b/Swiften/Parser/PayloadParserFactory.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Parser/AttributeMap.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParserFactoryCollection.cpp index 0080fbe..e3efc3d 100644 --- a/Swiften/Parser/PayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParserFactoryCollection.cpp @@ -7,8 +7,8 @@ #include <boost/bind.hpp> #include <algorithm> -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/PayloadParserFactory.h" +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParserFactoryCollection.h b/Swiften/Parser/PayloadParserFactoryCollection.h index 9afb9b7..6407641 100644 --- a/Swiften/Parser/PayloadParserFactoryCollection.h +++ b/Swiften/Parser/PayloadParserFactoryCollection.h @@ -4,16 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PAYLOADPARSERFACTORYCOLLECTION_H -#define SWIFTEN_PAYLOADPARSERFACTORYCOLLECTION_H +#pragma once #include <vector> -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Parser/AttributeMap.h> namespace Swift { class PayloadParserFactory; - class PayloadParserFactoryCollection { public: @@ -30,5 +28,3 @@ namespace Swift { PayloadParserFactory* defaultFactory_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/BlockParser.h b/Swiften/Parser/PayloadParsers/BlockParser.h new file mode 100644 index 0000000..cd727ad --- /dev/null +++ b/Swiften/Parser/PayloadParsers/BlockParser.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Nickname.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + template<typename BLOCK_ELEMENT> + class BlockParser : public GenericPayloadParser<BLOCK_ELEMENT> { + public: + BlockParser() : GenericPayloadParser<BLOCK_ELEMENT>() { + } + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (level == 1 && element == "item") { + JID jid(attributes.getAttribute("jid")); + if (jid.isValid()) { + GenericPayloadParser<BLOCK_ELEMENT>::getPayloadInternal()->addItem(jid); + } + } + ++level; + } + + virtual void handleEndElement(const std::string&, const std::string&) { + --level; + } + + virtual void handleCharacterData(const std::string&) { + } + + private: + int level; + }; +} diff --git a/Swiften/Parser/PayloadParsers/BodyParser.cpp b/Swiften/Parser/PayloadParsers/BodyParser.cpp index d0f4e09..ac8bdd5 100644 --- a/Swiften/Parser/PayloadParsers/BodyParser.cpp +++ b/Swiften/Parser/PayloadParsers/BodyParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/BodyParser.h" +#include <Swiften/Parser/PayloadParsers/BodyParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/BodyParser.h b/Swiften/Parser/PayloadParsers/BodyParser.h index f9e17e0..f571370 100644 --- a/Swiften/Parser/PayloadParsers/BodyParser.h +++ b/Swiften/Parser/PayloadParsers/BodyParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_BodyParser_H -#define SWIFTEN_BodyParser_H +#pragma once -#include "Swiften/Elements/Body.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Body.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class BodyParser : public GenericPayloadParser<Body> { @@ -24,5 +23,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp index 35db9ec..fddc1c7 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/BytestreamsParser.h" +#include <Swiften/Parser/PayloadParsers/BytestreamsParser.h> #include <boost/lexical_cast.hpp> -#include "Swiften/Base/foreach.h" +#include <Swiften/Base/foreach.h> namespace Swift { @@ -27,7 +27,7 @@ void BytestreamsParser::handleStartElement(const std::string& element, const std try { getPayloadInternal()->addStreamHost(Bytestreams::StreamHost(attributes.getAttribute("host"), JID(attributes.getAttribute("jid")), boost::lexical_cast<int>(attributes.getAttribute("port")))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "streamhost-used") { diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParser.h b/Swiften/Parser/PayloadParsers/BytestreamsParser.h index 2d67785..4785913 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParser.h +++ b/Swiften/Parser/PayloadParsers/BytestreamsParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/Bytestreams.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Bytestreams.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class BytestreamsParser : public GenericPayloadParser<Bytestreams> { diff --git a/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h b/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h index 8defd45..06ebc4d 100644 --- a/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h +++ b/Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/BytestreamsParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/BytestreamsParser.h> namespace Swift { class BytestreamsParserFactory : public GenericPayloadParserFactory<BytestreamsParser> { diff --git a/Swiften/Parser/PayloadParsers/CapsInfoParser.cpp b/Swiften/Parser/PayloadParsers/CapsInfoParser.cpp index d7d9324..770d98b 100644 --- a/Swiften/Parser/PayloadParsers/CapsInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/CapsInfoParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/CapsInfoParser.h" +#include <Swiften/Parser/PayloadParsers/CapsInfoParser.h> #include <locale> diff --git a/Swiften/Parser/PayloadParsers/CapsInfoParser.h b/Swiften/Parser/PayloadParsers/CapsInfoParser.h index 590326d..96aa734 100644 --- a/Swiften/Parser/PayloadParsers/CapsInfoParser.h +++ b/Swiften/Parser/PayloadParsers/CapsInfoParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/CapsInfo.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/CapsInfo.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class CapsInfoParser : public GenericPayloadParser<CapsInfo> { diff --git a/Swiften/Parser/PayloadParsers/ChatStateParser.cpp b/Swiften/Parser/PayloadParsers/ChatStateParser.cpp index 3a5ba3b..a85dcf7 100644 --- a/Swiften/Parser/PayloadParsers/ChatStateParser.cpp +++ b/Swiften/Parser/PayloadParsers/ChatStateParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/ChatStateParser.h" +#include <Swiften/Parser/PayloadParsers/ChatStateParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/ChatStateParser.h b/Swiften/Parser/PayloadParsers/ChatStateParser.h index 8d0e7f5..4363d6b 100644 --- a/Swiften/Parser/PayloadParsers/ChatStateParser.h +++ b/Swiften/Parser/PayloadParsers/ChatStateParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/ChatState.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/ChatState.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class ChatStateParser : public GenericPayloadParser<ChatState> { diff --git a/Swiften/Parser/PayloadParsers/ChatStateParserFactory.h b/Swiften/Parser/PayloadParsers/ChatStateParserFactory.h index 3dadda7..80d76c4 100644 --- a/Swiften/Parser/PayloadParsers/ChatStateParserFactory.h +++ b/Swiften/Parser/PayloadParsers/ChatStateParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/ChatStateParser.h" +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/ChatStateParser.h> namespace Swift { class PayloadParserFactoryCollection; diff --git a/Swiften/Parser/PayloadParsers/CommandParser.cpp b/Swiften/Parser/PayloadParsers/CommandParser.cpp index 3ebab39..1af4074 100644 --- a/Swiften/Parser/PayloadParsers/CommandParser.cpp +++ b/Swiften/Parser/PayloadParsers/CommandParser.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/CommandParser.h" +#include <Swiften/Parser/PayloadParsers/CommandParser.h> #include <boost/cast.hpp> -#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" -#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include <Swiften/Parser/PayloadParsers/FormParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/CommandParser.h b/Swiften/Parser/PayloadParsers/CommandParser.h index 0415ba6..80cffc4 100644 --- a/Swiften/Parser/PayloadParsers/CommandParser.h +++ b/Swiften/Parser/PayloadParsers/CommandParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/Command.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Command.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class FormParserFactory; diff --git a/Swiften/Parser/PayloadParsers/CommandParserFactory.h b/Swiften/Parser/PayloadParsers/CommandParserFactory.h index 9eaaf62..47d3333 100644 --- a/Swiften/Parser/PayloadParsers/CommandParserFactory.h +++ b/Swiften/Parser/PayloadParsers/CommandParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/CommandParser.h" +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/CommandParser.h> namespace Swift { class PayloadParserFactoryCollection; diff --git a/Swiften/Parser/PayloadParsers/DelayParser.cpp b/Swiften/Parser/PayloadParsers/DelayParser.cpp index 3425b84..e18d09d 100644 --- a/Swiften/Parser/PayloadParsers/DelayParser.cpp +++ b/Swiften/Parser/PayloadParsers/DelayParser.cpp @@ -4,28 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/DelayParser.h" +#include <Swiften/Parser/PayloadParsers/DelayParser.h> -#include <locale> - -#include <boost/date_time/time_facet.hpp> +#include <Swiften/Base/DateTime.h> namespace Swift { -DelayParser::DelayParser(const std::locale& locale) : locale(locale), level_(0) { -} - -boost::posix_time::ptime DelayParser::dateFromString(const std::string& string) { - std::istringstream stream(string); - stream.imbue(locale); - boost::posix_time::ptime result(boost::posix_time::not_a_date_time); - stream >> result; - return result; +DelayParser::DelayParser() : level_(0) { } void DelayParser::handleStartElement(const std::string& /*element*/, const std::string& /*ns*/, const AttributeMap& attributes) { if (level_ == 0) { - boost::posix_time::ptime stamp = dateFromString(attributes.getAttribute("stamp")); + boost::posix_time::ptime stamp = stringToDateTime(attributes.getAttribute("stamp")); getPayloadInternal()->setStamp(stamp); if (!attributes.getAttribute("from").empty()) { std::string from = attributes.getAttribute("from"); diff --git a/Swiften/Parser/PayloadParsers/DelayParser.h b/Swiften/Parser/PayloadParsers/DelayParser.h index c2e2bb6..144220a 100644 --- a/Swiften/Parser/PayloadParsers/DelayParser.h +++ b/Swiften/Parser/PayloadParsers/DelayParser.h @@ -6,23 +6,19 @@ #pragma once -#include "Swiften/Elements/Delay.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Delay.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class DelayParser : public GenericPayloadParser<Delay> { public: - DelayParser(const std::locale& locale); + DelayParser(); virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); virtual void handleEndElement(const std::string& element, const std::string&); virtual void handleCharacterData(const std::string& data); private: - boost::posix_time::ptime dateFromString(const std::string& string); - - private: - std::locale locale; int level_; }; } diff --git a/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp b/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp deleted file mode 100644 index 19d0530..0000000 --- a/Swiften/Parser/PayloadParsers/DelayParserFactory.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include <Swiften/Parser/PayloadParsers/DelayParserFactory.h> - -#include <boost/date_time/time_facet.hpp> - -namespace Swift { - -DelayParserFactory::DelayParserFactory() { - boost::posix_time::time_input_facet* facet = new boost::posix_time::time_input_facet("%Y-%m-%d %H:%M:%S%F%Q"); - locale = std::locale(std::locale::classic(), facet); -} - -} diff --git a/Swiften/Parser/PayloadParsers/DelayParserFactory.h b/Swiften/Parser/PayloadParsers/DelayParserFactory.h deleted file mode 100644 index c150853..0000000 --- a/Swiften/Parser/PayloadParsers/DelayParserFactory.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/DelayParser.h" - -namespace Swift { - class PayloadParserFactoryCollection; - - class DelayParserFactory : public PayloadParserFactory { - public: - DelayParserFactory(); - - virtual bool canParse(const std::string& /*element*/, const std::string& ns, const AttributeMap&) const { - return ns == "urn:xmpp:delay"; - } - - virtual PayloadParser* createPayloadParser() { - return new DelayParser(locale); - } - - private: - std::locale locale; - }; -} diff --git a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp index e1fcb20..14ff79d 100644 --- a/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/DiscoInfoParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h" -#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include <Swiften/Parser/PayloadParsers/DiscoInfoParser.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> namespace Swift { @@ -15,7 +15,7 @@ DiscoInfoParser::DiscoInfoParser() : level_(TopLevel), formParser_(NULL) { void DiscoInfoParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { if (level_ == PayloadLevel) { if (element == "identity") { - getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang"))); + getPayloadInternal()->addIdentity(DiscoInfo::Identity(attributes.getAttribute("name"), attributes.getAttribute("category"), attributes.getAttribute("type"), attributes.getAttribute("lang", "http://www.w3.org/XML/1998/namespace"))); } else if (element == "feature") { getPayloadInternal()->addFeature(attributes.getAttribute("var")); diff --git a/Swiften/Parser/PayloadParsers/DiscoInfoParser.h b/Swiften/Parser/PayloadParsers/DiscoInfoParser.h index 24a1d6f..df1441c 100644 --- a/Swiften/Parser/PayloadParsers/DiscoInfoParser.h +++ b/Swiften/Parser/PayloadParsers/DiscoInfoParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class DiscoInfoParser : public GenericPayloadParser<DiscoInfo> { diff --git a/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp b/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp index 7ff375b..d6ac94d 100644 --- a/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp +++ b/Swiften/Parser/PayloadParsers/DiscoItemsParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/DiscoItemsParser.h" +#include <Swiften/Parser/PayloadParsers/DiscoItemsParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/DiscoItemsParser.h b/Swiften/Parser/PayloadParsers/DiscoItemsParser.h index 0700df6..ae799cb 100644 --- a/Swiften/Parser/PayloadParsers/DiscoItemsParser.h +++ b/Swiften/Parser/PayloadParsers/DiscoItemsParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/DiscoItems.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/DiscoItems.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class DiscoItemsParser : public GenericPayloadParser<DiscoItems> { diff --git a/Swiften/Parser/PayloadParsers/ErrorParser.cpp b/Swiften/Parser/PayloadParsers/ErrorParser.cpp index 4034cb5..8a02317 100644 --- a/Swiften/Parser/PayloadParsers/ErrorParser.cpp +++ b/Swiften/Parser/PayloadParsers/ErrorParser.cpp @@ -4,14 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/ErrorParser.h" +#include <Swiften/Parser/PayloadParsers/ErrorParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { -ErrorParser::ErrorParser() : level_(TopLevel) { +ErrorParser::ErrorParser(PayloadParserFactoryCollection* factories) : factories(factories), level_(TopLevel) { } -void ErrorParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { +void ErrorParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { if (level_ == TopLevel) { std::string type = attributes.getAttribute("type"); if (type == "continue") { @@ -30,14 +32,9 @@ void ErrorParser::handleStartElement(const std::string&, const std::string&, con getPayloadInternal()->setType(ErrorPayload::Cancel); } } - ++level_; -} - -void ErrorParser::handleEndElement(const std::string& element, const std::string&) { - --level_; - if (level_ == PayloadLevel) { + else if (level_ == PayloadLevel) { if (element == "text") { - getPayloadInternal()->setText(currentText_); + } else if (element == "bad-request") { getPayloadInternal()->setCondition(ErrorPayload::BadRequest); @@ -103,13 +100,46 @@ void ErrorParser::handleEndElement(const std::string& element, const std::string getPayloadInternal()->setCondition(ErrorPayload::UnexpectedRequest); } else { - getPayloadInternal()->setCondition(ErrorPayload::UndefinedCondition); + PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } else { + getPayloadInternal()->setCondition(ErrorPayload::UndefinedCondition); + } + } + } + if (level_ >= PayloadLevel && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level_; +} + +void ErrorParser::handleEndElement(const std::string& element, const std::string& ns) { + --level_; + if (currentPayloadParser) { + if (level_ >= PayloadLevel) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level_ == PayloadLevel) { + getPayloadInternal()->setPayload(currentPayloadParser->getPayload()); + currentPayloadParser.reset(); + } + } + else if (level_ == PayloadLevel) { + if (element == "text") { + getPayloadInternal()->setText(currentText_); } } } void ErrorParser::handleCharacterData(const std::string& data) { - currentText_ += data; + if (level_ > PayloadLevel && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } + else { + currentText_ += data; + } } } diff --git a/Swiften/Parser/PayloadParsers/ErrorParser.h b/Swiften/Parser/PayloadParsers/ErrorParser.h index 4318a8c..b2d05cf 100644 --- a/Swiften/Parser/PayloadParsers/ErrorParser.h +++ b/Swiften/Parser/PayloadParsers/ErrorParser.h @@ -4,16 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ErrorParser_H -#define SWIFTEN_ErrorParser_H +#pragma once -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { + class PayloadParserFactoryCollection; class ErrorParser : public GenericPayloadParser<ErrorPayload> { public: - ErrorParser(); + ErrorParser(PayloadParserFactoryCollection* factories); virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); virtual void handleEndElement(const std::string& element, const std::string&); @@ -24,9 +24,9 @@ namespace Swift { TopLevel = 0, PayloadLevel = 1 }; + PayloadParserFactoryCollection* factories; int level_; std::string currentText_; + boost::shared_ptr<PayloadParser> currentPayloadParser; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/ErrorParserFactory.h b/Swiften/Parser/PayloadParsers/ErrorParserFactory.h new file mode 100644 index 0000000..1463807 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ErrorParserFactory.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/ErrorParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class ErrorParserFactory : public PayloadParserFactory { + public: + ErrorParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& /*ns*/, const AttributeMap&) const { + return element == "error"; + } + + virtual PayloadParser* createPayloadParser() { + return new ErrorParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; + + }; +} diff --git a/Swiften/Parser/PayloadParsers/FormParser.cpp b/Swiften/Parser/PayloadParsers/FormParser.cpp index f8e02a4..3905302 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.cpp +++ b/Swiften/Parser/PayloadParsers/FormParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include <Swiften/Parser/PayloadParsers/FormParser.h> namespace Swift { @@ -63,12 +63,9 @@ void FormParser::handleStartElement(const std::string& element, const std::strin else if (type == "text-private") { currentFieldParseHelper_ = TextPrivateFormFieldParseHelper::create(); } - else if (type == "text-single") { + else /*if (type == "text-single") || undefined */ { currentFieldParseHelper_ = TextSingleFormFieldParseHelper::create(); } - else { - currentFieldParseHelper_ = UntypedFormFieldParseHelper::create(); - } if (currentFieldParseHelper_) { currentFieldParseHelper_->getField()->setName(attributes.getAttribute("var")); currentFieldParseHelper_->getField()->setLabel(attributes.getAttribute("label")); diff --git a/Swiften/Parser/PayloadParsers/FormParser.h b/Swiften/Parser/PayloadParsers/FormParser.h index 90a3550..eae40a1 100644 --- a/Swiften/Parser/PayloadParsers/FormParser.h +++ b/Swiften/Parser/PayloadParsers/FormParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/Form.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Form.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class FormParser : public GenericPayloadParser<Form> { @@ -96,7 +96,6 @@ namespace Swift { SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDSingle, JID); SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(JIDMulti, JIDList); SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(ListMulti, StringList); - SWIFTEN_DECLARE_FORM_FIELD_PARSE_HELPER(Untyped, StringList); enum Level { TopLevel = 0, diff --git a/Swiften/Parser/PayloadParsers/FormParserFactory.h b/Swiften/Parser/PayloadParsers/FormParserFactory.h index 7c095a7..9e1794a 100644 --- a/Swiften/Parser/PayloadParsers/FormParserFactory.h +++ b/Swiften/Parser/PayloadParsers/FormParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> namespace Swift { class PayloadParserFactoryCollection; diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index e20c06d..ebb0f3e 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -4,41 +4,66 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Parser/GenericPayloadParser.h" -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/ErrorParser.h" -#include "Swiften/Parser/PayloadParsers/BodyParser.h" -#include "Swiften/Parser/PayloadParsers/SubjectParser.h" -#include "Swiften/Parser/PayloadParsers/ChatStateParserFactory.h" -#include "Swiften/Parser/PayloadParsers/PriorityParser.h" -#include "Swiften/Parser/PayloadParsers/ResourceBindParser.h" -#include "Swiften/Parser/PayloadParsers/StartSessionParser.h" -#include "Swiften/Parser/PayloadParsers/StatusParser.h" -#include "Swiften/Parser/PayloadParsers/StatusShowParser.h" -#include "Swiften/Parser/PayloadParsers/RosterParser.h" -#include "Swiften/Parser/PayloadParsers/SoftwareVersionParser.h" -#include "Swiften/Parser/PayloadParsers/StorageParser.h" -#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h" -#include "Swiften/Parser/PayloadParsers/DiscoItemsParser.h" -#include "Swiften/Parser/PayloadParsers/CapsInfoParser.h" -#include "Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h" -#include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h" -#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" -#include "Swiften/Parser/PayloadParsers/CommandParserFactory.h" -#include "Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h" -#include "Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h" -#include "Swiften/Parser/PayloadParsers/IBBParser.h" -#include "Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h" -#include "Swiften/Parser/PayloadParsers/VCardParserFactory.h" -#include "Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h" -#include "Swiften/Parser/PayloadParsers/DelayParserFactory.h" -#include "Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/NicknameParserFactory.h" +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/BlockPayload.h> +#include <Swiften/Elements/UnblockPayload.h> +#include <Swiften/Elements/BlockListPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/ErrorParser.h> +#include <Swiften/Parser/PayloadParsers/ErrorParserFactory.h> +#include <Swiften/Parser/PayloadParsers/BodyParser.h> +#include <Swiften/Parser/PayloadParsers/BlockParser.h> +#include <Swiften/Parser/PayloadParsers/SubjectParser.h> +#include <Swiften/Parser/PayloadParsers/ChatStateParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PriorityParser.h> +#include <Swiften/Parser/PayloadParsers/ResourceBindParser.h> +#include <Swiften/Parser/PayloadParsers/StartSessionParser.h> +#include <Swiften/Parser/PayloadParsers/StatusParser.h> +#include <Swiften/Parser/PayloadParsers/StatusShowParser.h> +#include <Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h> +#include <Swiften/Parser/PayloadParsers/RosterParser.h> +#include <Swiften/Parser/PayloadParsers/SoftwareVersionParser.h> +#include <Swiften/Parser/PayloadParsers/StorageParser.h> +#include <Swiften/Parser/PayloadParsers/DiscoInfoParser.h> +#include <Swiften/Parser/PayloadParsers/DiscoItemsParser.h> +#include <Swiften/Parser/PayloadParsers/CapsInfoParser.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParserFactory.h> +#include <Swiften/Parser/PayloadParsers/CommandParserFactory.h> +#include <Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h> +#include <Swiften/Parser/PayloadParsers/BytestreamsParserFactory.h> +#include <Swiften/Parser/PayloadParsers/IBBParser.h> +#include <Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h> +#include <Swiften/Parser/PayloadParsers/VCardParserFactory.h> +#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h> +#include <Swiften/Parser/PayloadParsers/DelayParser.h> +#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/NicknameParserFactory.h> +#include <Swiften/Parser/PayloadParsers/ReplaceParser.h> +#include <Swiften/Parser/PayloadParsers/LastParser.h> +#include <Swiften/Parser/PayloadParsers/JingleParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleReasonParser.h> +#include <Swiften/Parser/PayloadParsers/JingleContentPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h> +#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h> +#include <Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h> + +#include "JingleIBBTransportMethodPayloadParser.h" +#include "JingleFileTransferDescriptionParser.h" using namespace boost; @@ -48,18 +73,25 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<IBBParser>("", "http://jabber.org/protocol/ibb"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StatusShowParser>("show"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StatusParser>("status"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ReplaceParser>("replace", "http://swift.im/protocol/replace"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<LastParser>("query", "jabber:iq:last"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BodyParser>("body"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SubjectParser>("subject"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<PriorityParser>("priority"))); - factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ErrorParser>("error"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new ErrorParserFactory(this))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DelayParser>("delay", "urn:xmpp:delay"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<SoftwareVersionParser>("query", "jabber:iq:version"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StorageParser>("storage", "storage:bookmarks"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterItemExchangeParser>("x", "http://jabber.org/protocol/rosterx"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<RosterParser>("query", "jabber:iq:roster"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoInfoParser>("query", "http://jabber.org/protocol/disco#info"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<DiscoItemsParser>("query", "http://jabber.org/protocol/disco#items"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<CapsInfoParser>("c", "http://jabber.org/protocol/caps"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<ResourceBindParser>("bind", "urn:ietf:params:xml:ns:xmpp-bind"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StartSessionParser>("session", "urn:ietf:params:xml:ns:xmpp-session"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BlockParser<BlockPayload> >("block", "urn:xmpp:blocking"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BlockParser<BlockListPayload> >("blocklist", "urn:xmpp:blocking"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<BlockParser<UnblockPayload> >("unblock", "urn:xmpp:blocking"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new SecurityLabelParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new SecurityLabelsCatalogParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new FormParserFactory())); @@ -72,9 +104,22 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(shared_ptr<PayloadParserFactory>(new VCardParserFactory())); factories_.push_back(shared_ptr<PayloadParserFactory>(new PrivateStorageParserFactory(this))); factories_.push_back(shared_ptr<PayloadParserFactory>(new ChatStateParserFactory())); - factories_.push_back(shared_ptr<PayloadParserFactory>(new DelayParserFactory())); - factories_.push_back(shared_ptr<PayloadParserFactory>(new MUCUserPayloadParserFactory())); + factories_.push_back(shared_ptr<PayloadParserFactory>(new MUCUserPayloadParserFactory(this))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new MUCOwnerPayloadParserFactory(this))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<MUCAdminPayloadParser>("query", "http://jabber.org/protocol/muc#admin"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<MUCDestroyPayloadParser>("destroy", "http://jabber.org/protocol/muc#user"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<MUCDestroyPayloadParser>("destroy", "http://jabber.org/protocol/muc#owner"))); factories_.push_back(shared_ptr<PayloadParserFactory>(new NicknameParserFactory())); + factories_.push_back(shared_ptr<PayloadParserFactory>(new JingleParserFactory(this))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<JingleReasonParser>("reason", "urn:xmpp:jingle:1"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new JingleContentPayloadParserFactory(this))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<JingleIBBTransportMethodPayloadParser>("transport", "urn:xmpp:jingle:transports:ibb:1"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<JingleS5BTransportMethodPayloadParser>("transport", "urn:xmpp:jingle:transports:s5b:1"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new JingleFileTransferDescriptionParserFactory(this))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<StreamInitiationFileInfoParser>("file", "http://jabber.org/protocol/si/profile/file-transfer"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<JingleFileTransferReceivedParser>("received", "urn:xmpp:jingle:apps:file-transfer:3"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<JingleFileTransferHashParser>("checksum"))); + factories_.push_back(shared_ptr<PayloadParserFactory>(new GenericPayloadParserFactory<S5BProxyRequestParser>("query", "http://jabber.org/protocol/bytestreams"))); foreach(shared_ptr<PayloadParserFactory> factory, factories_) { addFactory(factory.get()); } diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h index f3883b0..46b692b 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <vector> -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/PayloadParserFactory.h" +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { class FullPayloadParserFactoryCollection : public PayloadParserFactoryCollection { diff --git a/Swiften/Parser/PayloadParsers/IBBParser.cpp b/Swiften/Parser/PayloadParsers/IBBParser.cpp index f36dc43..20a1ce9 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.cpp +++ b/Swiften/Parser/PayloadParsers/IBBParser.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/IBBParser.h" +#include <Swiften/Parser/PayloadParsers/IBBParser.h> #include <boost/lexical_cast.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { @@ -27,7 +27,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string try { getPayloadInternal()->setSequenceNumber(boost::lexical_cast<int>(attributes.getAttribute("seq"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "open") { @@ -42,7 +42,7 @@ void IBBParser::handleStartElement(const std::string& element, const std::string try { getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttribute("block-size"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "close") { @@ -60,7 +60,7 @@ void IBBParser::handleEndElement(const std::string& element, const std::string&) std::vector<char> data; for (size_t i = 0; i < currentText.size(); ++i) { char c = currentText[i]; - if (c >= 48 && c <= 122) { + if ((c >= 48 && c <= 122) || c == 47 || c == 43) { data.push_back(c); } } diff --git a/Swiften/Parser/PayloadParsers/IBBParser.h b/Swiften/Parser/PayloadParsers/IBBParser.h index 132e79d..d899475 100644 --- a/Swiften/Parser/PayloadParsers/IBBParser.h +++ b/Swiften/Parser/PayloadParsers/IBBParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/IBB.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/IBB.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class IBBParser : public GenericPayloadParser<IBB> { diff --git a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.cpp b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.cpp index 56995d8..06759cb 100644 --- a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h" +#include <Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h> #include <boost/cast.hpp> -#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" -#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include <Swiften/Parser/PayloadParsers/FormParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h index c0209c4..ae8d36c 100644 --- a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/InBandRegistrationPayload.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/InBandRegistrationPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class FormParserFactory; diff --git a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h index 0417174..2dff18f 100644 --- a/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h +++ b/Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/InBandRegistrationPayloadParser.h> namespace Swift { class InBandRegistrationPayloadParserFactory : public GenericPayloadParserFactory<InBandRegistrationPayloadParser> { diff --git a/Swiften/Parser/PayloadParsers/JingleContentPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleContentPayloadParser.cpp new file mode 100644 index 0000000..1431b9e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleContentPayloadParser.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "JingleContentPayloadParser.h" +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Elements/JinglePayload.h> + +#include <Swiften/Base/Log.h> + +namespace Swift { + JingleContentPayloadParser::JingleContentPayloadParser(PayloadParserFactoryCollection* factories) : factories(factories), level(0) { + + } + + void JingleContentPayloadParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + std::string creator = attributes.getAttributeValue("creator").get_value_or(""); + if (creator == "initiator") { + getPayloadInternal()->setCreator(JingleContentPayload::InitiatorCreator); + } else if (creator == "responder") { + getPayloadInternal()->setCreator(JingleContentPayload::ResponderCreator); + } else { + getPayloadInternal()->setCreator(JingleContentPayload::UnknownCreator); + } + + getPayloadInternal()->setName(attributes.getAttributeValue("name").get_value_or("")); + } + + if (level == 1) { + PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + + ++level; + } + + void JingleContentPayloadParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + boost::shared_ptr<JingleTransportPayload> transport = boost::dynamic_pointer_cast<JingleTransportPayload>(currentPayloadParser->getPayload()); + if (transport) { + getPayloadInternal()->addTransport(transport); + } + + boost::shared_ptr<JingleDescription> description = boost::dynamic_pointer_cast<JingleDescription>(currentPayloadParser->getPayload()); + if (description) { + getPayloadInternal()->addDescription(description); + } + } + } + } + + void JingleContentPayloadParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } + } +} diff --git a/Swiften/Parser/PayloadParsers/JingleContentPayloadParser.h b/Swiften/Parser/PayloadParsers/JingleContentPayloadParser.h new file mode 100644 index 0000000..a871cc4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleContentPayloadParser.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class PayloadParserFactoryCollection; + +class JingleContentPayloadParser : public GenericPayloadParser<JingleContentPayload> { + public: + JingleContentPayloadParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + PayloadParserFactoryCollection* factories; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleContentPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/JingleContentPayloadParserFactory.h new file mode 100644 index 0000000..6d66e74 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleContentPayloadParserFactory.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleContentPayloadParser.h> + +namespace Swift { + + class PayloadParserFactoryCollection; + + class JingleContentPayloadParserFactory : public PayloadParserFactory { + public: + JingleContentPayloadParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return element == "content" && ns == "urn:xmpp:jingle:1"; + } + + virtual PayloadParser* createPayloadParser() { + return new JingleContentPayloadParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; + + }; +} + + diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp new file mode 100644 index 0000000..b394115 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "JingleFileTransferDescriptionParser.h" + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Base/Log.h> + +namespace Swift { + +JingleFileTransferDescriptionParser::JingleFileTransferDescriptionParser(PayloadParserFactoryCollection* factories) : factories(factories), level(0), + currentElement(UnknownElement) { + +} + +void JingleFileTransferDescriptionParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 0) { + + } + + if (level == 1) { + if (element == "offer") { + currentElement = OfferElement; + } else if (element == "request") { + currentElement = RequestElement; + } else { + currentElement = UnknownElement; + } + } + + if (level == 2) { + PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (level >= 2 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + + ++level; +} + +void JingleFileTransferDescriptionParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 2) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 2) { + boost::shared_ptr<StreamInitiationFileInfo> info = boost::dynamic_pointer_cast<StreamInitiationFileInfo>(currentPayloadParser->getPayload()); + if (info) { + if (currentElement == OfferElement) { + getPayloadInternal()->addOffer(*info); + } else if (currentElement == RequestElement) { + getPayloadInternal()->addRequest(*info); + } + } + } + } +} + +void JingleFileTransferDescriptionParser::handleCharacterData(const std::string& data) { + if (level >= 2 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h new file mode 100644 index 0000000..93560c6 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/PayloadParser.h> + +namespace Swift { + +class PayloadParserFactoryCollection; + +class JingleFileTransferDescriptionParser : public GenericPayloadParser<JingleFileTransferDescription> { + public: + JingleFileTransferDescriptionParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + enum CurrentParseElement { + UnknownElement, + RequestElement, + OfferElement, + }; + + PayloadParserFactoryCollection* factories; + int level; + CurrentParseElement currentElement; + boost::shared_ptr<PayloadParser> currentPayloadParser; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h new file mode 100644 index 0000000..b997c1d --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h> + +namespace Swift { + + class PayloadParserFactoryCollection; + + class JingleFileTransferDescriptionParserFactory : public PayloadParserFactory { + public: + JingleFileTransferDescriptionParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return element == "description" && ns == "urn:xmpp:jingle:apps:file-transfer:3"; + } + + virtual PayloadParser* createPayloadParser() { + return new JingleFileTransferDescriptionParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; + + }; +} + + diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp new file mode 100644 index 0000000..87f8317 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "JingleFileTransferHashParser.h" + +#include <boost/shared_ptr.hpp> +#include <boost/algorithm/string.hpp> + +#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactory.h> + +namespace Swift { + +JingleFileTransferHashParser::JingleFileTransferHashParser() { +} + +void JingleFileTransferHashParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (element == "hash") { + algo = attributes.getAttribute("algo"); + } +} + +void JingleFileTransferHashParser::handleEndElement(const std::string& element, const std::string& ) { + if (element == "hash" && !algo.empty() && !hash.empty()) { + getPayloadInternal()->setHash(algo, hash); + algo.clear(); + hash.clear(); + } +} + +void JingleFileTransferHashParser::handleCharacterData(const std::string& data) { + if (!algo.empty()) { + std::string new_data(data); + boost::trim(new_data); + hash += new_data; + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h new file mode 100644 index 0000000..35e4a05 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class JingleFileTransferHashParser : public GenericPayloadParser<JingleFileTransferHash> { +public: + JingleFileTransferHashParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + +private: + std::string algo; + std::string hash; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp new file mode 100644 index 0000000..20ad73e --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "JingleFileTransferReceivedParser.h" +#include "StreamInitiationFileInfoParser.h" + +#include <boost/shared_ptr.hpp> +#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactory.h> + +namespace Swift { + +JingleFileTransferReceivedParser::JingleFileTransferReceivedParser() : level(0) { +} + +void JingleFileTransferReceivedParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 1 && element == "file") { + PayloadParserFactory* payloadParserFactory = new GenericPayloadParserFactory<StreamInitiationFileInfoParser>("file", "http://jabber.org/protocol/si/profile/file-transfer"); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (currentPayloadParser && level >= 1) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + + ++level; +} + +void JingleFileTransferReceivedParser::handleEndElement(const std::string& element, const std::string& ) { + --level; + if (element == "file") { + boost::shared_ptr<StreamInitiationFileInfo> fileInfo = boost::dynamic_pointer_cast<StreamInitiationFileInfo>(currentPayloadParser->getPayload()); + if (fileInfo) { + getPayloadInternal()->setFileInfo(*fileInfo); + } + } +} + +void JingleFileTransferReceivedParser::handleCharacterData(const std::string& ) { + +} + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h new file mode 100644 index 0000000..824b06d --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferReceivedParser.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleFileTransferReceived.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class JingleFileTransferReceivedParser : public GenericPayloadParser<JingleFileTransferReceived> { +public: + JingleFileTransferReceivedParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + +private: + boost::shared_ptr<PayloadParser> currentPayloadParser; + int level; +}; + +}
\ No newline at end of file diff --git a/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp new file mode 100644 index 0000000..a3dfd12 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> + +#include "JingleIBBTransportMethodPayloadParser.h" + +#include <Swiften/Base/Log.h> + +namespace Swift { + JingleIBBTransportMethodPayloadParser::JingleIBBTransportMethodPayloadParser() : level(0) { + + } + + void JingleIBBTransportMethodPayloadParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + try { + getPayloadInternal()->setBlockSize(boost::lexical_cast<int>(attributes.getAttributeValue("block-size").get_value_or("0"))); + } catch (boost::bad_lexical_cast &) { + getPayloadInternal()->setBlockSize(0); + } + getPayloadInternal()->setSessionID(attributes.getAttributeValue("sid").get_value_or("")); + ++level; + } + + void JingleIBBTransportMethodPayloadParser::handleEndElement(const std::string&, const std::string&) { + --level; + + + } + + void JingleIBBTransportMethodPayloadParser::handleCharacterData(const std::string&) { + + } +} diff --git a/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h b/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h new file mode 100644 index 0000000..311cc5b --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleIBBTransportMethodPayloadParser.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class JingleIBBTransportMethodPayloadParser : public GenericPayloadParser<JingleIBBTransportPayload> { + public: + JingleIBBTransportMethodPayloadParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + int level; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleParser.cpp b/Swiften/Parser/PayloadParsers/JingleParser.cpp new file mode 100644 index 0000000..dd34458 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleParser.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/JingleParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Elements/JingleFileTransferReceived.h> +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Base/Log.h> + +#include <boost/intrusive_ptr.hpp> + +namespace Swift { + + JingleParser::JingleParser(PayloadParserFactoryCollection* factories) : factories(factories), level(0) { + + } + + void JingleParser::handleStartElement(const std::string& element, const std::string &ns, const AttributeMap& attributes) { + if (level == 0) { + // <jingle > tag + JinglePayload::ref payload = getPayloadInternal(); + payload->setAction(stringToAction(attributes.getAttributeValue("action").get_value_or(""))); + payload->setInitiator(JID(attributes.getAttributeValue("initiator").get_value_or(""))); + payload->setResponder(JID(attributes.getAttributeValue("responder").get_value_or(""))); + payload->setSessionID(attributes.getAttributeValue("sid").get_value_or("")); + } + + if (level == 1) { + PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + + ++level; + } + + void JingleParser::handleEndElement(const std::string& element, const std::string &ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + boost::shared_ptr<JinglePayload::Reason> reason = boost::dynamic_pointer_cast<JinglePayload::Reason>(currentPayloadParser->getPayload()); + if (reason) { + getPayloadInternal()->setReason(*reason); + } + + boost::shared_ptr<JingleContentPayload> payload = boost::dynamic_pointer_cast<JingleContentPayload>(currentPayloadParser->getPayload()); + if (payload) { + getPayloadInternal()->addContent(payload); + } + + boost::shared_ptr<JingleFileTransferReceived> received = boost::dynamic_pointer_cast<JingleFileTransferReceived>(currentPayloadParser->getPayload()); + if (received) { + getPayloadInternal()->addPayload(received); + } + + boost::shared_ptr<JingleFileTransferHash> hash = boost::dynamic_pointer_cast<JingleFileTransferHash>(currentPayloadParser->getPayload()); + if (hash) { + getPayloadInternal()->addPayload(hash); + } + } + } + } + + void JingleParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } + } + + JinglePayload::Action JingleParser::stringToAction(const std::string &str) const { + if (str == "content-accept") { + return JinglePayload::ContentAccept; + } else if (str == "content-add") { + return JinglePayload::ContentAdd; + } else if (str == "content-modify") { + return JinglePayload::ContentModify; + } else if (str == "content-reject") { + return JinglePayload::ContentReject; + } else if (str == "content-remove") { + return JinglePayload::ContentRemove; + } else if (str == "description-info") { + return JinglePayload::DescriptionInfo; + } else if (str == "security-info") { + return JinglePayload::SecurityInfo; + } else if (str == "session-accept") { + return JinglePayload::SessionAccept; + } else if (str == "session-info") { + return JinglePayload::SessionInfo; + } else if (str == "session-initiate") { + return JinglePayload::SessionInitiate; + } else if (str == "session-terminate") { + return JinglePayload::SessionTerminate; + } else if (str == "transport-accept") { + return JinglePayload::TransportAccept; + } else if (str == "transport-info") { + return JinglePayload::TransportInfo; + } else if (str == "transport-reject") { + return JinglePayload::TransportReject; + } else if (str == "transport-replace") { + return JinglePayload::TransportReplace; + } else { + return JinglePayload::UnknownAction; + } + + } +} diff --git a/Swiften/Parser/PayloadParsers/JingleParser.h b/Swiften/Parser/PayloadParsers/JingleParser.h new file mode 100644 index 0000000..ecaca3c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleParser.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> + +namespace Swift { + +class JingleParser : public GenericPayloadParser<JinglePayload> { + public: + JingleParser(PayloadParserFactoryCollection* factories); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + JinglePayload::Action stringToAction(const std::string &str) const; + + private: + PayloadParserFactoryCollection* factories; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; +}; + +};
\ No newline at end of file diff --git a/Swiften/Parser/PayloadParsers/JingleParserFactory.h b/Swiften/Parser/PayloadParsers/JingleParserFactory.h new file mode 100644 index 0000000..fa25aeb --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleParserFactory.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/JingleParser.h> + +namespace Swift { + + class PayloadParserFactoryCollection; + + class JingleParserFactory : public PayloadParserFactory { + public: + JingleParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return element == "jingle" && ns == "urn:xmpp:jingle:1"; + } + + virtual PayloadParser* createPayloadParser() { + return new JingleParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; + + }; +} + + diff --git a/Swiften/Parser/PayloadParsers/JingleReasonParser.cpp b/Swiften/Parser/PayloadParsers/JingleReasonParser.cpp new file mode 100644 index 0000000..3df82ae --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleReasonParser.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "JingleReasonParser.h" + +#include <Swiften/Base/Log.h> + +namespace Swift { + JingleReasonParser::JingleReasonParser() : level(0), parseText(false) { + + } + + void JingleReasonParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap&) { + if (level == 1) { + if (element == "text") { + parseText = true; + } else { + // reason type + getPayloadInternal()->type = stringToReasonType(element); + } + } + ++level; + } + + void JingleReasonParser::handleEndElement(const std::string& element, const std::string&) { + --level; + if (element == "text") { + parseText = false; + getPayloadInternal()->text = text; + } + } + + void JingleReasonParser::handleCharacterData(const std::string& data) { + if (parseText) { + text += data; + } + } + + JinglePayload::Reason::Type JingleReasonParser::stringToReasonType(const std::string& type) const { + if (type == "alternative-session") { + return JinglePayload::Reason::AlternativeSession; + } else if (type == "busy") { + return JinglePayload::Reason::Busy; + } else if (type == "cancel") { + return JinglePayload::Reason::Cancel; + } else if (type == "connectivity-error") { + return JinglePayload::Reason::ConnectivityError; + } else if (type == "decline") { + return JinglePayload::Reason::Decline; + } else if (type == "expired") { + return JinglePayload::Reason::Expired; + } else if (type == "failed-application") { + return JinglePayload::Reason::FailedApplication; + } else if (type == "failed-transport") { + return JinglePayload::Reason::FailedTransport; + } else if (type == "general-error") { + return JinglePayload::Reason::GeneralError; + } else if (type == "gone") { + return JinglePayload::Reason::Gone; + } else if (type == "incompatible-parameters") { + return JinglePayload::Reason::IncompatibleParameters; + } else if (type == "media-error") { + return JinglePayload::Reason::MediaError; + } else if (type == "security-error") { + return JinglePayload::Reason::SecurityError; + } else if (type == "success") { + return JinglePayload::Reason::Success; + } else if (type == "timeout") { + return JinglePayload::Reason::Timeout; + } else if (type == "unsupported-applications") { + return JinglePayload::Reason::UnsupportedApplications; + } else if (type == "unsupported-transports") { + return JinglePayload::Reason::UnsupportedTransports; + } else { + return JinglePayload::Reason::UnknownType; + } + } +} diff --git a/Swiften/Parser/PayloadParsers/JingleReasonParser.h b/Swiften/Parser/PayloadParsers/JingleReasonParser.h new file mode 100644 index 0000000..08af31a --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleReasonParser.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class JingleReasonParser : public GenericPayloadParser<JinglePayload::Reason> { + public: + JingleReasonParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + private: + JinglePayload::Reason::Type stringToReasonType(const std::string& type) const; + + private: + int level; + bool parseText; + std::string text; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp new file mode 100644 index 0000000..14a80e6 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> + +#include "JingleS5BTransportMethodPayloadParser.h" + +#include <Swiften/Base/Log.h> + +namespace Swift { + JingleS5BTransportMethodPayloadParser::JingleS5BTransportMethodPayloadParser() : level(0) { + + } + + void JingleS5BTransportMethodPayloadParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (level == 0) { + getPayloadInternal()->setSessionID(attributes.getAttributeValue("sid").get_value_or("")); + std::string mode = attributes.getAttributeValue("mode").get_value_or("tcp"); + if (mode == "tcp") { + getPayloadInternal()->setMode(JingleS5BTransportPayload::TCPMode); + } else if(mode == "udp") { + getPayloadInternal()->setMode(JingleS5BTransportPayload::UDPMode); + } else { + std::cerr << "Unknown S5B mode; falling back to defaul!" << std::endl; + getPayloadInternal()->setMode(JingleS5BTransportPayload::TCPMode); + } + } else if (level == 1) { + if (element == "candidate") { + JingleS5BTransportPayload::Candidate candidate; + candidate.cid = attributes.getAttributeValue("cid").get_value_or(""); + + int port = -1; + try { + port = boost::lexical_cast<int>(attributes.getAttributeValue("port").get_value_or("-1")); + } catch(boost::bad_lexical_cast &) { } + candidate.hostPort = HostAddressPort(HostAddress(attributes.getAttributeValue("host").get_value_or("")), port); + candidate.jid = JID(attributes.getAttributeValue("jid").get_value_or("")); + int priority = -1; + try { + priority = boost::lexical_cast<int>(attributes.getAttributeValue("priority").get_value_or("-1")); + } catch(boost::bad_lexical_cast &) { } + candidate.priority = priority; + candidate.type = stringToType(attributes.getAttributeValue("type").get_value_or("direct")); + + getPayloadInternal()->addCandidate(candidate); + } else if (element == "candidate-used") { + getPayloadInternal()->setCandidateUsed(attributes.getAttributeValue("cid").get_value_or("")); + } else if (element == "candidate-error") { + getPayloadInternal()->setCandidateError(true); + } else if (element == "activated") { + getPayloadInternal()->setActivated(attributes.getAttributeValue("cid").get_value_or("")); + } else if (element == "proxy-error") { + getPayloadInternal()->setProxyError(true); + } + } + + ++level; + } + + void JingleS5BTransportMethodPayloadParser::handleEndElement(const std::string&, const std::string&) { + --level; + + + } + + void JingleS5BTransportMethodPayloadParser::handleCharacterData(const std::string&) { + + } + + JingleS5BTransportPayload::Candidate::Type JingleS5BTransportMethodPayloadParser::stringToType(const std::string &str) const { + if (str == "direct") { + return JingleS5BTransportPayload::Candidate::DirectType; + } else if (str == "assisted") { + return JingleS5BTransportPayload::Candidate::AssistedType; + } else if (str == "tunnel") { + return JingleS5BTransportPayload::Candidate::TunnelType; + } else if (str == "proxy") { + return JingleS5BTransportPayload::Candidate::ProxyType; + } else { + std::cerr << "Unknown candidate type; falling back to default!" << std::endl; + return JingleS5BTransportPayload::Candidate::DirectType; + } + } +} diff --git a/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h new file mode 100644 index 0000000..1987d3f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleS5BTransportMethodPayloadParser.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class JingleS5BTransportMethodPayloadParser : public GenericPayloadParser<JingleS5BTransportPayload> { + public: + JingleS5BTransportMethodPayloadParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + JingleS5BTransportPayload::Candidate::Type stringToType(const std::string &str) const; + + private: + int level; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/LastParser.cpp b/Swiften/Parser/PayloadParsers/LastParser.cpp new file mode 100644 index 0000000..77ebba8 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/LastParser.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/LastParser.h> + +#include <boost/lexical_cast.hpp> + +namespace Swift { + +LastParser::LastParser() : level_(0) { +} + +void LastParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level_ == 0) { + int seconds = 0; + try { + seconds = boost::lexical_cast<int>(attributes.getAttribute("seconds")); + } + catch (boost::bad_lexical_cast&) { + } + getPayloadInternal()->setSeconds(seconds); + } + ++level_; + +} + +void LastParser::handleEndElement(const std::string&, const std::string&) { +} + +void LastParser::handleCharacterData(const std::string&) { +} + +} diff --git a/Swiften/Parser/PayloadParsers/LastParser.h b/Swiften/Parser/PayloadParsers/LastParser.h new file mode 100644 index 0000000..7c5c707 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/LastParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Last.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class LastParser : public GenericPayloadParser<Last> { + public: + LastParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp new file mode 100644 index 0000000..137ead4 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h> + +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/MUCOccupant.h> + +namespace Swift { + +void MUCAdminPayloadParser::handleTree(ParserElement::ref root) { + foreach (ParserElement::ref itemElement, root->getChildren("item", "http://jabber.org/protocol/muc#admin")) { + MUCItem item = MUCItemParser::itemFromTree(itemElement); + getPayloadInternal()->addItem(item); + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h new file mode 100644 index 0000000..dfa26da --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include <Swiften/Elements/MUCAdminPayload.h> +#include <Swiften/Parser/GenericPayloadTreeParser.h> +#include <Swiften/Parser/PayloadParsers/MUCItemParser.h> + +namespace Swift { + class MUCAdminPayloadParser : public GenericPayloadTreeParser<MUCAdminPayload> { + public: + virtual void handleTree(ParserElement::ref root); + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.cpp new file mode 100644 index 0000000..a8d29d0 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.h> + +#include <Swiften/Base/foreach.h> + +namespace Swift { + +void MUCDestroyPayloadParser::handleTree(ParserElement::ref root) { + std::string ns = root->getNamespace(); + std::string jid = root->getAttributes().getAttribute("jid"); + if (!jid.empty()) { + getPayloadInternal()->setNewVenue(JID(jid)); + } + getPayloadInternal()->setReason(root->getChild("reason", ns)->getText()); +} + +} diff --git a/Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.h b/Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.h new file mode 100644 index 0000000..714651f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCDestroyPayloadParser.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include <Swiften/Elements/MUCDestroyPayload.h> +#include <Swiften/Parser/GenericPayloadTreeParser.h> + +namespace Swift { + class MUCDestroyPayloadParser : public GenericPayloadTreeParser<MUCDestroyPayload> { + public: + virtual void handleTree(ParserElement::ref root); + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCItemParser.cpp b/Swiften/Parser/PayloadParsers/MUCItemParser.cpp new file mode 100644 index 0000000..2eb9997 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCItemParser.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/MUCItemParser.h> + +#include <boost/lexical_cast.hpp> + +#include <Swiften/Elements/MUCOccupant.h> + +#include <cassert> +#include <iostream> + +namespace Swift { + +MUCItem MUCItemParser::itemFromTree(ParserElement::ref root) { + MUCItem item; + std::string affiliation = root->getAttributes().getAttribute("affiliation"); + std::string role = root->getAttributes().getAttribute("role"); + std::string nick = root->getAttributes().getAttribute("nick"); + std::string jid = root->getAttributes().getAttribute("jid"); + item.affiliation = parseAffiliation(affiliation); + item.role = parseRole(role); + if (!jid.empty()) { + item.realJID = JID(jid); + } + if (!nick.empty()) { + item.nick = nick; + } + std::string xmlns = root->getNamespace(); + std::string reason = root->getChild("reason", xmlns)->getText(); + std::string actor = root->getChild("actor", xmlns)->getAttributes().getAttribute("jid"); + if (!reason.empty()) { + item.reason = reason; + } + if (!actor.empty()) { + item.actor = JID(actor); + } + + return item; +} + +boost::optional<MUCOccupant::Role> MUCItemParser::parseRole(const std::string& roleString) { + if (roleString == "moderator") { + return MUCOccupant::Moderator; + } + if (roleString == "participant") { + return MUCOccupant::Participant; + } + if (roleString == "visitor") { + return MUCOccupant::Visitor; + } + if (roleString == "none") { + return MUCOccupant::NoRole; + } + return boost::optional<MUCOccupant::Role>(); +} + +boost::optional<MUCOccupant::Affiliation> MUCItemParser::parseAffiliation(const std::string& affiliationString) { + if (affiliationString == "owner") { + return MUCOccupant::Owner; + } + if (affiliationString == "admin") { + return MUCOccupant::Admin; + } + if (affiliationString == "member") { + return MUCOccupant::Member; + } + if (affiliationString == "outcast") { + return MUCOccupant::Outcast; + } + if (affiliationString == "none") { + return MUCOccupant::NoAffiliation; + } + return boost::optional<MUCOccupant::Affiliation>(); +} + +} + + diff --git a/Swiften/Parser/PayloadParsers/MUCItemParser.h b/Swiften/Parser/PayloadParsers/MUCItemParser.h new file mode 100644 index 0000000..a0ea060 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCItemParser.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/MUCItem.h> +#include <Swiften/Parser/GenericPayloadTreeParser.h> + +namespace Swift { + class MUCItemParser { + public: + static MUCItem itemFromTree(ParserElement::ref root); + private: + static boost::optional<MUCOccupant::Role> parseRole(const std::string& itemString); + static boost::optional<MUCOccupant::Affiliation> parseAffiliation(const std::string& statusString); + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.cpp new file mode 100644 index 0000000..d7ae789 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> + +namespace Swift { + +MUCOwnerPayloadParser::MUCOwnerPayloadParser(PayloadParserFactoryCollection* factories) : factories(factories), level(0) { +} + +void MUCOwnerPayloadParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 1) { + PayloadParserFactory* payloadParserFactory = factories->getPayloadParserFactory(element, ns, attributes); + if (payloadParserFactory) { + currentPayloadParser.reset(payloadParserFactory->createPayloadParser()); + } + } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; +} + +void MUCOwnerPayloadParser::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (currentPayloadParser) { + if (level >= 1) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + getPayloadInternal()->setPayload(currentPayloadParser->getPayload()); + } + } +} + +void MUCOwnerPayloadParser::handleCharacterData(const std::string& data) { + if (level > 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h b/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h new file mode 100644 index 0000000..2761981 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> + +#include <Swiften/Elements/MUCOwnerPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class MUCOwnerPayloadParser : public GenericPayloadParser<MUCOwnerPayload> { + public: + MUCOwnerPayloadParser(PayloadParserFactoryCollection* factories); + + private: + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + PayloadParserFactoryCollection* factories; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParserFactory.h new file mode 100644 index 0000000..918c72c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/MUCOwnerPayloadParserFactory.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/MUCOwnerPayloadParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + + class MUCOwnerPayloadParserFactory : public PayloadParserFactory { + public: + MUCOwnerPayloadParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return element == "query" && ns == "http://jabber.org/protocol/muc#owner"; + } + + virtual PayloadParser* createPayloadParser() { + return new MUCOwnerPayloadParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; + + }; +} diff --git a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp index ec9e200..2da8b35 100644 --- a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.cpp @@ -4,91 +4,36 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h" +#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h> #include <boost/lexical_cast.hpp> -#include "Swiften/Elements/MUCOccupant.h" - -#include <cassert> -#include <iostream> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/MUCOccupant.h> +#include <Swiften/Parser/Tree/TreeReparser.h> namespace Swift { -MUCUserPayloadParser::MUCUserPayloadParser() : level(TopLevel) { -} - -void MUCUserPayloadParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { - if (level == ItemLevel) { - if (element == "item") { - MUCUserPayload::Item item; - std::string affiliation = attributes.getAttribute("affiliation"); - std::string role = attributes.getAttribute("role"); - std::string nick = attributes.getAttribute("nick"); - std::string jid = attributes.getAttribute("jid"); - item.affiliation = parseAffiliation(affiliation); - item.role = parseRole(role); - if (!jid.empty()) { - item.realJID = JID(jid); - } - if (!nick.empty()) { - item.nick = nick; - } +void MUCUserPayloadParser::handleTree(ParserElement::ref root) { + foreach (ParserElement::ref child, root->getAllChildren()) { + if (child->getName() == "item" && child->getNamespace() == root->getNamespace()) { + MUCItem item = MUCItemParser::itemFromTree(child); getPayloadInternal()->addItem(item); - } else if (element == "status") { + } + else if (child->getName() == "status" && child->getNamespace() == root->getNamespace()) { MUCUserPayload::StatusCode status; try { - status.code = boost::lexical_cast<int>(attributes.getAttribute("code").c_str()); + status.code = boost::lexical_cast<int>(child->getAttributes().getAttribute("code").c_str()); getPayloadInternal()->addStatusCode(status); } catch (boost::bad_lexical_cast&) { } } + else { + getPayloadInternal()->setPayload(TreeReparser::parseTree(child, factories)); + } } - ++level; -} - -MUCOccupant::Role MUCUserPayloadParser::parseRole(const std::string& roleString) const { - if (roleString == "moderator") { - return MUCOccupant::Moderator; - } - if (roleString == "participant") { - return MUCOccupant::Participant; - } - if (roleString == "visitor") { - return MUCOccupant::Visitor; - } - if (roleString == "none") { - return MUCOccupant::NoRole; - } - return MUCOccupant::NoRole; -} - -MUCOccupant::Affiliation MUCUserPayloadParser::parseAffiliation(const std::string& affiliationString) const { - if (affiliationString == "owner") { - return MUCOccupant::Owner; - } - if (affiliationString == "admin") { - return MUCOccupant::Admin; - } - if (affiliationString == "member") { - return MUCOccupant::Member; - } - if (affiliationString == "outcast") { - return MUCOccupant::Outcast; - } - if (affiliationString == "none") { - return MUCOccupant::NoAffiliation; - } - return MUCOccupant::NoAffiliation; -} - - -void MUCUserPayloadParser::handleEndElement(const std::string& /*element*/, const std::string&) { - --level; -} - -void MUCUserPayloadParser::handleCharacterData(const std::string& /*data*/) { - } } diff --git a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h index 384f0cd..66e63a8 100644 --- a/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h @@ -8,24 +8,17 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/MUCUserPayload.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/MUCUserPayload.h> +#include <Swiften/Parser/GenericPayloadTreeParser.h> +#include <Swiften/Parser/PayloadParsers/MUCItemParser.h> namespace Swift { - class MUCUserPayloadParser : public GenericPayloadParser<MUCUserPayload> { + class PayloadParserFactoryCollection; + class MUCUserPayloadParser : public GenericPayloadTreeParser<MUCUserPayload> { public: - MUCUserPayloadParser(); - - virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); - virtual void handleEndElement(const std::string& element, const std::string&); - virtual void handleCharacterData(const std::string& data); - MUCOccupant::Role parseRole(const std::string& itemString) const; - MUCOccupant::Affiliation parseAffiliation(const std::string& statusString) const; + MUCUserPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {} + virtual void handleTree(ParserElement::ref root); private: - enum Level { - TopLevel = 0, - ItemLevel = 1 - }; - int level; + PayloadParserFactoryCollection* factories; }; } diff --git a/Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h index 3946ece..2c1c915 100644 --- a/Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h +++ b/Swiften/Parser/PayloadParsers/MUCUserPayloadParserFactory.h @@ -6,12 +6,24 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h> namespace Swift { - class MUCUserPayloadParserFactory : public GenericPayloadParserFactory<MUCUserPayloadParser> { + class MUCUserPayloadParserFactory : public PayloadParserFactory { public: - MUCUserPayloadParserFactory() : GenericPayloadParserFactory<MUCUserPayloadParser>("x", "http://jabber.org/protocol/muc#user") {} + MUCUserPayloadParserFactory(PayloadParserFactoryCollection* factories) : factories(factories) { + } + + virtual bool canParse(const std::string& element, const std::string& ns, const AttributeMap&) const { + return element == "x" && ns == "http://jabber.org/protocol/muc#user"; + } + + virtual PayloadParser* createPayloadParser() { + return new MUCUserPayloadParser(factories); + } + + private: + PayloadParserFactoryCollection* factories; }; } diff --git a/Swiften/Parser/PayloadParsers/NicknameParser.cpp b/Swiften/Parser/PayloadParsers/NicknameParser.cpp index cd7ec27..b647b4d 100644 --- a/Swiften/Parser/PayloadParsers/NicknameParser.cpp +++ b/Swiften/Parser/PayloadParsers/NicknameParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/NicknameParser.h" +#include <Swiften/Parser/PayloadParsers/NicknameParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/NicknameParser.h b/Swiften/Parser/PayloadParsers/NicknameParser.h index 6e723c8..a89f835 100644 --- a/Swiften/Parser/PayloadParsers/NicknameParser.h +++ b/Swiften/Parser/PayloadParsers/NicknameParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/Nickname.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Nickname.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class NicknameParser : public GenericPayloadParser<Nickname> { diff --git a/Swiften/Parser/PayloadParsers/NicknameParserFactory.h b/Swiften/Parser/PayloadParsers/NicknameParserFactory.h index ce2ebdd..b292513 100644 --- a/Swiften/Parser/PayloadParsers/NicknameParserFactory.h +++ b/Swiften/Parser/PayloadParsers/NicknameParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/NicknameParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/NicknameParser.h> namespace Swift { class NicknameParserFactory : public GenericPayloadParserFactory<NicknameParser> { diff --git a/Swiften/Parser/PayloadParsers/PriorityParser.cpp b/Swiften/Parser/PayloadParsers/PriorityParser.cpp index bcbf67f..b440444 100644 --- a/Swiften/Parser/PayloadParsers/PriorityParser.cpp +++ b/Swiften/Parser/PayloadParsers/PriorityParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/PriorityParser.h" +#include <Swiften/Parser/PayloadParsers/PriorityParser.h> #include <boost/lexical_cast.hpp> @@ -24,7 +24,7 @@ void PriorityParser::handleEndElement(const std::string&, const std::string&) { try { priority = boost::lexical_cast<int>(text_); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } getPayloadInternal()->setPriority(priority); } diff --git a/Swiften/Parser/PayloadParsers/PriorityParser.h b/Swiften/Parser/PayloadParsers/PriorityParser.h index 1b02255..8d6bf86 100644 --- a/Swiften/Parser/PayloadParsers/PriorityParser.h +++ b/Swiften/Parser/PayloadParsers/PriorityParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PriorityParser_H -#define SWIFTEN_PriorityParser_H +#pragma once -#include "Swiften/Elements/Priority.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Priority.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class PriorityParser : public GenericPayloadParser<Priority> { @@ -24,5 +23,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/PrivateStorageParser.cpp b/Swiften/Parser/PayloadParsers/PrivateStorageParser.cpp index 026da96..bf16394 100644 --- a/Swiften/Parser/PayloadParsers/PrivateStorageParser.cpp +++ b/Swiften/Parser/PayloadParsers/PrivateStorageParser.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/PrivateStorageParser.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/PayloadParserFactory.h" +#include <Swiften/Parser/PayloadParsers/PrivateStorageParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { @@ -21,7 +21,7 @@ void PrivateStorageParser::handleStartElement(const std::string& element, const } } - if (level >= 1 && currentPayloadParser.get()) { + if (level >= 1 && currentPayloadParser) { currentPayloadParser->handleStartElement(element, ns, attributes); } ++level; @@ -29,7 +29,7 @@ void PrivateStorageParser::handleStartElement(const std::string& element, const void PrivateStorageParser::handleEndElement(const std::string& element, const std::string& ns) { --level; - if (currentPayloadParser.get()) { + if (currentPayloadParser) { if (level >= 1) { currentPayloadParser->handleEndElement(element, ns); } @@ -41,7 +41,7 @@ void PrivateStorageParser::handleEndElement(const std::string& element, const st } void PrivateStorageParser::handleCharacterData(const std::string& data) { - if (level > 1 && currentPayloadParser.get()) { + if (level > 1 && currentPayloadParser) { currentPayloadParser->handleCharacterData(data); } } diff --git a/Swiften/Parser/PayloadParsers/PrivateStorageParser.h b/Swiften/Parser/PayloadParsers/PrivateStorageParser.h index f5f569a..d350593 100644 --- a/Swiften/Parser/PayloadParsers/PrivateStorageParser.h +++ b/Swiften/Parser/PayloadParsers/PrivateStorageParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/PrivateStorage.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/PrivateStorage.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class PayloadParserFactoryCollection; @@ -26,6 +26,6 @@ namespace Swift { private: PayloadParserFactoryCollection* factories; int level; - std::auto_ptr<PayloadParser> currentPayloadParser; + boost::shared_ptr<PayloadParser> currentPayloadParser; }; } diff --git a/Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h b/Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h index 9399ace..5b93aef 100644 --- a/Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h +++ b/Swiften/Parser/PayloadParsers/PrivateStorageParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/PrivateStorageParser.h" +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/PrivateStorageParser.h> namespace Swift { class PayloadParserFactoryCollection; diff --git a/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.cpp b/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.cpp index bc9b843..0837ae8 100644 --- a/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h" -#include "Swiften/Parser/SerializingParser.h" +#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h> +#include <Swiften/Parser/SerializingParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h b/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h index b5c887a..4a027a1 100644 --- a/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Elements/RawXMLPayload.h" -#include "Swiften/Parser/GenericPayloadParser.h" -#include "Swiften/Parser/SerializingParser.h" +#include <Swiften/Elements/RawXMLPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/SerializingParser.h> namespace Swift { class SerializingParser; diff --git a/Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h index b180e1e..d777caa 100644 --- a/Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h +++ b/Swiften/Parser/PayloadParsers/RawXMLPayloadParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h" +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h> #include <string> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.cpp b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp new file mode 100644 index 0000000..fb85fbd --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/ReplaceParser.h> + +namespace Swift { + + ReplaceParser::ReplaceParser() : level_(0) { + } + + void ReplaceParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level_ == 0) { + std::string id = attributes.getAttribute("id"); + getPayloadInternal()->setID(id); + } + level_++; + } + + void ReplaceParser::handleEndElement(const std::string&, const std::string&) { + --level_; + } + + void ReplaceParser::handleCharacterData(const std::string&) { + } + +} diff --git a/Swiften/Parser/PayloadParsers/ReplaceParser.h b/Swiften/Parser/PayloadParsers/ReplaceParser.h new file mode 100644 index 0000000..4d73459 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/ReplaceParser.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/Replace.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class ReplaceParser : public GenericPayloadParser<Replace> { + public: + ReplaceParser(); + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + int level_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/ResourceBindParser.cpp b/Swiften/Parser/PayloadParsers/ResourceBindParser.cpp index 5c3affb..81378df 100644 --- a/Swiften/Parser/PayloadParsers/ResourceBindParser.cpp +++ b/Swiften/Parser/PayloadParsers/ResourceBindParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/ResourceBindParser.h" +#include <Swiften/Parser/PayloadParsers/ResourceBindParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/ResourceBindParser.h b/Swiften/Parser/PayloadParsers/ResourceBindParser.h index 875b5f4..e604751 100644 --- a/Swiften/Parser/PayloadParsers/ResourceBindParser.h +++ b/Swiften/Parser/PayloadParsers/ResourceBindParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ResourceBindParser_H -#define SWIFTEN_ResourceBindParser_H +#pragma once -#include "Swiften/Elements/ResourceBind.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/ResourceBind.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class ResourceBindParser : public GenericPayloadParser<ResourceBind> { @@ -26,5 +25,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp new file mode 100644 index 0000000..32be2c7 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h> +#include <Swiften/Parser/SerializingParser.h> + +namespace Swift { + +RosterItemExchangeParser::RosterItemExchangeParser() : level_(TopLevel), inItem_(false) { +} + +void RosterItemExchangeParser::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) { + if (level_ == PayloadLevel) { + if (element == "item") { + inItem_ = true; + + currentItem_ = RosterItemExchangePayload::Item(); + + currentItem_.setJID(JID(attributes.getAttribute("jid"))); + currentItem_.setName(attributes.getAttribute("name")); + + std::string action = attributes.getAttribute("action"); + if (action == "add") { + currentItem_.setAction(RosterItemExchangePayload::Item::Add); + } + else if (action == "modify") { + currentItem_.setAction(RosterItemExchangePayload::Item::Modify); + } + else if (action == "delete") { + currentItem_.setAction(RosterItemExchangePayload::Item::Delete); + } + else { + // Add is default action according to XEP + currentItem_.setAction(RosterItemExchangePayload::Item::Add); + } + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentText_ = ""; + } + } + ++level_; +} + +void RosterItemExchangeParser::handleEndElement(const std::string& element, const std::string& /*ns*/) { + --level_; + if (level_ == PayloadLevel) { + if (inItem_) { + getPayloadInternal()->addItem(currentItem_); + inItem_ = false; + } + } + else if (level_ == ItemLevel) { + if (element == "group") { + currentItem_.addGroup(currentText_); + } + } +} + +void RosterItemExchangeParser::handleCharacterData(const std::string& data) { + currentText_ += data; +} + +} diff --git a/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h new file mode 100644 index 0000000..5652b94 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/RosterItemExchangePayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + class SerializingParser; + + class RosterItemExchangeParser : public GenericPayloadParser<RosterItemExchangePayload> { + public: + RosterItemExchangeParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + enum Level { + TopLevel = 0, + PayloadLevel = 1, + ItemLevel = 2 + }; + int level_; + bool inItem_; + RosterItemExchangePayload::Item currentItem_; + std::string currentText_; + }; +} diff --git a/Swiften/Parser/PayloadParsers/RosterParser.cpp b/Swiften/Parser/PayloadParsers/RosterParser.cpp index ba19fbf..53c433a 100644 --- a/Swiften/Parser/PayloadParsers/RosterParser.cpp +++ b/Swiften/Parser/PayloadParsers/RosterParser.cpp @@ -4,8 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/RosterParser.h" -#include "Swiften/Parser/SerializingParser.h" +#include <Swiften/Parser/PayloadParsers/RosterParser.h> + +#include <boost/optional.hpp> + +#include <Swiften/Parser/SerializingParser.h> namespace Swift { @@ -13,7 +16,13 @@ RosterParser::RosterParser() : level_(TopLevel), inItem_(false), unknownContentP } void RosterParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { - if (level_ == PayloadLevel) { + if (level_ == TopLevel) { + boost::optional<std::string> ver = attributes.getAttributeValue("ver"); + if (ver) { + getPayloadInternal()->setVersion(*ver); + } + } + else if (level_ == PayloadLevel) { if (element == "item") { inItem_ = true; currentItem_ = RosterItemPayload(); diff --git a/Swiften/Parser/PayloadParsers/RosterParser.h b/Swiften/Parser/PayloadParsers/RosterParser.h index ac72696..c29064f 100644 --- a/Swiften/Parser/PayloadParsers/RosterParser.h +++ b/Swiften/Parser/PayloadParsers/RosterParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterParser_H -#define SWIFTEN_RosterParser_H +#pragma once -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SerializingParser; @@ -34,5 +33,3 @@ namespace Swift { SerializingParser* unknownContentParser_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp new file mode 100644 index 0000000..6e33f16 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "S5BProxyRequestParser.h" + +#include <boost/lexical_cast.hpp> +#include <boost/optional.hpp> + +namespace Swift { + +S5BProxyRequestParser::S5BProxyRequestParser() : parseActivate(false) { +} + +S5BProxyRequestParser::~S5BProxyRequestParser() { +} + +void S5BProxyRequestParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (element == "streamhost") { + if (attributes.getAttributeValue("host") && attributes.getAttributeValue("jid") && attributes.getAttributeValue("port")) { + HostAddress address = attributes.getAttributeValue("host").get_value_or(""); + int port = -1; + JID jid = attributes.getAttributeValue("jid").get_value_or(""); + + try { + port = boost::lexical_cast<int>(attributes.getAttributeValue("port").get()); + } catch (boost::bad_lexical_cast &) { + port = -1; + } + if (address.isValid() && port != -1 && jid.isValid()) { + S5BProxyRequest::StreamHost streamHost; + streamHost.addressPort = HostAddressPort(address, port); + streamHost.jid = jid; + getPayloadInternal()->setStreamHost(streamHost); + } + } + } else if (element == "activate") { + parseActivate = true; + } else if (element == "query") { + if (attributes.getAttributeValue("sid")) { + getPayloadInternal()->setSID(attributes.getAttributeValue("sid").get()); + } + } +} + +void S5BProxyRequestParser::handleEndElement(const std::string& element, const std::string&) { + if (element == "activate") { + JID activate = JID(activateJID); + if (activate.isValid()) { + getPayloadInternal()->setActivate(activate); + } + parseActivate = false; + } +} + +void S5BProxyRequestParser::handleCharacterData(const std::string& data) { + if (parseActivate) { + activateJID = activateJID + data; + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h new file mode 100644 index 0000000..0bf1a26 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/S5BProxyRequestParser.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <string> + +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class S5BProxyRequestParser : public GenericPayloadParser<S5BProxyRequest> { +public: + S5BProxyRequestParser(); + virtual ~S5BProxyRequestParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + +private: + bool parseActivate; + std::string activateJID; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp b/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp index 9daf842..f4de503 100644 --- a/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParser.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/SearchPayloadParser.h" +#include <Swiften/Parser/PayloadParsers/SearchPayloadParser.h> #include <boost/cast.hpp> -#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" -#include "Swiften/Parser/PayloadParsers/FormParser.h" +#include <Swiften/Parser/PayloadParsers/FormParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParser.h b/Swiften/Parser/PayloadParsers/SearchPayloadParser.h index 01441e8..006e0d9 100644 --- a/Swiften/Parser/PayloadParsers/SearchPayloadParser.h +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/SearchPayload.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/SearchPayload.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class FormParserFactory; diff --git a/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h b/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h index 0f8a6c7..5130556 100644 --- a/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h +++ b/Swiften/Parser/PayloadParsers/SearchPayloadParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/SearchPayloadParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SearchPayloadParser.h> namespace Swift { class SearchPayloadParserFactory : public GenericPayloadParserFactory<SearchPayloadParser> { diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp b/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp index b769a47..4177baa 100644 --- a/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp +++ b/Swiften/Parser/PayloadParsers/SecurityLabelParser.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/SecurityLabelParser.h" -#include "Swiften/Parser/SerializingParser.h" +#include <Swiften/Parser/PayloadParsers/SecurityLabelParser.h> +#include <Swiften/Parser/SerializingParser.h> namespace Swift { @@ -62,7 +62,7 @@ void SecurityLabelParser::handleCharacterData(const std::string& data) { } } -boost::shared_ptr<SecurityLabel> SecurityLabelParser::getLabelPayload() { +boost::shared_ptr<SecurityLabel> SecurityLabelParser::getLabelPayload() const { return getPayloadInternal(); } diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelParser.h b/Swiften/Parser/PayloadParsers/SecurityLabelParser.h index b54c3be..5357028 100644 --- a/Swiften/Parser/PayloadParsers/SecurityLabelParser.h +++ b/Swiften/Parser/PayloadParsers/SecurityLabelParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelParser_H -#define SWIFTEN_SecurityLabelParser_H +#pragma once -#include "Swiften/Elements/SecurityLabel.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/SecurityLabel.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SerializingParser; @@ -20,7 +19,7 @@ namespace Swift { virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); virtual void handleEndElement(const std::string& element, const std::string&); virtual void handleCharacterData(const std::string& data); - boost::shared_ptr<SecurityLabel> getLabelPayload(); + boost::shared_ptr<SecurityLabel> getLabelPayload() const; private: enum Level { TopLevel = 0, @@ -33,5 +32,3 @@ namespace Swift { std::string currentText_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h b/Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h index 538d4a1..47c4a0c 100644 --- a/Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h +++ b/Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelParserFactory_H -#define SWIFTEN_SecurityLabelParserFactory_H +#pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/SecurityLabelParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelParser.h> namespace Swift { class SecurityLabelParserFactory : public GenericPayloadParserFactory<SecurityLabelParser> { @@ -16,5 +15,3 @@ namespace Swift { SecurityLabelParserFactory() : GenericPayloadParserFactory<SecurityLabelParser>("securitylabel", "urn:xmpp:sec-label:0") {} }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp index 6a366b3..e90573f 100644 --- a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp +++ b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.cpp @@ -4,9 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h" -#include "Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h" -#include "Swiften/Parser/PayloadParsers/SecurityLabelParser.h" +#include <Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h index ca422d1..d50faa4 100644 --- a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h +++ b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelsCatalogParser_H -#define SWIFTEN_SecurityLabelsCatalogParser_H +#pragma once -#include "Swiften/Elements/SecurityLabelsCatalog.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/SecurityLabelsCatalog.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SecurityLabelParserFactory; @@ -36,5 +35,3 @@ namespace Swift { boost::shared_ptr<SecurityLabelsCatalog::Item> currentItem_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h index a148d81..a93100a 100644 --- a/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h +++ b/Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParserFactory.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelsCatalogParserFactory_H -#define SWIFTEN_SecurityLabelsCatalogParserFactory_H +#pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h> namespace Swift { class SecurityLabelsCatalogParserFactory : public GenericPayloadParserFactory<SecurityLabelsCatalogParser> { @@ -16,5 +15,3 @@ namespace Swift { SecurityLabelsCatalogParserFactory() : GenericPayloadParserFactory<SecurityLabelsCatalogParser>("catalog", "urn:xmpp:sec-label:catalog:2") {} }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/SoftwareVersionParser.cpp b/Swiften/Parser/PayloadParsers/SoftwareVersionParser.cpp index f8e61c7..b1c3e18 100644 --- a/Swiften/Parser/PayloadParsers/SoftwareVersionParser.cpp +++ b/Swiften/Parser/PayloadParsers/SoftwareVersionParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/SoftwareVersionParser.h" +#include <Swiften/Parser/PayloadParsers/SoftwareVersionParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/SoftwareVersionParser.h b/Swiften/Parser/PayloadParsers/SoftwareVersionParser.h index 4272e5a..01d5ed8 100644 --- a/Swiften/Parser/PayloadParsers/SoftwareVersionParser.h +++ b/Swiften/Parser/PayloadParsers/SoftwareVersionParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SoftwareVersionParser_H -#define SWIFTEN_SoftwareVersionParser_H +#pragma once -#include "Swiften/Elements/SoftwareVersion.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/SoftwareVersion.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SoftwareVersionParser : public GenericPayloadParser<SoftwareVersion> { @@ -28,5 +27,3 @@ namespace Swift { std::string currentText_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/StartSessionParser.h b/Swiften/Parser/PayloadParsers/StartSessionParser.h index ba6e3c8..ce78ae7 100644 --- a/Swiften/Parser/PayloadParsers/StartSessionParser.h +++ b/Swiften/Parser/PayloadParsers/StartSessionParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartSessionParser_H -#define SWIFTEN_StartSessionParser_H +#pragma once -#include "Swiften/Elements/StartSession.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/StartSession.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class StartSessionParser : public GenericPayloadParser<StartSession> { @@ -20,5 +19,3 @@ namespace Swift { virtual void handleCharacterData(const std::string&) {} }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/StatusParser.cpp b/Swiften/Parser/PayloadParsers/StatusParser.cpp index a5d00de..1394d46 100644 --- a/Swiften/Parser/PayloadParsers/StatusParser.cpp +++ b/Swiften/Parser/PayloadParsers/StatusParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/StatusParser.h" +#include <Swiften/Parser/PayloadParsers/StatusParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/StatusParser.h b/Swiften/Parser/PayloadParsers/StatusParser.h index 4c6f4ac..9d7493e 100644 --- a/Swiften/Parser/PayloadParsers/StatusParser.h +++ b/Swiften/Parser/PayloadParsers/StatusParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StatusParser_H -#define SWIFTEN_StatusParser_H +#pragma once -#include "Swiften/Elements/Status.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Status.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class StatusParser : public GenericPayloadParser<Status> { @@ -24,5 +23,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/StatusShowParser.cpp b/Swiften/Parser/PayloadParsers/StatusShowParser.cpp index 774f27d..f5814ec 100644 --- a/Swiften/Parser/PayloadParsers/StatusShowParser.cpp +++ b/Swiften/Parser/PayloadParsers/StatusShowParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/StatusShowParser.h" +#include <Swiften/Parser/PayloadParsers/StatusShowParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/StatusShowParser.h b/Swiften/Parser/PayloadParsers/StatusShowParser.h index b4100a3..6e72c13 100644 --- a/Swiften/Parser/PayloadParsers/StatusShowParser.h +++ b/Swiften/Parser/PayloadParsers/StatusShowParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StatusShowParser_H -#define SWIFTEN_StatusShowParser_H +#pragma once -#include "Swiften/Elements/StatusShow.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/StatusShow.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class StatusShowParser : public GenericPayloadParser<StatusShow> { @@ -24,5 +23,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Parser/PayloadParsers/StorageParser.cpp b/Swiften/Parser/PayloadParsers/StorageParser.cpp index 94cd0ce..05e24e7 100644 --- a/Swiften/Parser/PayloadParsers/StorageParser.cpp +++ b/Swiften/Parser/PayloadParsers/StorageParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/StorageParser.h" +#include <Swiften/Parser/PayloadParsers/StorageParser.h> #include <cassert> diff --git a/Swiften/Parser/PayloadParsers/StorageParser.h b/Swiften/Parser/PayloadParsers/StorageParser.h index 16fd869..76dce90 100644 --- a/Swiften/Parser/PayloadParsers/StorageParser.h +++ b/Swiften/Parser/PayloadParsers/StorageParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/Storage.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Storage.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class StorageParser : public GenericPayloadParser<Storage> { diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp new file mode 100644 index 0000000..0a13844 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include "StreamInitiationFileInfoParser.h" + +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/Base/Log.h> + +namespace Swift { + +StreamInitiationFileInfoParser::StreamInitiationFileInfoParser() : level(0), parseDescription(false) { + +} + +void StreamInitiationFileInfoParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + if (level == 0) { + getPayloadInternal()->setName(attributes.getAttributeValue("name").get_value_or("")); + getPayloadInternal()->setHash(attributes.getAttributeValue("hash").get_value_or("")); + getPayloadInternal()->setAlgo(attributes.getAttributeValue("algo").get_value_or("md5")); + try { + getPayloadInternal()->setSize(boost::lexical_cast<boost::uintmax_t>(attributes.getAttributeValue("size").get_value_or("0"))); + } catch (boost::bad_lexical_cast &) { + getPayloadInternal()->setSize(0); + } + getPayloadInternal()->setDate(stringToDateTime(attributes.getAttributeValue("date").get_value_or(""))); + } else if (level == 1) { + if (element == "desc") { + parseDescription = true; + } else { + parseDescription = false; + if (element == "range") { + int offset = 0; + try { + offset = boost::lexical_cast<boost::uintmax_t>(attributes.getAttributeValue("offset").get_value_or("0")); + } catch (boost::bad_lexical_cast &) { + offset = 0; + } + if (offset == 0) { + getPayloadInternal()->setSupportsRangeRequests(true); + } else { + getPayloadInternal()->setRangeOffset(offset); + } + } + } + } + ++level; +} + +void StreamInitiationFileInfoParser::handleEndElement(const std::string& element, const std::string&) { + --level; + if (parseDescription && element == "desc") { + parseDescription = false; + getPayloadInternal()->setDescription(desc); + } +} + +void StreamInitiationFileInfoParser::handleCharacterData(const std::string& data) { + if (parseDescription) { + desc += data; + } +} + +} diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h new file mode 100644 index 0000000..6d3591d --- /dev/null +++ b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class StreamInitiationFileInfoParser : public GenericPayloadParser<StreamInitiationFileInfo> { + public: + StreamInitiationFileInfoParser(); + + virtual void handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string&); + virtual void handleCharacterData(const std::string& data); + + private: + int level; + bool parseDescription; + std::string desc; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp index 1cf7fcf..fd3d019 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/StreamInitiationParser.h" +#include <Swiften/Parser/PayloadParsers/StreamInitiationParser.h> #include <boost/lexical_cast.hpp> #include <boost/cast.hpp> -#include "Swiften/Parser/PayloadParsers/FormParserFactory.h" -#include "Swiften/Parser/PayloadParsers/FormParser.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Parser/PayloadParsers/FormParserFactory.h> +#include <Swiften/Parser/PayloadParsers/FormParser.h> +#include <Swiften/Base/foreach.h> #define FILE_TRANSFER_NS "http://jabber.org/protocol/si/profile/file-transfer" @@ -38,11 +38,11 @@ void StreamInitiationParser::handleStartElement(const std::string& element, cons if (element == "file") { inFile = true; currentFile = StreamInitiationFileInfo(); - currentFile.name = attributes.getAttribute("name"); + currentFile.setName(attributes.getAttribute("name")); try { - currentFile.size = boost::lexical_cast<int>(attributes.getAttribute("size")); + currentFile.setSize(boost::lexical_cast<int>(attributes.getAttribute("size"))); } - catch (boost::bad_lexical_cast& e) { + catch (boost::bad_lexical_cast&) { } } else if (element == "feature" && ns == FEATURE_NEG_NS) { @@ -83,7 +83,7 @@ void StreamInitiationParser::handleEndElement(const std::string& element, const } else if (level == FileOrFeatureLevel) { if (inFile && element == "desc") { - currentFile.description = currentText; + currentFile.setDescription(currentText); } else if (formParser) { Form::ref form = formParser->getPayloadInternal(); diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParser.h b/Swiften/Parser/PayloadParsers/StreamInitiationParser.h index 46f5b2f..c2ffd07 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParser.h +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParser.h @@ -8,8 +8,8 @@ #include <boost/optional.hpp> -#include "Swiften/Elements/StreamInitiation.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/StreamInitiation.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class FormParserFactory; diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h b/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h index ee5ed09..a75cf37 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h +++ b/Swiften/Parser/PayloadParsers/StreamInitiationParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/StreamInitiationParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/StreamInitiationParser.h> namespace Swift { class StreamInitiationParserFactory : public GenericPayloadParserFactory<StreamInitiationParser> { diff --git a/Swiften/Parser/PayloadParsers/SubjectParser.cpp b/Swiften/Parser/PayloadParsers/SubjectParser.cpp index d7d9af8..276a05a 100644 --- a/Swiften/Parser/PayloadParsers/SubjectParser.cpp +++ b/Swiften/Parser/PayloadParsers/SubjectParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/SubjectParser.h" +#include <Swiften/Parser/PayloadParsers/SubjectParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/SubjectParser.h b/Swiften/Parser/PayloadParsers/SubjectParser.h index 78e5a9e..1d7d2ce 100644 --- a/Swiften/Parser/PayloadParsers/SubjectParser.h +++ b/Swiften/Parser/PayloadParsers/SubjectParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/Subject.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/Subject.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SubjectParser : public GenericPayloadParser<Subject> { diff --git a/Swiften/Parser/PayloadParsers/UnitTest/BodyParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/BodyParserTest.cpp index bb53586..fe91088 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/BodyParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/BodyParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/BodyParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/BodyParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp index 7ebcbac..3e4971b 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/CommandParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" -#include "Swiften/Elements/Command.h" +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Command.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp index 793e0c2..bfbc312 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/DiscoInfoParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/DiscoInfoParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp index 02c2f7d..005fc09 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp @@ -7,14 +7,16 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/ErrorParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/ErrorParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Delay.h> using namespace Swift; class ErrorParserTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ErrorParserTest); CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParseWithPayload); CPPUNIT_TEST_SUITE_END(); public: @@ -31,7 +33,26 @@ class ErrorParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(ErrorPayload::BadRequest, payload->getCondition()); CPPUNIT_ASSERT_EQUAL(ErrorPayload::Modify, payload->getType()); CPPUNIT_ASSERT_EQUAL(std::string("boo"), payload->getText()); + CPPUNIT_ASSERT(!payload->getPayload()); } + + void testParseWithPayload() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse( + "<error type=\"modify\">" + "<bad-request xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>" + "<delay xmlns='urn:xmpp:delay' from='juliet@capulet.com/balcony' stamp='2002-09-10T23:41:07Z'/>" + "<text xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\">boo</text>" + "</error>")); + + ErrorPayload::ref payload = boost::dynamic_pointer_cast<ErrorPayload>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(ErrorPayload::BadRequest, payload->getCondition()); + CPPUNIT_ASSERT_EQUAL(ErrorPayload::Modify, payload->getType()); + CPPUNIT_ASSERT_EQUAL(std::string("boo"), payload->getText()); + CPPUNIT_ASSERT(boost::dynamic_pointer_cast<Delay>(payload->getPayload())); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION(ErrorParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp index 6ec825b..86845be 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/FormParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" -#include "Swiften/Elements/Form.h" +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/Form.h> using namespace Swift; @@ -77,7 +77,6 @@ class FormParserTest : public CppUnit::TestFixture { "</field>" "<field var=\"untyped\">" "<value>foo</value>" - "<value>baz</value>" "</field>" "</x>")); @@ -114,8 +113,7 @@ class FormParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(JID("baz@fum.org"), boost::dynamic_pointer_cast<JIDMultiFormField>(payload->getFields()[8])->getValue()[1]); CPPUNIT_ASSERT_EQUAL(std::string("Tell all your friends about your new bot!"), payload->getFields()[8]->getDescription()); - CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<UntypedFormField>(payload->getFields()[9])->getValue()[0]); - CPPUNIT_ASSERT_EQUAL(std::string("baz"), boost::dynamic_pointer_cast<UntypedFormField>(payload->getFields()[9])->getValue()[1]); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), boost::dynamic_pointer_cast<TextSingleFormField>(payload->getFields()[9])->getValue()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp index b4229f2..90d7b6b 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/IBBParserTest.cpp @@ -4,13 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" -#include "Swiften/Elements/IBB.h" +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/IBB.h> using namespace Swift; @@ -32,7 +32,7 @@ class IBBParserTest : public CppUnit::TestFixture { IBB::ref ibb = parser.getPayload<IBB>(); CPPUNIT_ASSERT(ibb->getAction() == IBB::Data); - CPPUNIT_ASSERT_EQUAL(ByteArray("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a"), ibb->getData()); + CPPUNIT_ASSERT(createByteArray("abcdefgihjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\x0a") == ibb->getData()); CPPUNIT_ASSERT_EQUAL(4, ibb->getSequenceNumber()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp new file mode 100644 index 0000000..f1f25cd --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/JingleFileTransferReceived.h> +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Base/DateTime.h> + +#include <Swiften/Base/Log.h> + +using namespace Swift; + +class JingleParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(JingleParserTest); + CPPUNIT_TEST(testParse_Xep0166_Example3); + CPPUNIT_TEST(testParse_Xep0166_Example8); + + CPPUNIT_TEST(testParse_Xep0261_Example1); + CPPUNIT_TEST(testParse_Xep0261_Example3); + CPPUNIT_TEST(testParse_Xep0261_Example9); + CPPUNIT_TEST(testParse_Xep0261_Example13); + + CPPUNIT_TEST(testParse_Xep0234_Example1); + CPPUNIT_TEST(testParse_Xep0234_Example3); + CPPUNIT_TEST(testParse_Xep0234_Example5); + CPPUNIT_TEST(testParse_Xep0234_Example8); + CPPUNIT_TEST(testParse_Xep0234_Example10); + CPPUNIT_TEST(testParse_Xep0234_Example11); + CPPUNIT_TEST(testParse_Xep0234_Example12); + + CPPUNIT_TEST(testParse_Xep0260_Example1); + CPPUNIT_TEST(testParse_Xep0260_Example3); + CPPUNIT_TEST_SUITE_END(); + + public: + //http://xmpp.org/extensions/xep-0166.html#example-3 + void testParse_Xep0166_Example3() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-terminate'\n" + " sid='a73sjjvkla37jfea'>\n" + " <reason>\n" + " <success/>\n" + " </reason>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionTerminate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + CPPUNIT_ASSERT_EQUAL(JinglePayload::Reason::Success, + jingle->getReason().get_value_or(JinglePayload::Reason(JinglePayload::Reason::UnknownType, "")).type); + } + + //http://xmpp.org/extensions/xep-0166.html#example-8 + void testParse_Xep0166_Example8() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-terminate'\n" + " sid='a73sjjvkla37jfea'>\n" + " <reason>\n" + " <success/>\n" + " <text>Sorry, gotta go!</text>\n" + " </reason>\n" + "</jingle>\n" + )); + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionTerminate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + CPPUNIT_ASSERT_EQUAL(JinglePayload::Reason::Success, + jingle->getReason().get_value_or(JinglePayload::Reason(JinglePayload::Reason::UnknownType, "")).type); + CPPUNIT_ASSERT_EQUAL(std::string("Sorry, gotta go!"), + jingle->getReason().get_value_or(JinglePayload::Reason(JinglePayload::Reason::UnknownType, "")).text); + } + + // IBB Transport Method Examples + + // http://xmpp.org/extensions/xep-0261.html#example-1 + void testParse_Xep0261_Example1() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-initiate'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <content creator='initiator' name='ex'>\n" + " <description xmlns='urn:xmpp:example'/>\n" + " <transport xmlns='urn:xmpp:jingle:transports:ibb:1'\n" + " block-size='4096'\n" + " sid='ch3d9s71'/>\n" + " </content>\n" + "</jingle>\n" + )); + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInitiate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + std::vector<JingleContentPayload::ref> payloads = jingle->getContents(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payloads.size()); + JingleContentPayload::ref payload = payloads[0]; + CPPUNIT_ASSERT_EQUAL(JingleContentPayload::InitiatorCreator, payload->getCreator()); + CPPUNIT_ASSERT_EQUAL(std::string("ex"), payload->getName()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payload->getTransports().size()); + + JingleIBBTransportPayload::ref transportPaylod = payload->getTransport<JingleIBBTransportPayload>(); + CPPUNIT_ASSERT(transportPaylod); + CPPUNIT_ASSERT_EQUAL(4096, transportPaylod->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(std::string("ch3d9s71"), transportPaylod->getSessionID()); + } + + // http://xmpp.org/extensions/xep-0261.html#example-1 + void testParse_Xep0261_Example3() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-accept'\n" + " initiator='romeo@montague.lit/orchard'\n" + " responder='juliet@capulet.lit/balcony'\n" + " sid='a73sjjvkla37jfea'>\n" + " <content creator='initiator' name='ex'>\n" + " <description xmlns='urn:xmpp:example'/>\n" + " <transport xmlns='urn:xmpp:jingle:transports:ibb:1'\n" + " block-size='2048'\n" + " sid='ch3d9s71'/>\n" + " </content>\n" + " </jingle>\n" + )); + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionAccept, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), jingle->getResponder()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + std::vector<JingleContentPayload::ref> payloads = jingle->getContents(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payloads.size()); + JingleContentPayload::ref payload = payloads[0]; + CPPUNIT_ASSERT_EQUAL(JingleContentPayload::InitiatorCreator, payload->getCreator()); + CPPUNIT_ASSERT_EQUAL(std::string("ex"), payload->getName()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payload->getTransports().size()); + + JingleIBBTransportPayload::ref transportPaylod = payload->getTransport<JingleIBBTransportPayload>(); + CPPUNIT_ASSERT(transportPaylod); + CPPUNIT_ASSERT_EQUAL(2048, transportPaylod->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(std::string("ch3d9s71"), transportPaylod->getSessionID()); + } + + // http://xmpp.org/extensions/xep-0261.html#example-9 + void testParse_Xep0261_Example9() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='transport-info'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <content creator='initiator' name='ex'>\n" + " <transport xmlns='urn:xmpp:jingle:transports:ibb:1'\n" + " block-size='2048'\n" + " sid='bt8a71h6'/>\n" + " </content>\n" + "</jingle>\n" + )); + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::TransportInfo, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + std::vector<JingleContentPayload::ref> payloads = jingle->getContents(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), payloads.size()); + JingleContentPayload::ref payload = payloads[0]; + CPPUNIT_ASSERT_EQUAL(JingleContentPayload::InitiatorCreator, payload->getCreator()); + CPPUNIT_ASSERT_EQUAL(std::string("ex"), payload->getName()); + + JingleIBBTransportPayload::ref transportPaylod = payload->getTransport<JingleIBBTransportPayload>(); + CPPUNIT_ASSERT(transportPaylod); + CPPUNIT_ASSERT_EQUAL(2048, transportPaylod->getBlockSize()); + CPPUNIT_ASSERT_EQUAL(std::string("bt8a71h6"), transportPaylod->getSessionID()); + } + + // http://xmpp.org/extensions/xep-0261.html#example-13 + void testParse_Xep0261_Example13() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-terminate'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <reason><success/></reason>\n" + " </jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionTerminate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + CPPUNIT_ASSERT_EQUAL(JinglePayload::Reason::Success, jingle->getReason().get_value_or(JinglePayload::Reason()).type); + + } + + // Jingle File Transfer Examples + + // http://xmpp.org/extensions/xep-0234.html#example-1 + void testParse_Xep0234_Example1() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-initiate'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='851ba2'>\n" + " <content creator='initiator' name='a-file-offer'>\n" + " <description xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <offer>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " date='1969-07-21T02:56:15Z'\n" + " hash='552da749930852c69ae5d2141d3766b1'\n" + " name='test.txt'\n" + " size='1022'>\n" + " <desc>This is a test. If this were a real file...</desc>\n" + " <range/>\n" + " </file>\n" + " </offer>\n" + " </description>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " mode='tcp'\n" + " sid='vj3hs98y'>\n" + " <candidate cid='hft54dqy'\n" + " host='192.168.4.1'\n" + " jid='romeo@montague.lit/orchard'\n" + " port='5086'\n" + " priority='8257636'\n" + " type='direct'/>\n" + " <candidate cid='hutr46fe'\n" + " host='24.24.24.1'\n" + " jid='romeo@montague.lit/orchard'\n" + " port='5087'\n" + " priority='8258636'\n" + " type='direct'/>\n" + " </transport>\n" + " </content>\n" + " </jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInitiate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("851ba2"), jingle->getSessionID()); + + std::vector<JingleContentPayload::ref> contents = jingle->getContents(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), contents.size()); + + JingleFileTransferDescription::ref description = contents[0]->getDescription<JingleFileTransferDescription>(); + + + std::vector<StreamInitiationFileInfo> offers = description->getOffers(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), offers.size()); + CPPUNIT_ASSERT_EQUAL(std::string("test.txt"), offers[0].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("552da749930852c69ae5d2141d3766b1"), offers[0].getHash()); + CPPUNIT_ASSERT(1022 == offers[0].getSize()); + CPPUNIT_ASSERT_EQUAL(std::string("This is a test. If this were a real file..."), offers[0].getDescription()); + CPPUNIT_ASSERT_EQUAL(true, offers[0].getSupportsRangeRequests()); + CPPUNIT_ASSERT(stringToDateTime("1969-07-21T02:56:15Z") == offers[0].getDate()); + CPPUNIT_ASSERT_EQUAL(std::string("md5"), offers[0].getAlgo()); + } + + // http://xmpp.org/extensions/xep-0234.html#example-3 + void testParse_Xep0234_Example3() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-accept'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='851ba2'>\n" + " <content creator='initiator' name='a-file-offer'>\n" + " <description xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <offer>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " name='test.txt'\n" + " size='1022'\n" + " hash='552da749930852c69ae5d2141d3766b1'\n" + " date='1969-07-21T02:56:15Z'>\n" + " <desc>This is a test. If this were a real file...</desc>\n" + " <range/>\n" + " </file>\n" + " </offer>\n" + " </description>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " mode='tcp'\n" + " sid='vj3hs98y'>\n" + " <candidate cid='ht567dq'\n" + " host='192.169.1.10'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='6539'\n" + " priority='8257636'\n" + " type='direct'/>\n" + " <candidate cid='hr65dqyd'\n" + " host='134.102.201.180'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='16453'\n" + " priority='7929856'\n" + " type='assisted'/>\n" + " <candidate cid='grt654q2'\n" + " host='2001:638:708:30c9:219:d1ff:fea4:a17d'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='6539'\n" + " priority='8257606'\n" + " type='direct'/>\n" + " </transport>\n" + " </content>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionAccept, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("851ba2"), jingle->getSessionID()); + + std::vector<JingleContentPayload::ref> contents = jingle->getContents(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), contents.size()); + + JingleFileTransferDescription::ref description = contents[0]->getDescription<JingleFileTransferDescription>(); + + + std::vector<StreamInitiationFileInfo> offers = description->getOffers(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), offers.size()); + CPPUNIT_ASSERT_EQUAL(std::string("test.txt"), offers[0].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("552da749930852c69ae5d2141d3766b1"), offers[0].getHash()); + CPPUNIT_ASSERT(1022 == offers[0].getSize()); + CPPUNIT_ASSERT_EQUAL(std::string("This is a test. If this were a real file..."), offers[0].getDescription()); + CPPUNIT_ASSERT_EQUAL(true, offers[0].getSupportsRangeRequests()); + CPPUNIT_ASSERT(stringToDateTime("1969-07-21T02:56:15Z") == offers[0].getDate()); + CPPUNIT_ASSERT_EQUAL(std::string("md5"), offers[0].getAlgo()); + } + + // http://xmpp.org/extensions/xep-0234.html#example-5 + void testParse_Xep0234_Example5() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='transport-info'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <content creator='initiator' name='ex'>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " sid='vj3hs98y'>\n" + " <candidate-used cid='hr65dqyd'/>\n" + " </transport>\n" + " </content>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::TransportInfo, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + std::vector<JingleContentPayload::ref> contents = jingle->getContents(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), contents.size()); + + JingleS5BTransportPayload::ref transport = contents[0]->getTransport<JingleS5BTransportPayload>(); + CPPUNIT_ASSERT(transport); + + CPPUNIT_ASSERT_EQUAL(std::string("vj3hs98y"), transport->getSessionID()); + CPPUNIT_ASSERT_EQUAL(std::string("hr65dqyd"), transport->getCandidateUsed()); + } + + // http://xmpp.org/extensions/xep-0234.html#example-8 + void testParse_Xep0234_Example8() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-info'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <checksum xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <file>\n" + " <hashes xmlns='urn:xmpp:hashes:0'>\n" + " <hash algo='sha-1'>552da749930852c69ae5d2141d3766b1</hash>\n" + " </hashes>\n" + " </file>\n" + " </checksum>\n" + "</jingle>\n" + )); + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInfo, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + JingleFileTransferHash::ref hash = jingle->getPayload<JingleFileTransferHash>(); + CPPUNIT_ASSERT(hash); + CPPUNIT_ASSERT_EQUAL(std::string("552da749930852c69ae5d2141d3766b1"), hash->getHashes().find("sha-1")->second); + + } + + // http://xmpp.org/extensions/xep-0234.html#example-10 + void testParse_Xep0234_Example10() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-initiate'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='uj3b2'>\n" + " <content creator='initiator' name='a-file-request'>\n" + " <description xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <request>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " hash='552da749930852c69ae5d2141d3766b1'>\n" + " <range offset='270336'/>\n" + " </file>\n" + " </request>\n" + " </description>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " mode='tcp'\n" + " sid='xig361fj'>\n" + " <candidate cid='ht567dq'\n" + " host='192.169.1.10'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='6539'\n" + " priority='8257636'\n" + " type='direct'/>\n" + " <candidate cid='hr65dqyd'\n" + " host='134.102.201.180'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='16453'\n" + " priority='7929856'\n" + " type='assisted'/>\n" + " <candidate cid='grt654q2'\n" + " host='2001:638:708:30c9:219:d1ff:fea4:a17d'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='6539'\n" + " priority='8257606'\n" + " type='direct'/>\n" + " </transport>\n" + " </content>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInitiate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("uj3b2"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload<JingleContentPayload>(); + CPPUNIT_ASSERT(content); + + StreamInitiationFileInfo file = content->getDescription<JingleFileTransferDescription>()->getRequests()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("552da749930852c69ae5d2141d3766b1"), file.getHash()); + CPPUNIT_ASSERT_EQUAL(270336, file.getRangeOffset()); + CPPUNIT_ASSERT_EQUAL(true, file.getSupportsRangeRequests()); + } + + // http://xmpp.org/extensions/xep-0234.html#example-11 + void testParse_Xep0234_Example11() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-initiate'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='h2va419i'>\n" + " <content creator='initiator' name='a-file-offer'>\n" + " <description xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <offer>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " date='2011-06-01T15:58:15Z'\n" + " hash='a749930852c69ae5d2141d3766b1552d'\n" + " name='somefile.txt'\n" + " size='1234'/>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " date='2011-06-01T15:58:15Z'\n" + " hash='930852c69ae5d2141d3766b1552da749'\n" + " name='anotherfile.txt'\n" + " size='2345'/>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " date='2011-06-01T15:58:15Z'\n" + " hash='52c69ae5d2141d3766b1552da7499308'\n" + " name='yetanotherfile.txt'\n" + " size='3456'/>\n" + " </offer>\n" + " </description>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " mode='tcp'\n" + " sid='vj3hs98y'>\n" + " <candidate cid='hft54dqy'\n" + " host='192.168.4.1'\n" + " jid='romeo@montague.lit/orchard'\n" + " port='5086'\n" + " priority='8257636'\n" + " type='direct'/>\n" + " <candidate cid='hutr46fe'\n" + " host='24.24.24.1'\n" + " jid='romeo@montague.lit/orchard'\n" + " port='5087'\n" + " priority='8258636'\n" + " type='direct'/>\n" + " </transport>\n" + " </content>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInitiate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("h2va419i"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload<JingleContentPayload>(); + CPPUNIT_ASSERT(content); + CPPUNIT_ASSERT_EQUAL(JingleContentPayload::InitiatorCreator, content->getCreator()); + CPPUNIT_ASSERT_EQUAL(std::string("a-file-offer"), content->getName()); + + std::vector<StreamInitiationFileInfo> offers = content->getDescription<JingleFileTransferDescription>()->getOffers(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), offers.size()); + } + + // http://xmpp.org/extensions/xep-0234.html#example-12 + void testParse_Xep0234_Example12() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-info'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <received xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <file xmlns='http://jabber.org/protocol/si/profile/file-transfer'\n" + " hash='a749930852c69ae5d2141d3766b1552d'/>\n" + " </received>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInfo, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + boost::shared_ptr<JingleFileTransferReceived> received = jingle->getPayload<JingleFileTransferReceived>(); + CPPUNIT_ASSERT(received); + CPPUNIT_ASSERT_EQUAL(std::string("a749930852c69ae5d2141d3766b1552d"), received->getFileInfo().getHash()); + } + + // http://xmpp.org/extensions/xep-0260.html#example-1 + void testParse_Xep0260_Example1() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-initiate'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <content creator='initiator' name='ex'>\n" + " <description xmlns='urn:xmpp:example'/>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " mode='tcp'\n" + " sid='vj3hs98y'>\n" + " <candidate cid='hft54dqy'\n" + " host='192.168.4.1'\n" + " jid='romeo@montague.lit/orchard'\n" + " port='5086'\n" + " priority='8257636'\n" + " type='direct'/>\n" + " <candidate cid='hutr46fe'\n" + " host='24.24.24.1'\n" + " jid='romeo@montague.lit/orchard'\n" + " port='5087'\n" + " priority='8258636'\n" + " type='direct'/>\n" + " </transport>\n" + " </content>\n" + "</jingle>\n" + )); + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionInitiate, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload<JingleContentPayload>(); + CPPUNIT_ASSERT(content); + + JingleS5BTransportPayload::ref s5bPayload = content->getTransport<JingleS5BTransportPayload>(); + CPPUNIT_ASSERT(s5bPayload); + + CPPUNIT_ASSERT_EQUAL(std::string("vj3hs98y"), s5bPayload->getSessionID()); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::TCPMode, s5bPayload->getMode()); + CPPUNIT_ASSERT_EQUAL(false, s5bPayload->hasCandidateError()); + CPPUNIT_ASSERT_EQUAL(false, s5bPayload->hasProxyError()); + CPPUNIT_ASSERT_EQUAL(std::string(), s5bPayload->getActivated()); + CPPUNIT_ASSERT_EQUAL(std::string(), s5bPayload->getCandidateUsed()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), s5bPayload->getCandidates().size()); + + JingleS5BTransportPayload::Candidate candidate; + candidate = s5bPayload->getCandidates()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("hft54dqy"), candidate.cid); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), candidate.jid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("192.168.4.1"), 5086) == candidate.hostPort); + CPPUNIT_ASSERT_EQUAL(8257636, candidate.priority); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::Candidate::DirectType, candidate.type); + + candidate = s5bPayload->getCandidates()[1]; + CPPUNIT_ASSERT_EQUAL(std::string("hutr46fe"), candidate.cid); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), candidate.jid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("24.24.24.1"), 5087) == candidate.hostPort); + CPPUNIT_ASSERT_EQUAL(8258636, candidate.priority); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::Candidate::DirectType, candidate.type); + } + + // http://xmpp.org/extensions/xep-0260.html#example-3 + void testParse_Xep0260_Example3() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<jingle xmlns='urn:xmpp:jingle:1'\n" + " action='session-accept'\n" + " initiator='romeo@montague.lit/orchard'\n" + " sid='a73sjjvkla37jfea'>\n" + " <content creator='initiator' name='ex'>\n" + " <description xmlns='urn:xmpp:example'/>\n" + " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" + " mode='tcp'\n" + " sid='vj3hs98y'>\n" + " <candidate cid='ht567dq'\n" + " host='192.169.1.10'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='6539'\n" + " priority='8257636'\n" + " type='direct'/>\n" + " <candidate cid='hr65dqyd'\n" + " host='134.102.201.180'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='16453'\n" + " priority='7929856'\n" + " type='assisted'/>\n" + " <candidate cid='grt654q2'\n" + " host='2001:638:708:30c9:219:d1ff:fea4:a17d'\n" + " jid='juliet@capulet.lit/balcony'\n" + " port='6539'\n" + " priority='8257606'\n" + " type='direct'/>\n" + " </transport>\n" + " </content>\n" + "</jingle>\n" + )); + + JinglePayload::ref jingle = parser.getPayload<JinglePayload>(); + CPPUNIT_ASSERT(jingle); + CPPUNIT_ASSERT_EQUAL(JinglePayload::SessionAccept, jingle->getAction()); + CPPUNIT_ASSERT_EQUAL(JID("romeo@montague.lit/orchard"), jingle->getInitiator()); + CPPUNIT_ASSERT_EQUAL(std::string("a73sjjvkla37jfea"), jingle->getSessionID()); + + JingleContentPayload::ref content = jingle->getPayload<JingleContentPayload>(); + CPPUNIT_ASSERT(content); + + JingleS5BTransportPayload::ref s5bPayload = content->getTransport<JingleS5BTransportPayload>(); + CPPUNIT_ASSERT(s5bPayload); + + CPPUNIT_ASSERT_EQUAL(std::string("vj3hs98y"), s5bPayload->getSessionID()); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::TCPMode, s5bPayload->getMode()); + CPPUNIT_ASSERT_EQUAL(false, s5bPayload->hasCandidateError()); + CPPUNIT_ASSERT_EQUAL(false, s5bPayload->hasProxyError()); + CPPUNIT_ASSERT_EQUAL(std::string(), s5bPayload->getActivated()); + CPPUNIT_ASSERT_EQUAL(std::string(), s5bPayload->getCandidateUsed()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), s5bPayload->getCandidates().size()); + + JingleS5BTransportPayload::Candidate candidate; + candidate = s5bPayload->getCandidates()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("ht567dq"), candidate.cid); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), candidate.jid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("192.169.1.10"), 6539) == candidate.hostPort); + CPPUNIT_ASSERT_EQUAL(8257636, candidate.priority); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::Candidate::DirectType, candidate.type); + + candidate = s5bPayload->getCandidates()[1]; + CPPUNIT_ASSERT_EQUAL(std::string("hr65dqyd"), candidate.cid); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), candidate.jid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("134.102.201.180"), 16453) == candidate.hostPort); + CPPUNIT_ASSERT_EQUAL(7929856, candidate.priority); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::Candidate::AssistedType, candidate.type); + + candidate = s5bPayload->getCandidates()[2]; + CPPUNIT_ASSERT_EQUAL(std::string("grt654q2"), candidate.cid); + CPPUNIT_ASSERT_EQUAL(JID("juliet@capulet.lit/balcony"), candidate.jid); + CPPUNIT_ASSERT(HostAddressPort(HostAddress("2001:638:708:30c9:219:d1ff:fea4:a17d"), 6539) == candidate.hostPort); + CPPUNIT_ASSERT_EQUAL(8257606, candidate.priority); + CPPUNIT_ASSERT_EQUAL(JingleS5BTransportPayload::Candidate::DirectType, candidate.type); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(JingleParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp new file mode 100644 index 0000000..0648f58 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/MUCAdminPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class MUCAdminPayloadParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MUCAdminPayloadParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + MUCAdminPayloadParserTest() {} + + void testParse() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<query xmlns=\"http://jabber.org/protocol/muc#admin\"><item affiliation=\"owner\" role=\"visitor\"><actor jid=\"kev@tester.lit\"/><reason>malice</reason></item></query>")); + + MUCAdminPayload::ref payload = boost::dynamic_pointer_cast<MUCAdminPayload>(parser.getPayload()); + MUCItem item = payload->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(MUCOccupant::Owner, item.affiliation.get()); + CPPUNIT_ASSERT_EQUAL(MUCOccupant::Visitor, item.role.get()); + CPPUNIT_ASSERT_EQUAL(JID("kev@tester.lit"), item.actor.get()); + CPPUNIT_ASSERT_EQUAL(std::string("malice"), item.reason.get()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MUCAdminPayloadParserTest); + + + diff --git a/Swiften/Parser/PayloadParsers/UnitTest/MUCUserPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/MUCUserPayloadParserTest.cpp new file mode 100644 index 0000000..45862e2 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/MUCUserPayloadParserTest.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Parser/PayloadParsers/MUCUserPayloadParser.h> +#include <Swiften/Elements/MUCDestroyPayload.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class MUCUserPayloadParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MUCUserPayloadParserTest); + CPPUNIT_TEST(testParseEmpty); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST(testParseDestroy); + CPPUNIT_TEST_SUITE_END(); + + public: + MUCUserPayloadParserTest() {} + + void testParse() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<x xmlns=\"http://jabber.org/protocol/muc#user\"><status code='110'/><item affiliation=\"owner\" role=\"visitor\"><actor jid=\"kev@tester.lit\"/><reason>malice</reason></item><status code='210'/></x>")); + + bool found110 = false; + bool found210 = false; + + MUCUserPayload::ref payload = boost::dynamic_pointer_cast<MUCUserPayload>(parser.getPayload()); + + foreach (MUCUserPayload::StatusCode status, payload->getStatusCodes()) { + if (status.code == 110) found110 = true; + if (status.code == 210) found210 = true; + } + + MUCItem item = payload->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(MUCOccupant::Owner, item.affiliation.get()); + CPPUNIT_ASSERT_EQUAL(MUCOccupant::Visitor, item.role.get()); + CPPUNIT_ASSERT_EQUAL(JID("kev@tester.lit"), item.actor.get()); + CPPUNIT_ASSERT_EQUAL(std::string("malice"), item.reason.get()); + CPPUNIT_ASSERT(found110); + CPPUNIT_ASSERT(found210); + } + + void testParseEmpty() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<x xmlns=\"http://jabber.org/protocol/muc#user\"/>")); + + MUCUserPayload::ref payload = boost::dynamic_pointer_cast<MUCUserPayload>(parser.getPayload()); + CPPUNIT_ASSERT(payload); + CPPUNIT_ASSERT(payload->getItems().empty()); + } + + void testParseDestroy() { + PayloadsParserTester parser; + + CPPUNIT_ASSERT(parser.parse("<x xmlns=\"http://jabber.org/protocol/muc#user\"><destroy jid='alice@wonderland.lit'><reason>bert</reason></destroy></x>")); + + MUCUserPayload::ref payload = boost::dynamic_pointer_cast<MUCUserPayload>(parser.getPayload()); + CPPUNIT_ASSERT(payload); + MUCDestroyPayload::ref destroy = boost::dynamic_pointer_cast<MUCDestroyPayload>(payload->getPayload()); + CPPUNIT_ASSERT(destroy); + CPPUNIT_ASSERT_EQUAL(std::string("bert"), destroy->getReason()); + CPPUNIT_ASSERT_EQUAL(JID("alice@wonderland.lit"), destroy->getNewVenue()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MUCUserPayloadParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h index 32fc56c..b0f68ab 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h +++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/UnitTest/ParserTester.h" -#include "Swiften/Parser/PayloadParser.h" +#include <Swiften/Parser/UnitTest/ParserTester.h> +#include <Swiften/Parser/PayloadParser.h> namespace Swift { typedef ParserTester<PayloadParser> PayloadParserTester; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h index 2c88955..213cd06 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h +++ b/Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h @@ -8,12 +8,12 @@ #include <cppunit/extensions/HelperMacros.h> -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Parser/XMLParser.h" -#include "Swiften/Parser/XMLParserClient.h" -#include "Swiften/Parser/PlatformXMLParserFactory.h" -#include "Swiften/Elements/Payload.h" -#include "Swiften/Parser/PayloadParser.h" +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> +#include <Swiften/Parser/XMLParser.h> +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/PlatformXMLParserFactory.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Parser/PayloadParser.h> namespace Swift { class PayloadsParserTester : public XMLParserClient { @@ -62,7 +62,7 @@ namespace Swift { private: XMLParser* xmlParser; FullPayloadParserFactoryCollection factories; - std::auto_ptr<PayloadParser> payloadParser; + boost::shared_ptr<PayloadParser> payloadParser; int level; }; } diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp index 68a2e4f..0974aec 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/PriorityParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/PriorityParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; @@ -24,7 +24,7 @@ class PriorityParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(parser.parse("<priority>-120</priority>")); - Priority::ref payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); + boost::shared_ptr<Priority> payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); CPPUNIT_ASSERT_EQUAL(-120, payload->getPriority()); } @@ -33,7 +33,7 @@ class PriorityParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(parser.parse("<priority>invalid</priority>")); - Priority::ref payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); + boost::shared_ptr<Priority> payload = boost::dynamic_pointer_cast<Priority>(parser.getPayload()); CPPUNIT_ASSERT_EQUAL(0, payload->getPriority()); } }; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp index 867b25f..ef6ed9a 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp @@ -7,10 +7,10 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Elements/Storage.h" -#include "Swiften/Parser/PayloadParsers/PrivateStorageParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" +#include <Swiften/Elements/Storage.h> +#include <Swiften/Parser/PayloadParsers/PrivateStorageParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp index 8885974..4862584 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h" +#include <Swiften/Parser/PayloadParsers/RawXMLPayloadParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp new file mode 100644 index 0000000..c3f410f --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/ReplaceTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/ReplaceParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class ReplaceParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ReplaceParserTest); + CPPUNIT_TEST(testParseTrivial); + CPPUNIT_TEST(testParseChild); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParseTrivial() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<replace id='bad1' xmlns='http://swift.im/protocol/replace'/>")); + Replace::ref payload = boost::dynamic_pointer_cast <Replace>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("bad1"), payload->getID()); + } + void testParseChild() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<replace id='bad1' xmlns='http://swift.im/protocol/replace' ><child xmlns='blah' id=\"hi\"/></replace>")); + Replace::ref payload = boost::dynamic_pointer_cast <Replace>(parser.getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("bad1"), payload->getID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ReplaceParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp index 026ef2c..663a81c 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/ResourceBindParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/ResourceBindParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp new file mode 100644 index 0000000..1a18d6d --- /dev/null +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/PayloadParsers/RosterItemExchangeParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> + +using namespace Swift; + +class RosterItemExchangeParserTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse( + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>")); + + RosterItemExchangePayload* payload = dynamic_cast<RosterItemExchangePayload*>(parser.getPayload().get()); + const RosterItemExchangePayload::RosterItemExchangePayloadItems& items = payload->getItems(); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); + + CPPUNIT_ASSERT_EQUAL(JID("foo@bar.com"), items[0].getJID()); + CPPUNIT_ASSERT_EQUAL(std::string("Foo @ Bar"), items[0].getName()); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Item::Add, items[0].getAction()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items[0].getGroups().size()); + CPPUNIT_ASSERT_EQUAL(std::string("Group 1"), items[0].getGroups()[0]); + CPPUNIT_ASSERT_EQUAL(std::string("Group 2"), items[0].getGroups()[1]); + + CPPUNIT_ASSERT_EQUAL(JID("baz@blo.com"), items[1].getJID()); + CPPUNIT_ASSERT_EQUAL(std::string("Baz"), items[1].getName()); + CPPUNIT_ASSERT_EQUAL(RosterItemExchangePayload::Item::Modify, items[1].getAction()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), items[1].getGroups().size()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp index 1bcea0e..6cb5dbc 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/RosterParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/RosterParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/RosterParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; @@ -17,6 +17,8 @@ class RosterParserTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE(RosterParserTest); CPPUNIT_TEST(testParse); CPPUNIT_TEST(testParse_ItemWithUnknownContent); + CPPUNIT_TEST(testParse_WithVersion); + CPPUNIT_TEST(testParse_WithEmptyVersion); CPPUNIT_TEST_SUITE_END(); public: @@ -32,6 +34,8 @@ class RosterParserTest : public CppUnit::TestFixture "</query>")); RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + + CPPUNIT_ASSERT(!payload->getVersion()); const RosterPayload::RosterItemPayloads& items = payload->getItems(); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), items.size()); @@ -74,6 +78,24 @@ class RosterParserTest : public CppUnit::TestFixture "<baz xmlns=\"jabber:iq:roster\"><fum xmlns=\"jabber:iq:roster\">foo</fum></baz>" ), items[0].getUnknownContent()); } + + void testParse_WithVersion() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<query xmlns='jabber:iq:roster' ver='ver10'/>")); + + RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("ver10"), *payload->getVersion()); + } + + void testParse_WithEmptyVersion() { + PayloadsParserTester parser; + CPPUNIT_ASSERT(parser.parse("<query xmlns='jabber:iq:roster' ver=''/>")); + + RosterPayload* payload = dynamic_cast<RosterPayload*>(parser.getPayload().get()); + CPPUNIT_ASSERT(payload->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *payload->getVersion()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(RosterParserTest); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp index 3d3bc7b..c07cd7f 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" -#include "Swiften/Elements/SearchPayload.h" +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/SearchPayload.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp index 0812c6b..5083a07 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/SecurityLabelParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/SecurityLabelParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp index e1e8594..395daf5 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/SecurityLabelsCatalogParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/SoftwareVersionParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/SoftwareVersionParserTest.cpp index 3689f10..d22d207 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/SoftwareVersionParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/SoftwareVersionParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/SoftwareVersionParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/SoftwareVersionParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/StatusParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/StatusParserTest.cpp index 7791f5f..358ff88 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/StatusParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/StatusParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/StatusParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/StatusParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/StatusShowParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/StatusShowParserTest.cpp index 17617b4..924a87f 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/StatusShowParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/StatusShowParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/StatusShowParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/StatusShowParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp index 88730b7..4fd8ae5 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/StorageParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/StorageParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/StorageParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp index 8001487..63a6c9b 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/StreamInitiationParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" -#include "Swiften/Elements/StreamInitiation.h" +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> +#include <Swiften/Elements/StreamInitiation.h> using namespace Swift; @@ -42,9 +42,9 @@ class StreamInitiationParserTest : public CppUnit::TestFixture { StreamInitiation::ref si = parser.getPayload<StreamInitiation>(); CPPUNIT_ASSERT(si->getIsFileTransfer()); CPPUNIT_ASSERT(si->getFileInfo()); - CPPUNIT_ASSERT_EQUAL(std::string("test.txt"), si->getFileInfo()->name); - CPPUNIT_ASSERT_EQUAL(1022, si->getFileInfo()->size); - CPPUNIT_ASSERT_EQUAL(std::string("This is info about the file."), si->getFileInfo()->description); + CPPUNIT_ASSERT_EQUAL(std::string("test.txt"), si->getFileInfo()->getName()); + CPPUNIT_ASSERT(1022 == si->getFileInfo()->getSize()); + CPPUNIT_ASSERT_EQUAL(std::string("This is info about the file."), si->getFileInfo()->getDescription()); CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(si->getProvidedMethods().size())); CPPUNIT_ASSERT_EQUAL(std::string("http://jabber.org/protocol/bytestreams"), si->getProvidedMethods()[0]); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:oob"), si->getProvidedMethods()[1]); diff --git a/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp index 909401d..f1e6635 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/VCardParserTest.cpp @@ -4,13 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/VCardParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/VCardParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; @@ -93,7 +94,7 @@ class VCardParserTest : public CppUnit::TestFixture { VCard* payload = dynamic_cast<VCard*>(parser.getPayload().get()); CPPUNIT_ASSERT_EQUAL(std::string("image/jpeg"), payload->getPhotoType()); - CPPUNIT_ASSERT_EQUAL(ByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), payload->getPhoto()); + CPPUNIT_ASSERT_EQUAL(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), payload->getPhoto()); } void testParse_Nickname() { diff --git a/Swiften/Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp index b8ea4fb..fe69242 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParsers/VCardUpdateParser.h" -#include "Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h" +#include <Swiften/Parser/PayloadParsers/VCardUpdateParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadsParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/PayloadParsers/VCardParser.cpp b/Swiften/Parser/PayloadParsers/VCardParser.cpp index 61af0ba..553d26a 100644 --- a/Swiften/Parser/PayloadParsers/VCardParser.cpp +++ b/Swiften/Parser/PayloadParsers/VCardParser.cpp @@ -4,10 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/VCardParser.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/StringCodecs/Base64.h" -#include "Swiften/Parser/SerializingParser.h" +#include <Swiften/Parser/PayloadParsers/VCardParser.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Parser/SerializingParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/VCardParser.h b/Swiften/Parser/PayloadParsers/VCardParser.h index c858e61..1475277 100644 --- a/Swiften/Parser/PayloadParsers/VCardParser.h +++ b/Swiften/Parser/PayloadParsers/VCardParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/VCard.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/VCard.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SerializingParser; diff --git a/Swiften/Parser/PayloadParsers/VCardParserFactory.h b/Swiften/Parser/PayloadParsers/VCardParserFactory.h index 305d42e..8731c55 100644 --- a/Swiften/Parser/PayloadParsers/VCardParserFactory.h +++ b/Swiften/Parser/PayloadParsers/VCardParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/VCardParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/VCardParser.h> namespace Swift { class VCardParserFactory : public GenericPayloadParserFactory<VCardParser> { diff --git a/Swiften/Parser/PayloadParsers/VCardUpdateParser.cpp b/Swiften/Parser/PayloadParsers/VCardUpdateParser.cpp index 2218d75..d4703da 100644 --- a/Swiften/Parser/PayloadParsers/VCardUpdateParser.cpp +++ b/Swiften/Parser/PayloadParsers/VCardUpdateParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PayloadParsers/VCardUpdateParser.h" +#include <Swiften/Parser/PayloadParsers/VCardUpdateParser.h> namespace Swift { diff --git a/Swiften/Parser/PayloadParsers/VCardUpdateParser.h b/Swiften/Parser/PayloadParsers/VCardUpdateParser.h index b91c17b..4954f0a 100644 --- a/Swiften/Parser/PayloadParsers/VCardUpdateParser.h +++ b/Swiften/Parser/PayloadParsers/VCardUpdateParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Elements/VCardUpdate.h" -#include "Swiften/Parser/GenericPayloadParser.h" +#include <Swiften/Elements/VCardUpdate.h> +#include <Swiften/Parser/GenericPayloadParser.h> namespace Swift { class SerializingParser; diff --git a/Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h b/Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h index 562f253..8a449fb 100644 --- a/Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h +++ b/Swiften/Parser/PayloadParsers/VCardUpdateParserFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericPayloadParserFactory.h" -#include "Swiften/Parser/PayloadParsers/VCardUpdateParser.h" +#include <Swiften/Parser/GenericPayloadParserFactory.h> +#include <Swiften/Parser/PayloadParsers/VCardUpdateParser.h> namespace Swift { class VCardUpdateParserFactory : public GenericPayloadParserFactory<VCardUpdateParser> { diff --git a/Swiften/Parser/PlatformXMLParserFactory.cpp b/Swiften/Parser/PlatformXMLParserFactory.cpp index 078e562..18acdc2 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.cpp +++ b/Swiften/Parser/PlatformXMLParserFactory.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/PlatformXMLParserFactory.h" +#include <Swiften/Parser/PlatformXMLParserFactory.h> #include <cassert> #ifdef HAVE_LIBXML -#include "Swiften/Parser/LibXMLParser.h" +#include <Swiften/Parser/LibXMLParser.h> #else -#include "Swiften/Parser/ExpatParser.h" +#include <Swiften/Parser/ExpatParser.h> #endif diff --git a/Swiften/Parser/PlatformXMLParserFactory.h b/Swiften/Parser/PlatformXMLParserFactory.h index ea1bfd7..16756ee 100644 --- a/Swiften/Parser/PlatformXMLParserFactory.h +++ b/Swiften/Parser/PlatformXMLParserFactory.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PlatformXMLParserFactory_H -#define SWIFTEN_PlatformXMLParserFactory_H +#pragma once -#include "Swiften/Parser/XMLParserFactory.h" +#include <Swiften/Parser/XMLParserFactory.h> namespace Swift { class PlatformXMLParserFactory : public XMLParserFactory { @@ -17,5 +16,3 @@ namespace Swift { virtual XMLParser* createXMLParser(XMLParserClient*); }; } - -#endif diff --git a/Swiften/Parser/PresenceParser.cpp b/Swiften/Parser/PresenceParser.cpp index 845ccf0..39305c0 100644 --- a/Swiften/Parser/PresenceParser.cpp +++ b/Swiften/Parser/PresenceParser.cpp @@ -5,8 +5,9 @@ */ #include <iostream> +#include <boost/optional.hpp> -#include "Swiften/Parser/PresenceParser.h" +#include <Swiften/Parser/PresenceParser.h> namespace Swift { @@ -15,31 +16,31 @@ PresenceParser::PresenceParser(PayloadParserFactoryCollection* factories) : } void PresenceParser::handleStanzaAttributes(const AttributeMap& attributes) { - AttributeMap::const_iterator type = attributes.find("type"); - if (type != attributes.end()) { - if (type->second == "unavailable") { + boost::optional<std::string> type = attributes.getAttributeValue("type"); + if (type) { + if (*type == "unavailable") { getStanzaGeneric()->setType(Presence::Unavailable); } - else if (type->second == "probe") { + else if (*type == "probe") { getStanzaGeneric()->setType(Presence::Probe); } - else if (type->second == "subscribe") { + else if (*type == "subscribe") { getStanzaGeneric()->setType(Presence::Subscribe); } - else if (type->second == "subscribed") { + else if (*type == "subscribed") { getStanzaGeneric()->setType(Presence::Subscribed); } - else if (type->second == "unsubscribe") { + else if (*type == "unsubscribe") { getStanzaGeneric()->setType(Presence::Unsubscribe); } - else if (type->second == "unsubscribed") { + else if (*type == "unsubscribed") { getStanzaGeneric()->setType(Presence::Unsubscribed); } - else if (type->second == "error") { + else if (*type == "error") { getStanzaGeneric()->setType(Presence::Error); } else { - std::cerr << "Unknown Presence type: " << type->second << std::endl; + std::cerr << "Unknown Presence type: " << *type << std::endl; getStanzaGeneric()->setType(Presence::Available); } } diff --git a/Swiften/Parser/PresenceParser.h b/Swiften/Parser/PresenceParser.h index cfecedf..19f90b3 100644 --- a/Swiften/Parser/PresenceParser.h +++ b/Swiften/Parser/PresenceParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PresenceParser_H -#define SWIFTEN_PresenceParser_H +#pragma once -#include "Swiften/Parser/GenericStanzaParser.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/Parser/GenericStanzaParser.h> +#include <Swiften/Elements/Presence.h> namespace Swift { class PresenceParser : public GenericStanzaParser<Presence> { @@ -19,5 +18,3 @@ namespace Swift { virtual void handleStanzaAttributes(const AttributeMap&); }; } - -#endif diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index cbb2190..2a5d2ee 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -6,6 +6,7 @@ myenv.MergeFlags(swiften_env.get("LIBXML_FLAGS", "")) myenv.MergeFlags(swiften_env.get("EXPAT_FLAGS", "")) sources = [ + "AttributeMap.cpp", "AuthRequestParser.cpp", "AuthChallengeParser.cpp", "AuthSuccessParser.cpp", @@ -25,10 +26,18 @@ sources = [ "PayloadParsers/CapsInfoParser.cpp", "PayloadParsers/DiscoInfoParser.cpp", "PayloadParsers/DiscoItemsParser.cpp", - "PayloadParsers/DelayParserFactory.cpp", "PayloadParsers/ErrorParser.cpp", "PayloadParsers/FormParser.cpp", "PayloadParsers/IBBParser.cpp", + "PayloadParsers/JingleParser.cpp", + "PayloadParsers/JingleReasonParser.cpp", + "PayloadParsers/JingleContentPayloadParser.cpp", + "PayloadParsers/JingleIBBTransportMethodPayloadParser.cpp", + "PayloadParsers/JingleS5BTransportMethodPayloadParser.cpp", + "PayloadParsers/JingleFileTransferDescriptionParser.cpp", + "PayloadParsers/JingleFileTransferReceivedParser.cpp", + "PayloadParsers/JingleFileTransferHashParser.cpp", + "PayloadParsers/StreamInitiationFileInfoParser.cpp", "PayloadParsers/CommandParser.cpp", "PayloadParsers/InBandRegistrationPayloadParser.cpp", "PayloadParsers/SearchPayloadParser.cpp", @@ -37,6 +46,7 @@ sources = [ "PayloadParsers/PrivateStorageParser.cpp", "PayloadParsers/RawXMLPayloadParser.cpp", "PayloadParsers/ResourceBindParser.cpp", + "PayloadParsers/RosterItemExchangeParser.cpp", "PayloadParsers/RosterParser.cpp", "PayloadParsers/SecurityLabelParser.cpp", "PayloadParsers/SecurityLabelsCatalogParser.cpp", @@ -50,13 +60,26 @@ sources = [ "PayloadParsers/VCardUpdateParser.cpp", "PayloadParsers/DelayParser.cpp", "PayloadParsers/MUCUserPayloadParser.cpp", + "PayloadParsers/MUCAdminPayloadParser.cpp", + "PayloadParsers/MUCOwnerPayloadParser.cpp", + "PayloadParsers/MUCDestroyPayloadParser.cpp", + "PayloadParsers/MUCItemParser.cpp", "PayloadParsers/NicknameParser.cpp", + "PayloadParsers/ReplaceParser.cpp", + "PayloadParsers/LastParser.cpp", + "PayloadParsers/S5BProxyRequestParser.cpp", "PlatformXMLParserFactory.cpp", "PresenceParser.cpp", "SerializingParser.cpp", "StanzaParser.cpp", "StreamErrorParser.cpp", "StreamFeaturesParser.cpp", + "StreamManagementEnabledParser.cpp", + "StreamResumeParser.cpp", + "StreamResumedParser.cpp", + "Tree/ParserElement.cpp", + "Tree/NullParserElement.cpp", + "Tree/TreeReparser.cpp", "XMLParser.cpp", "XMLParserClient.cpp", "XMLParserFactory.cpp", diff --git a/Swiften/Parser/SerializingParser.cpp b/Swiften/Parser/SerializingParser.cpp index 43dfc51..cd044cc 100644 --- a/Swiften/Parser/SerializingParser.cpp +++ b/Swiften/Parser/SerializingParser.cpp @@ -4,10 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/SerializingParser.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Base/foreach.h" -#include <iostream> +#include <Swiften/Parser/SerializingParser.h> + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Base/foreach.h> namespace Swift { @@ -15,9 +17,10 @@ SerializingParser::SerializingParser() { } void SerializingParser::handleStartElement(const std::string& tag, const std::string& ns, const AttributeMap& attributes) { - boost::shared_ptr<XMLElement> element(new XMLElement(tag, ns)); - for (AttributeMap::const_iterator i = attributes.begin(); i != attributes.end(); ++i) { - element->setAttribute((*i).first, (*i).second); + boost::shared_ptr<XMLElement> element = boost::make_shared<XMLElement>(tag, ns); + // FIXME: Ignoring attribute namespace + foreach (const AttributeMap::Entry& e, attributes.getEntries()) { + element->setAttribute(e.getAttribute().getName(), e.getValue()); } if (elementStack_.empty()) { @@ -36,7 +39,7 @@ void SerializingParser::handleEndElement(const std::string&, const std::string&) void SerializingParser::handleCharacterData(const std::string& data) { if (!elementStack_.empty()) { - (*(elementStack_.end()-1))->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(data))); + (*(elementStack_.end()-1))->addNode(boost::make_shared<XMLTextNode>(data)); } } diff --git a/Swiften/Parser/SerializingParser.h b/Swiften/Parser/SerializingParser.h index 6276ea0..5f2c0cd 100644 --- a/Swiften/Parser/SerializingParser.h +++ b/Swiften/Parser/SerializingParser.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SerializingParser_H -#define SWIFTEN_SerializingParser_H +#pragma once #include <string> -#include "Swiften/Parser/AttributeMap.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Parser/AttributeMap.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class SerializingParser { @@ -27,5 +26,3 @@ namespace Swift { boost::shared_ptr<XMLElement> rootElement_; }; } - -#endif diff --git a/Swiften/Parser/StanzaAckParser.cpp b/Swiften/Parser/StanzaAckParser.cpp index 9d029cc..1730493 100644 --- a/Swiften/Parser/StanzaAckParser.cpp +++ b/Swiften/Parser/StanzaAckParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/StanzaAckParser.h" +#include <Swiften/Parser/StanzaAckParser.h> #include <boost/lexical_cast.hpp> diff --git a/Swiften/Parser/StanzaAckParser.h b/Swiften/Parser/StanzaAckParser.h index 4078dc1..c188878 100644 --- a/Swiften/Parser/StanzaAckParser.h +++ b/Swiften/Parser/StanzaAckParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StanzaAck.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StanzaAck.h> namespace Swift { class StanzaAckParser : public GenericElementParser<StanzaAck> { diff --git a/Swiften/Parser/StanzaAckRequestParser.h b/Swiften/Parser/StanzaAckRequestParser.h index 82290c6..9a2ccd1 100644 --- a/Swiften/Parser/StanzaAckRequestParser.h +++ b/Swiften/Parser/StanzaAckRequestParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StanzaAckRequest.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StanzaAckRequest.h> namespace Swift { class StanzaAckRequestParser : public GenericElementParser<StanzaAckRequest> { diff --git a/Swiften/Parser/StanzaParser.cpp b/Swiften/Parser/StanzaParser.cpp index 64c4901..271fbf0 100644 --- a/Swiften/Parser/StanzaParser.cpp +++ b/Swiften/Parser/StanzaParser.cpp @@ -4,15 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/StanzaParser.h" +#include <Swiften/Parser/StanzaParser.h> #include <iostream> +#include <boost/optional.hpp> #include <cassert> -#include "Swiften/Parser/PayloadParser.h" -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/UnknownPayloadParser.h" +#include <Swiften/Parser/PayloadParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/UnknownPayloadParser.h> namespace Swift { @@ -26,7 +27,7 @@ StanzaParser::~StanzaParser() { void StanzaParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { if (inStanza()) { if (!inPayload()) { - assert(!currentPayloadParser_.get()); + assert(!currentPayloadParser_); PayloadParserFactory* payloadParserFactory = factories_->getPayloadParserFactory(element, ns, attributes); if (payloadParserFactory) { currentPayloadParser_.reset(payloadParserFactory->createPayloadParser()); @@ -35,21 +36,21 @@ void StanzaParser::handleStartElement(const std::string& element, const std::str currentPayloadParser_.reset(new UnknownPayloadParser()); } } - assert(currentPayloadParser_.get()); + assert(currentPayloadParser_); currentPayloadParser_->handleStartElement(element, ns, attributes); } else { - AttributeMap::const_iterator from = attributes.find("from"); - if (from != attributes.end()) { - getStanza()->setFrom(JID(from->second)); + boost::optional<std::string> from = attributes.getAttributeValue("from"); + if (from) { + getStanza()->setFrom(JID(*from)); } - AttributeMap::const_iterator to = attributes.find("to"); - if (to != attributes.end()) { - getStanza()->setTo(JID(to->second)); + boost::optional<std::string> to = attributes.getAttributeValue("to"); + if (to) { + getStanza()->setTo(JID(*to)); } - AttributeMap::const_iterator id = attributes.find("id"); - if (id != attributes.end()) { - getStanza()->setID(id->second); + boost::optional<std::string> id = attributes.getAttributeValue("id"); + if (id) { + getStanza()->setID(*id); } handleStanzaAttributes(attributes); } @@ -59,7 +60,7 @@ void StanzaParser::handleStartElement(const std::string& element, const std::str void StanzaParser::handleEndElement(const std::string& element, const std::string& ns) { assert(inStanza()); if (inPayload()) { - assert(currentPayloadParser_.get()); + assert(currentPayloadParser_); currentPayloadParser_->handleEndElement(element, ns); --currentDepth_; if (!inPayload()) { @@ -76,7 +77,7 @@ void StanzaParser::handleEndElement(const std::string& element, const std::strin } void StanzaParser::handleCharacterData(const std::string& data) { - if (currentPayloadParser_.get()) { + if (currentPayloadParser_) { currentPayloadParser_->handleCharacterData(data); } } diff --git a/Swiften/Parser/StanzaParser.h b/Swiften/Parser/StanzaParser.h index df01943..6887981 100644 --- a/Swiften/Parser/StanzaParser.h +++ b/Swiften/Parser/StanzaParser.h @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StanzaParser_H -#define SWIFTEN_StanzaParser_H +#pragma once #include <boost/noncopyable.hpp> +#include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Parser/ElementParser.h" -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Parser/ElementParser.h> +#include <Swiften/Parser/AttributeMap.h> namespace Swift { class PayloadParser; @@ -47,8 +47,6 @@ namespace Swift { private: int currentDepth_; PayloadParserFactoryCollection* factories_; - std::auto_ptr<PayloadParser> currentPayloadParser_; + boost::shared_ptr<PayloadParser> currentPayloadParser_; }; } - -#endif diff --git a/Swiften/Parser/StartTLSFailureParser.h b/Swiften/Parser/StartTLSFailureParser.h index 29b2d90..41ecafb 100644 --- a/Swiften/Parser/StartTLSFailureParser.h +++ b/Swiften/Parser/StartTLSFailureParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartTLSFailureParser_H -#define SWIFTEN_StartTLSFailureParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StartTLSFailure.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StartTLSFailure.h> namespace Swift { class StartTLSFailureParser : public GenericElementParser<StartTLSFailure> { @@ -16,5 +15,3 @@ namespace Swift { StartTLSFailureParser() : GenericElementParser<StartTLSFailure>() {} }; } - -#endif diff --git a/Swiften/Parser/StartTLSParser.h b/Swiften/Parser/StartTLSParser.h index 3822c3f..9bc7576 100644 --- a/Swiften/Parser/StartTLSParser.h +++ b/Swiften/Parser/StartTLSParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartTLSParser_H -#define SWIFTEN_StartTLSParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StartTLSRequest.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StartTLSRequest.h> namespace Swift { class StartTLSParser : public GenericElementParser<StartTLSRequest> { @@ -16,5 +15,3 @@ namespace Swift { StartTLSParser() : GenericElementParser<StartTLSRequest>() {} }; } - -#endif diff --git a/Swiften/Parser/StreamFeaturesParser.cpp b/Swiften/Parser/StreamFeaturesParser.cpp index 377f215..6a527ce 100644 --- a/Swiften/Parser/StreamFeaturesParser.cpp +++ b/Swiften/Parser/StreamFeaturesParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/StreamFeaturesParser.h" +#include <Swiften/Parser/StreamFeaturesParser.h> namespace Swift { @@ -31,6 +31,9 @@ void StreamFeaturesParser::handleStartElement(const std::string& element, const else if (element == "compression" && ns == "http://jabber.org/features/compress") { inCompression_ = true; } + else if (element == "ver" && ns == "urn:xmpp:features:rosterver") { + getElementGeneric()->setHasRosterVersioning(); + } } else if (currentDepth_ == 2) { if (inCompression_ && element == "method") { diff --git a/Swiften/Parser/StreamFeaturesParser.h b/Swiften/Parser/StreamFeaturesParser.h index ee65a2a..d55abe9 100644 --- a/Swiften/Parser/StreamFeaturesParser.h +++ b/Swiften/Parser/StreamFeaturesParser.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_STREAMFEATURESPARSER_H -#define SWIFTEN_STREAMFEATURESPARSER_H +#pragma once #include <string> -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StreamFeatures.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamFeatures.h> namespace Swift { class StreamFeaturesParser : public GenericElementParser<StreamFeatures> { @@ -30,5 +29,3 @@ namespace Swift { bool inCompressionMethod_; }; } - -#endif diff --git a/Swiften/Parser/StreamManagementEnabledParser.cpp b/Swiften/Parser/StreamManagementEnabledParser.cpp new file mode 100644 index 0000000..906e071 --- /dev/null +++ b/Swiften/Parser/StreamManagementEnabledParser.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamManagementEnabledParser.h> + +using namespace Swift; + +StreamManagementEnabledParser::StreamManagementEnabledParser() : level(TopLevel) { +} + +StreamManagementEnabledParser::~StreamManagementEnabledParser() { +} + +void StreamManagementEnabledParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + if (attributes.getBoolAttribute("resume", false)) { + getElementGeneric()->setResumeSupported(); + } + getElementGeneric()->setResumeID(attributes.getAttribute("id")); + } + ++level; +} + +void StreamManagementEnabledParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamManagementEnabledParser.h b/Swiften/Parser/StreamManagementEnabledParser.h index adc45ab..db616af 100644 --- a/Swiften/Parser/StreamManagementEnabledParser.h +++ b/Swiften/Parser/StreamManagementEnabledParser.h @@ -1,17 +1,27 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StreamManagementEnabled.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamManagementEnabled.h> namespace Swift { class StreamManagementEnabledParser : public GenericElementParser<StreamManagementEnabled> { public: - StreamManagementEnabledParser() : GenericElementParser<StreamManagementEnabled>() {} + StreamManagementEnabledParser(); + ~StreamManagementEnabledParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; }; } diff --git a/Swiften/Parser/StreamManagementFailedParser.h b/Swiften/Parser/StreamManagementFailedParser.h index 07f5935..6c111d0 100644 --- a/Swiften/Parser/StreamManagementFailedParser.h +++ b/Swiften/Parser/StreamManagementFailedParser.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/StreamManagementFailed.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamManagementFailed.h> namespace Swift { class StreamManagementFailedParser : public GenericElementParser<StreamManagementFailed> { diff --git a/Swiften/Parser/StreamResumeParser.cpp b/Swiften/Parser/StreamResumeParser.cpp new file mode 100644 index 0000000..cb1a61d --- /dev/null +++ b/Swiften/Parser/StreamResumeParser.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamResumeParser.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +StreamResumeParser::StreamResumeParser() : level(TopLevel) { +} + +StreamResumeParser::~StreamResumeParser() { +} + +void StreamResumeParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + boost::optional<std::string> handledStanzasCount = attributes.getAttributeValue("h"); + if (handledStanzasCount) { + try { + getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<unsigned int>(*handledStanzasCount)); + } + catch (const boost::bad_lexical_cast &) { + } + } + getElementGeneric()->setResumeID(attributes.getAttribute("previd")); + } + ++level; +} + +void StreamResumeParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamResumeParser.h b/Swiften/Parser/StreamResumeParser.h new file mode 100644 index 0000000..0ccd24c --- /dev/null +++ b/Swiften/Parser/StreamResumeParser.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamResume.h> + +namespace Swift { + class StreamResumeParser : public GenericElementParser<StreamResume> { + public: + StreamResumeParser(); + ~StreamResumeParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; + }; +} diff --git a/Swiften/Parser/StreamResumedParser.cpp b/Swiften/Parser/StreamResumedParser.cpp new file mode 100644 index 0000000..4b39c04 --- /dev/null +++ b/Swiften/Parser/StreamResumedParser.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/StreamResumedParser.h> + +#include <boost/lexical_cast.hpp> + +using namespace Swift; + +StreamResumedParser::StreamResumedParser() : level(TopLevel) { +} + +StreamResumedParser::~StreamResumedParser() { +} + +void StreamResumedParser::handleStartElement(const std::string&, const std::string&, const AttributeMap& attributes) { + if (level == TopLevel) { + boost::optional<std::string> handledStanzasCount = attributes.getAttributeValue("h"); + if (handledStanzasCount) { + try { + getElementGeneric()->setHandledStanzasCount(boost::lexical_cast<unsigned int>(*handledStanzasCount)); + } + catch (const boost::bad_lexical_cast &) { + } + } + getElementGeneric()->setResumeID(attributes.getAttribute("previd")); + } + ++level; +} + +void StreamResumedParser::handleEndElement(const std::string&, const std::string&) { + --level; +} diff --git a/Swiften/Parser/StreamResumedParser.h b/Swiften/Parser/StreamResumedParser.h new file mode 100644 index 0000000..f2377aa --- /dev/null +++ b/Swiften/Parser/StreamResumedParser.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/StreamResumed.h> + +namespace Swift { + class StreamResumedParser : public GenericElementParser<StreamResumed> { + public: + StreamResumedParser(); + ~StreamResumedParser(); + + virtual void handleStartElement(const std::string&, const std::string&, const AttributeMap&); + virtual void handleEndElement(const std::string&, const std::string&); + + private: + enum Level { + TopLevel = 0 + }; + int level; + }; +} diff --git a/Swiften/Parser/TLSProceedParser.h b/Swiften/Parser/TLSProceedParser.h index 20a44d7..d36f088 100644 --- a/Swiften/Parser/TLSProceedParser.h +++ b/Swiften/Parser/TLSProceedParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_TLSProceedParser_H -#define SWIFTEN_TLSProceedParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/TLSProceed.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/TLSProceed.h> namespace Swift { class TLSProceedParser : public GenericElementParser<TLSProceed> { @@ -16,5 +15,3 @@ namespace Swift { TLSProceedParser() : GenericElementParser<TLSProceed>() {} }; } - -#endif diff --git a/Swiften/Parser/Tree/NullParserElement.cpp b/Swiften/Parser/Tree/NullParserElement.cpp new file mode 100644 index 0000000..7dda9c3 --- /dev/null +++ b/Swiften/Parser/Tree/NullParserElement.cpp @@ -0,0 +1,13 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/Tree/NullParserElement.h> + +namespace Swift { + +boost::shared_ptr<NullParserElement> NullParserElement::element = boost::make_shared<NullParserElement>(); + +} diff --git a/Swiften/Parser/Tree/NullParserElement.h b/Swiften/Parser/Tree/NullParserElement.h new file mode 100644 index 0000000..8dd9bc1 --- /dev/null +++ b/Swiften/Parser/Tree/NullParserElement.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <string> +#include <Swiften/Parser/Tree/ParserElement.h> + +namespace Swift { + class NullParserElement : public ParserElement { + public: + NullParserElement() : ParserElement("", "", AttributeMap()) {} + + virtual operator bool() { return false; } + + static boost::shared_ptr<NullParserElement> element; + }; +} diff --git a/Swiften/Parser/Tree/ParserElement.cpp b/Swiften/Parser/Tree/ParserElement.cpp new file mode 100644 index 0000000..9d9b9b6 --- /dev/null +++ b/Swiften/Parser/Tree/ParserElement.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#include <Swiften/Parser/Tree/ParserElement.h> +#include <Swiften/Parser/Tree/NullParserElement.h> + +#include <iostream> + +namespace Swift{ + +ParserElement::ParserElement(const std::string& name, const std::string& xmlns, const AttributeMap& attributes) : name_(name), xmlns_(xmlns), attributes_(attributes) { +} + +ParserElement::~ParserElement() { +} + +ParserElement::ref ParserElement::addChild(const std::string& name, const std::string& xmlns, const AttributeMap& attributes) { + ParserElement::ref child = boost::make_shared<ParserElement>(name, xmlns, attributes); + children_.push_back(child); + return child; +} + +void ParserElement::appendCharacterData(const std::string& data) { + text_ += data; +} + +struct DoesntMatch { + public: + DoesntMatch(const std::string& tagName, const std::string& ns) : tagName(tagName), ns(ns) {} + bool operator()(ParserElement::ref element) { return element->getName() != tagName || element->getNamespace() != ns; } + private: + std::string tagName; + std::string ns; +}; + + +std::vector<ParserElement::ref> ParserElement::getChildren(const std::string& name, const std::string& xmlns) const { + std::vector<ParserElement::ref> result; + std::remove_copy_if(children_.begin(), children_.end(), std::back_inserter(result), DoesntMatch(name, xmlns)); + return result; +} + +ParserElement::ref ParserElement::getChild(const std::string& name, const std::string& xmlns) const { + std::vector<ParserElement::ref> results = getChildren(name, xmlns); + ParserElement::ref result = results.empty() ? NullParserElement::element : results[0]; + return result; +} + +} diff --git a/Swiften/Parser/Tree/ParserElement.h b/Swiften/Parser/Tree/ParserElement.h new file mode 100644 index 0000000..b268c76 --- /dev/null +++ b/Swiften/Parser/Tree/ParserElement.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + + +#pragma once + +#include <string> +#include <vector> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Parser/AttributeMap.h> +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + class ParserElement { + public: + typedef boost::shared_ptr<ParserElement> ref; + + ParserElement(const std::string& name, const std::string& xmlns, const AttributeMap& attributes); + virtual ~ParserElement(); + + const std::string& getText() const { return text_; } + const std::string& getName() const { return name_; } + const std::string& getNamespace() const { return xmlns_; } + const AttributeMap& getAttributes() const { return attributes_; } + + ParserElement::ref addChild(const std::string& name, const std::string& xmlns, const AttributeMap& attributes); + void appendCharacterData(const std::string& data); + + std::vector<ParserElement::ref> getChildren(const std::string& name, const std::string& xmlns) const; + const std::vector<ParserElement::ref>& getAllChildren() const {return children_;} + ParserElement::ref getChild(const std::string& name, const std::string& xmlns) const; + + virtual operator bool() { + return true; + } + + private: + std::vector<ParserElement::ref> children_; + std::string name_; + std::string xmlns_; + AttributeMap attributes_; + std::string text_; + }; +} diff --git a/Swiften/Parser/Tree/TreeReparser.cpp b/Swiften/Parser/Tree/TreeReparser.cpp new file mode 100644 index 0000000..9d09831 --- /dev/null +++ b/Swiften/Parser/Tree/TreeReparser.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Parser/Tree/TreeReparser.h> + +#include <boost/lexical_cast.hpp> +#include <utility> +#include <deque> + +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParser.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/MUCOccupant.h> + +namespace Swift { + +typedef std::pair<ParserElement::ref, bool> ElementState; + +boost::shared_ptr<Payload> TreeReparser::parseTree(ParserElement::ref root, PayloadParserFactoryCollection* collection) { + PayloadParser* parser = collection->getPayloadParserFactory(root->getName(), root->getNamespace(), root->getAttributes())->createPayloadParser(); + std::deque<ElementState > stack; + stack.push_back(ElementState(root, true)); + while (!stack.empty()) { + ElementState current = stack.back(); + stack.pop_back(); + if (current.second) { + stack.push_back(ElementState(current.first, false)); + parser->handleStartElement(current.first->getName(), current.first->getNamespace(), current.first->getAttributes()); + foreach(ParserElement::ref child, current.first->getAllChildren()) { + stack.push_back(ElementState(child, true)); + } + } else { + parser->handleCharacterData(current.first->getText()); + parser->handleEndElement(current.first->getName(), current.first->getNamespace()); + } + + } + + boost::shared_ptr<Payload> payload = parser->getPayload(); + delete parser; + return payload; +} + +} diff --git a/Swiften/Parser/Tree/TreeReparser.h b/Swiften/Parser/Tree/TreeReparser.h new file mode 100644 index 0000000..212c518 --- /dev/null +++ b/Swiften/Parser/Tree/TreeReparser.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Parser/GenericPayloadTreeParser.h> +#include <Swiften/Parser/PayloadParsers/MUCItemParser.h> + +namespace Swift { + class PayloadParserFactoryCollection; + class TreeReparser { + public: + static boost::shared_ptr<Payload> parseTree(ParserElement::ref root, PayloadParserFactoryCollection* collection); + + }; +} diff --git a/Swiften/Parser/UnitTest/AttributeMapTest.cpp b/Swiften/Parser/UnitTest/AttributeMapTest.cpp index fb68f29..d6c3c01 100644 --- a/Swiften/Parser/UnitTest/AttributeMapTest.cpp +++ b/Swiften/Parser/UnitTest/AttributeMapTest.cpp @@ -7,13 +7,14 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Parser/AttributeMap.h> using namespace Swift; class AttributeMapTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(AttributeMapTest); + CPPUNIT_TEST(testGetAttribute_Namespaced); CPPUNIT_TEST(testGetBoolAttribute_True); CPPUNIT_TEST(testGetBoolAttribute_1); CPPUNIT_TEST(testGetBoolAttribute_False); @@ -24,39 +25,46 @@ class AttributeMapTest : public CppUnit::TestFixture CPPUNIT_TEST_SUITE_END(); public: - AttributeMapTest() {} + void testGetAttribute_Namespaced() { + AttributeMap testling; + testling.addAttribute("lang", "", "nl"); + testling.addAttribute("lang", "http://www.w3.org/XML/1998/namespace", "en"); + testling.addAttribute("lang", "", "fr"); + + CPPUNIT_ASSERT_EQUAL(std::string("en"), testling.getAttribute("lang", "http://www.w3.org/XML/1998/namespace")); + } void testGetBoolAttribute_True() { AttributeMap testling; - testling["foo"] = "true"; + testling.addAttribute("foo", "", "true"); CPPUNIT_ASSERT(testling.getBoolAttribute("foo")); } void testGetBoolAttribute_1() { AttributeMap testling; - testling["foo"] = "1"; + testling.addAttribute("foo", "", "1"); CPPUNIT_ASSERT(testling.getBoolAttribute("foo")); } void testGetBoolAttribute_False() { AttributeMap testling; - testling["foo"] = "false"; + testling.addAttribute("foo", "", "false"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } void testGetBoolAttribute_0() { AttributeMap testling; - testling["foo"] = "0"; + testling.addAttribute("foo", "", "0"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } void testGetBoolAttribute_Invalid() { AttributeMap testling; - testling["foo"] = "bla"; + testling.addAttribute("foo", "", "bla"); CPPUNIT_ASSERT(!testling.getBoolAttribute("foo", true)); } diff --git a/Swiften/Parser/UnitTest/ElementParserTester.h b/Swiften/Parser/UnitTest/ElementParserTester.h index ba39eb7..76b8870 100644 --- a/Swiften/Parser/UnitTest/ElementParserTester.h +++ b/Swiften/Parser/UnitTest/ElementParserTester.h @@ -4,13 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ElementParserTester_H -#define SWIFTEN_ElementParserTester_H +#pragma once -#include "Swiften/Parser/UnitTest/ParserTester.h" + +#include <Swiften/Parser/UnitTest/ParserTester.h> namespace Swift { typedef ParserTester<ElementParser> ElementParserTester; } - -#endif diff --git a/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp b/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp new file mode 100644 index 0000000..d095afc --- /dev/null +++ b/Swiften/Parser/UnitTest/GenericPayloadTreeParserTest.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/GenericPayloadTreeParser.h> +#include <Swiften/Parser/PayloadParsers/UnitTest/PayloadParserTester.h> +#include <Swiften/Elements/RawXMLPayload.h> + +using namespace Swift; + +class GenericPayloadTreeParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(GenericPayloadTreeParserTest); + CPPUNIT_TEST(testTree); + CPPUNIT_TEST_SUITE_END(); + + public: + void testTree() { + MyParser testling; + + std::string data = "<topLevel xmlns='urn:test:top'><firstLevelInheritedEmpty/><firstLevelInherited><secondLevelMultiChildren num='1'/><secondLevelMultiChildren num='2'/></firstLevelInherited><firstLevelNS xmlns='urn:test:first'/></topLevel>"; + + PayloadParserTester tester(&testling); + tester.parse(data); + + ParserElement::ref tree = testling.tree; + + CPPUNIT_ASSERT_EQUAL(std::string("topLevel"), tree->getName()); + CPPUNIT_ASSERT_EQUAL(std::string("urn:test:top"), tree->getNamespace()); + CPPUNIT_ASSERT(tree->getChild("firstLevelInheritedEmpty", "urn:test:top")); + CPPUNIT_ASSERT(!*tree->getChild("firstLevelInheritedEmpty", "")); + CPPUNIT_ASSERT(tree->getChild("firstLevelInherited", "urn:test:top")); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), tree->getChild("firstLevelInherited", "urn:test:top")->getChildren("secondLevelMultiChildren", "urn:test:top").size()); + CPPUNIT_ASSERT_EQUAL(std::string("1"), tree->getChild("firstLevelInherited", "urn:test:top")->getChildren("secondLevelMultiChildren", "urn:test:top")[0]->getAttributes().getAttribute("num")); + CPPUNIT_ASSERT_EQUAL(std::string("2"), tree->getChild("firstLevelInherited", "urn:test:top")->getChildren("secondLevelMultiChildren", "urn:test:top")[1]->getAttributes().getAttribute("num")); + CPPUNIT_ASSERT(tree->getChild("firstLevelNS", "urn:test:first")); + } + + private: + + + class MyParser : public GenericPayloadTreeParser<RawXMLPayload> + { + public: + virtual ~MyParser() {} + virtual void handleTree(ParserElement::ref root) { + tree = root; + } + ParserElement::ref tree; + }; + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(GenericPayloadTreeParserTest); diff --git a/Swiften/Parser/UnitTest/IQParserTest.cpp b/Swiften/Parser/UnitTest/IQParserTest.cpp index 3cc7d45..3c86a5d 100644 --- a/Swiften/Parser/UnitTest/IQParserTest.cpp +++ b/Swiften/Parser/UnitTest/IQParserTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/IQParser.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/UnitTest/StanzaParserTester.h" +#include <Swiften/Parser/IQParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/UnitTest/StanzaParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/UnitTest/MessageParserTest.cpp b/Swiften/Parser/UnitTest/MessageParserTest.cpp index 7615fa3..8ab59ed 100644 --- a/Swiften/Parser/UnitTest/MessageParserTest.cpp +++ b/Swiften/Parser/UnitTest/MessageParserTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/MessageParser.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/UnitTest/StanzaParserTester.h" +#include <Swiften/Parser/MessageParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/UnitTest/StanzaParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/UnitTest/ParserTester.h b/Swiften/Parser/UnitTest/ParserTester.h index 970c1be..73f013c 100644 --- a/Swiften/Parser/UnitTest/ParserTester.h +++ b/Swiften/Parser/UnitTest/ParserTester.h @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ParserTester_H -#define SWIFTEN_ParserTester_H +#pragma once -#include "Swiften/Parser/XMLParserClient.h" -#include "Swiften/Parser/PlatformXMLParserFactory.h" -#include "Swiften/Parser/XMLParser.h" + +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/PlatformXMLParserFactory.h> +#include <Swiften/Parser/XMLParser.h> namespace Swift { class XMLParser; @@ -46,5 +46,3 @@ namespace Swift { ParserType* parser_; }; } - -#endif diff --git a/Swiften/Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp b/Swiften/Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp index 8e49764..fea64e2 100644 --- a/Swiften/Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp +++ b/Swiften/Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/PayloadParserFactory.h" +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/PayloadParserFactory.h> using namespace Swift; diff --git a/Swiften/Parser/UnitTest/PresenceParserTest.cpp b/Swiften/Parser/UnitTest/PresenceParserTest.cpp index f68db40..f9d6cf6 100644 --- a/Swiften/Parser/UnitTest/PresenceParserTest.cpp +++ b/Swiften/Parser/UnitTest/PresenceParserTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/PresenceParser.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/UnitTest/StanzaParserTester.h" +#include <Swiften/Parser/PresenceParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/UnitTest/StanzaParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/UnitTest/SerializingParserTest.cpp b/Swiften/Parser/UnitTest/SerializingParserTest.cpp index c0af493..aef1dfb 100644 --- a/Swiften/Parser/UnitTest/SerializingParserTest.cpp +++ b/Swiften/Parser/UnitTest/SerializingParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/SerializingParser.h" -#include "Swiften/Parser/UnitTest/StanzaParserTester.h" +#include <Swiften/Parser/SerializingParser.h> +#include <Swiften/Parser/UnitTest/StanzaParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp b/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp index b90af6e..b68fb30 100644 --- a/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp +++ b/Swiften/Parser/UnitTest/StanzaAckParserTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/StanzaAckParser.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Parser/UnitTest/ElementParserTester.h" +#include <Swiften/Parser/StanzaAckParser.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Parser/UnitTest/ElementParserTester.h> using namespace Swift; diff --git a/Swiften/Parser/UnitTest/StanzaParserTest.cpp b/Swiften/Parser/UnitTest/StanzaParserTest.cpp index d57f798..b2ddb39 100644 --- a/Swiften/Parser/UnitTest/StanzaParserTest.cpp +++ b/Swiften/Parser/UnitTest/StanzaParserTest.cpp @@ -7,12 +7,12 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/StanzaParser.h" -#include "Swiften/Parser/GenericPayloadParser.h" -#include "Swiften/Parser/PayloadParserFactory.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Parser/StanzaParser.h> +#include <Swiften/Parser/GenericPayloadParser.h> +#include <Swiften/Parser/PayloadParserFactory.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Elements/Payload.h> using namespace Swift; @@ -40,8 +40,8 @@ class StanzaParserTest : public CppUnit::TestFixture { MyStanzaParser testling(factoryCollection_); AttributeMap attributes; - attributes["foo"] = "fum"; - attributes["bar"] = "baz"; + attributes.addAttribute("foo", "", "fum"); + attributes.addAttribute("bar", "", "baz"); testling.handleStartElement("mystanza", "", attributes); testling.handleStartElement("mypayload1", "", attributes); testling.handleStartElement("child", "", attributes); @@ -107,9 +107,9 @@ class StanzaParserTest : public CppUnit::TestFixture { MyStanzaParser testling(factoryCollection_); AttributeMap attributes; - attributes["to"] = "foo@example.com/blo"; - attributes["from"] = "bar@example.com/baz"; - attributes["id"] = "id-123"; + attributes.addAttribute("to", "", "foo@example.com/blo"); + attributes.addAttribute("from", "", "bar@example.com/baz"); + attributes.addAttribute("id", "", "id-123"); testling.handleStartElement("mystanza", "", attributes); testling.handleEndElement("mypayload1", ""); diff --git a/Swiften/Parser/UnitTest/StanzaParserTester.h b/Swiften/Parser/UnitTest/StanzaParserTester.h index eb3a18b..e4ce48e 100644 --- a/Swiften/Parser/UnitTest/StanzaParserTester.h +++ b/Swiften/Parser/UnitTest/StanzaParserTester.h @@ -4,14 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StanzaParserTester_H -#define SWIFTEN_StanzaParserTester_H +#pragma once -#include "Swiften/Parser/StanzaParser.h" -#include "Swiften/Parser/UnitTest/ParserTester.h" +#include <Swiften/Parser/StanzaParser.h> +#include <Swiften/Parser/UnitTest/ParserTester.h> namespace Swift { typedef ParserTester<StanzaParser> StanzaParserTester; } - -#endif diff --git a/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp b/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp index 1cdaf54..4bc971f 100644 --- a/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp +++ b/Swiften/Parser/UnitTest/StreamFeaturesParserTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Parser/StreamFeaturesParser.h" -#include "Swiften/Parser/UnitTest/ElementParserTester.h" +#include <Swiften/Parser/StreamFeaturesParser.h> +#include <Swiften/Parser/UnitTest/ElementParserTester.h> using namespace Swift; @@ -37,6 +37,7 @@ class StreamFeaturesParserTest : public CppUnit::TestFixture { "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>" "<sm xmlns='urn:xmpp:sm:2'/>" "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>" + "<ver xmlns=\"urn:xmpp:features:rosterver\"/>" "</stream:features>")); StreamFeatures::ref element = boost::dynamic_pointer_cast<StreamFeatures>(testling.getElement()); @@ -49,6 +50,7 @@ class StreamFeaturesParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT(element->hasAuthenticationMechanism("DIGEST-MD5")); CPPUNIT_ASSERT(element->hasAuthenticationMechanism("PLAIN")); CPPUNIT_ASSERT(element->hasStreamManagement()); + CPPUNIT_ASSERT(element->hasRosterVersioning()); } void testParse_Empty() { diff --git a/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp b/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp new file mode 100644 index 0000000..07b7b31 --- /dev/null +++ b/Swiften/Parser/UnitTest/StreamManagementEnabledParserTest.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Parser/StreamManagementEnabledParser.h> +#include <Swiften/Parser/UnitTest/ElementParserTester.h> + +using namespace Swift; + +class StreamManagementEnabledParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(StreamManagementEnabledParserTest); + CPPUNIT_TEST(testParse); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse() { + StreamManagementEnabledParser testling; + ElementParserTester parser(&testling); + + CPPUNIT_ASSERT(parser.parse( + "<enabled xmlns=\"urn:xmpp:sm:3\" id=\"some-long-sm-id\" resume=\"true\"/>")); + + boost::shared_ptr<StreamManagementEnabled> element = boost::dynamic_pointer_cast<StreamManagementEnabled>(testling.getElement()); + CPPUNIT_ASSERT(element->getResumeSupported()); + CPPUNIT_ASSERT_EQUAL(std::string("some-long-sm-id"), element->getResumeID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(StreamManagementEnabledParserTest); diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 2086ece..8ff56c0 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -9,12 +9,12 @@ #include <vector> #include <string> -#include "Swiften/Parser/XMLParserClient.h" +#include <Swiften/Parser/XMLParserClient.h> #ifdef HAVE_EXPAT -#include "Swiften/Parser/ExpatParser.h" +#include <Swiften/Parser/ExpatParser.h> #endif #ifdef HAVE_LIBXML -#include "Swiften/Parser/LibXMLParser.h" +#include <Swiften/Parser/LibXMLParser.h> #endif using namespace Swift; @@ -32,6 +32,8 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_TEST(testParse_InErrorState); CPPUNIT_TEST(testParse_Incremental); CPPUNIT_TEST(testParse_WhitespaceInAttribute); + CPPUNIT_TEST(testParse_AttributeWithoutNamespace); + CPPUNIT_TEST(testParse_AttributeWithNamespace); CPPUNIT_TEST(testParse_BillionLaughs); CPPUNIT_TEST_SUITE_END(); @@ -48,13 +50,13 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.size()); - CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes["type"]); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes.getAttribute("type")); CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[0].ns); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); @@ -78,7 +80,7 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); @@ -228,6 +230,28 @@ class XMLParserTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[2].data); } + void testParse_AttributeWithoutNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + } + + void testParse_AttributeWithNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' f:attr='3'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + } + void testParse_BillionLaughs() { ParserType testling(&client_); @@ -246,7 +270,6 @@ class XMLParserTest : public CppUnit::TestFixture { "]>" "<lolz>&lol9;</lolz>" )); - } private: diff --git a/Swiften/Parser/UnitTest/XMPPParserTest.cpp b/Swiften/Parser/UnitTest/XMPPParserTest.cpp index 8ce96d8..dbee18a 100644 --- a/Swiften/Parser/UnitTest/XMPPParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMPPParserTest.cpp @@ -8,17 +8,17 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <vector> -#include "Swiften/Elements/ProtocolHeader.h" +#include <Swiften/Elements/ProtocolHeader.h> #include <string> -#include "Swiften/Parser/XMPPParser.h" -#include "Swiften/Parser/ElementParser.h" -#include "Swiften/Parser/XMPPParserClient.h" -#include "Swiften/Parser/PayloadParserFactoryCollection.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/StreamFeatures.h" -#include "Swiften/Elements/UnknownElement.h" +#include <Swiften/Parser/XMPPParser.h> +#include <Swiften/Parser/ElementParser.h> +#include <Swiften/Parser/XMPPParserClient.h> +#include <Swiften/Parser/PayloadParserFactoryCollection.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/StreamFeatures.h> +#include <Swiften/Elements/UnknownElement.h> using namespace Swift; diff --git a/Swiften/Parser/UnknownElementParser.h b/Swiften/Parser/UnknownElementParser.h index 6ff885f..59133de 100644 --- a/Swiften/Parser/UnknownElementParser.h +++ b/Swiften/Parser/UnknownElementParser.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_UnknownElementParser_H -#define SWIFTEN_UnknownElementParser_H +#pragma once -#include "Swiften/Parser/GenericElementParser.h" -#include "Swiften/Elements/UnknownElement.h" +#include <Swiften/Parser/GenericElementParser.h> +#include <Swiften/Elements/UnknownElement.h> namespace Swift { class UnknownElementParser : public GenericElementParser<UnknownElement> { @@ -16,5 +15,3 @@ namespace Swift { UnknownElementParser() : GenericElementParser<UnknownElement>() {} }; } - -#endif diff --git a/Swiften/Parser/UnknownPayloadParser.h b/Swiften/Parser/UnknownPayloadParser.h index 8750f22..0843f41 100644 --- a/Swiften/Parser/UnknownPayloadParser.h +++ b/Swiften/Parser/UnknownPayloadParser.h @@ -4,16 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_UNKNOWNPAYLOADPARSER_H -#define SWIFTEN_UNKNOWNPAYLOADPARSER_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Parser/PayloadParser.h" +#include <Swiften/Parser/PayloadParser.h> namespace Swift { - - class UnknownPayloadParser : public PayloadParser { public: UnknownPayloadParser() {} @@ -27,5 +24,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Parser/XMLParser.cpp b/Swiften/Parser/XMLParser.cpp index a2e73fc..cd7baea 100644 --- a/Swiften/Parser/XMLParser.cpp +++ b/Swiften/Parser/XMLParser.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/XMLParser.h" +#include <Swiften/Parser/XMLParser.h> namespace Swift { diff --git a/Swiften/Parser/XMLParserClient.cpp b/Swiften/Parser/XMLParserClient.cpp index c0e7853..46d57b7 100644 --- a/Swiften/Parser/XMLParserClient.cpp +++ b/Swiften/Parser/XMLParserClient.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/XMLParserClient.h" +#include <Swiften/Parser/XMLParserClient.h> namespace Swift { diff --git a/Swiften/Parser/XMLParserClient.h b/Swiften/Parser/XMLParserClient.h index 089ef35..ff706a0 100644 --- a/Swiften/Parser/XMLParserClient.h +++ b/Swiften/Parser/XMLParserClient.h @@ -7,7 +7,7 @@ #ifndef XMLPARSERCLIENT_H #define XMLPARSERCLIENT_H -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Parser/AttributeMap.h> namespace Swift { diff --git a/Swiften/Parser/XMLParserFactory.cpp b/Swiften/Parser/XMLParserFactory.cpp index 9da0747..af719bf 100644 --- a/Swiften/Parser/XMLParserFactory.cpp +++ b/Swiften/Parser/XMLParserFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/XMLParserFactory.h" +#include <Swiften/Parser/XMLParserFactory.h> namespace Swift { diff --git a/Swiften/Parser/XMLParserFactory.h b/Swiften/Parser/XMLParserFactory.h index 369c454..32665cb 100644 --- a/Swiften/Parser/XMLParserFactory.h +++ b/Swiften/Parser/XMLParserFactory.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_XMLParserFactory_H -#define SWIFTEN_XMLParserFactory_H +#pragma once namespace Swift { class XMLParser; @@ -18,5 +17,3 @@ namespace Swift { virtual XMLParser* createXMLParser(XMLParserClient*) = 0; }; } - -#endif diff --git a/Swiften/Parser/XMPPParser.cpp b/Swiften/Parser/XMPPParser.cpp index 1fb7682..6779b86 100644 --- a/Swiften/Parser/XMPPParser.cpp +++ b/Swiften/Parser/XMPPParser.cpp @@ -4,41 +4,43 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/XMPPParser.h" +#include <Swiften/Parser/XMPPParser.h> #include <iostream> #include <cassert> -#include "Swiften/Elements/ProtocolHeader.h" +#include <Swiften/Elements/ProtocolHeader.h> #include <string> -#include "Swiften/Parser/XMLParser.h" -#include "Swiften/Parser/PlatformXMLParserFactory.h" -#include "Swiften/Parser/XMPPParserClient.h" -#include "Swiften/Parser/XMPPParser.h" -#include "Swiften/Parser/ElementParser.h" -#include "Swiften/Parser/PresenceParser.h" -#include "Swiften/Parser/IQParser.h" -#include "Swiften/Parser/MessageParser.h" -#include "Swiften/Parser/StreamFeaturesParser.h" -#include "Swiften/Parser/StreamErrorParser.h" -#include "Swiften/Parser/AuthRequestParser.h" -#include "Swiften/Parser/AuthSuccessParser.h" -#include "Swiften/Parser/AuthFailureParser.h" -#include "Swiften/Parser/AuthChallengeParser.h" -#include "Swiften/Parser/AuthResponseParser.h" -#include "Swiften/Parser/EnableStreamManagementParser.h" -#include "Swiften/Parser/StreamManagementEnabledParser.h" -#include "Swiften/Parser/StreamManagementFailedParser.h" -#include "Swiften/Parser/StanzaAckParser.h" -#include "Swiften/Parser/StanzaAckRequestParser.h" -#include "Swiften/Parser/StartTLSParser.h" -#include "Swiften/Parser/StartTLSFailureParser.h" -#include "Swiften/Parser/CompressParser.h" -#include "Swiften/Parser/CompressFailureParser.h" -#include "Swiften/Parser/CompressedParser.h" -#include "Swiften/Parser/UnknownElementParser.h" -#include "Swiften/Parser/TLSProceedParser.h" -#include "Swiften/Parser/ComponentHandshakeParser.h" +#include <Swiften/Parser/XMLParser.h> +#include <Swiften/Parser/PlatformXMLParserFactory.h> +#include <Swiften/Parser/XMPPParserClient.h> +#include <Swiften/Parser/XMPPParser.h> +#include <Swiften/Parser/ElementParser.h> +#include <Swiften/Parser/PresenceParser.h> +#include <Swiften/Parser/IQParser.h> +#include <Swiften/Parser/MessageParser.h> +#include <Swiften/Parser/StreamFeaturesParser.h> +#include <Swiften/Parser/StreamErrorParser.h> +#include <Swiften/Parser/AuthRequestParser.h> +#include <Swiften/Parser/AuthSuccessParser.h> +#include <Swiften/Parser/AuthFailureParser.h> +#include <Swiften/Parser/AuthChallengeParser.h> +#include <Swiften/Parser/AuthResponseParser.h> +#include <Swiften/Parser/EnableStreamManagementParser.h> +#include <Swiften/Parser/StreamManagementEnabledParser.h> +#include <Swiften/Parser/StreamManagementFailedParser.h> +#include <Swiften/Parser/StreamResumeParser.h> +#include <Swiften/Parser/StreamResumedParser.h> +#include <Swiften/Parser/StanzaAckParser.h> +#include <Swiften/Parser/StanzaAckRequestParser.h> +#include <Swiften/Parser/StartTLSParser.h> +#include <Swiften/Parser/StartTLSFailureParser.h> +#include <Swiften/Parser/CompressParser.h> +#include <Swiften/Parser/CompressFailureParser.h> +#include <Swiften/Parser/CompressedParser.h> +#include <Swiften/Parser/UnknownElementParser.h> +#include <Swiften/Parser/TLSProceedParser.h> +#include <Swiften/Parser/ComponentHandshakeParser.h> // TODO: Whenever an error occurs in the handlers, stop the parser by returing // a bool value, and stopping the XML parser @@ -182,6 +184,12 @@ ElementParser* XMPPParser::createElementParser(const std::string& element, const else if (element == "failed" && ns == "urn:xmpp:sm:2") { return new StreamManagementFailedParser(); } + else if (element == "resume" && ns == "urn:xmpp:sm:2") { + return new StreamResumeParser(); + } + else if (element == "resumed" && ns == "urn:xmpp:sm:2") { + return new StreamResumedParser(); + } else if (element == "a" && ns == "urn:xmpp:sm:2") { return new StanzaAckParser(); } diff --git a/Swiften/Parser/XMPPParser.h b/Swiften/Parser/XMPPParser.h index 8a00995..b5d6d24 100644 --- a/Swiften/Parser/XMPPParser.h +++ b/Swiften/Parser/XMPPParser.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_XMPPPARSER_H -#define SWIFTEN_XMPPPARSER_H +#pragma once #include <boost/shared_ptr.hpp> #include <boost/noncopyable.hpp> -#include "Swiften/Parser/XMLParserClient.h" -#include "Swiften/Parser/AttributeMap.h" +#include <Swiften/Parser/XMLParserClient.h> +#include <Swiften/Parser/AttributeMap.h> namespace Swift { class XMLParser; @@ -53,5 +52,3 @@ namespace Swift { bool parseErrorOccurred_; }; } - -#endif diff --git a/Swiften/Parser/XMPPParserClient.cpp b/Swiften/Parser/XMPPParserClient.cpp index 3761e4f..4b7da04 100644 --- a/Swiften/Parser/XMPPParserClient.cpp +++ b/Swiften/Parser/XMPPParserClient.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Parser/XMPPParserClient.h" +#include <Swiften/Parser/XMPPParserClient.h> namespace Swift { diff --git a/Swiften/Parser/XMPPParserClient.h b/Swiften/Parser/XMPPParserClient.h index 1ddb86d..e613f8e 100644 --- a/Swiften/Parser/XMPPParserClient.h +++ b/Swiften/Parser/XMPPParserClient.h @@ -8,7 +8,7 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> namespace Swift { diff --git a/Swiften/Presence/DirectedPresenceSender.cpp b/Swiften/Presence/DirectedPresenceSender.cpp index d824554..ec0bd3f 100644 --- a/Swiften/Presence/DirectedPresenceSender.cpp +++ b/Swiften/Presence/DirectedPresenceSender.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Presence/DirectedPresenceSender.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/Base/foreach.h> namespace Swift { diff --git a/Swiften/Presence/DirectedPresenceSender.h b/Swiften/Presence/DirectedPresenceSender.h index 207de3e..7dbdd37 100644 --- a/Swiften/Presence/DirectedPresenceSender.h +++ b/Swiften/Presence/DirectedPresenceSender.h @@ -8,8 +8,8 @@ #include <set> -#include "Swiften/Elements/Presence.h" -#include "Swiften/Presence/PresenceSender.h" +#include <Swiften/Elements/Presence.h> +#include <Swiften/Presence/PresenceSender.h> namespace Swift { class DirectedPresenceSender : public PresenceSender { diff --git a/Swiften/Presence/PayloadAddingPresenceSender.cpp b/Swiften/Presence/PayloadAddingPresenceSender.cpp index c3d1638..5e8cd81 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.cpp +++ b/Swiften/Presence/PayloadAddingPresenceSender.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Presence/PayloadAddingPresenceSender.h" +#include <Swiften/Presence/PayloadAddingPresenceSender.h> namespace Swift { @@ -34,11 +34,15 @@ bool PayloadAddingPresenceSender::isAvailable() const { return sender->isAvailable(); } -void PayloadAddingPresenceSender::setPayload(Payload::ref payload) { +void PayloadAddingPresenceSender::setPayload(boost::shared_ptr<Payload> payload) { this->payload = payload; if (lastSentPresence) { sendPresence(lastSentPresence); } } +void PayloadAddingPresenceSender::reset() { + lastSentPresence.reset(); +} + } diff --git a/Swiften/Presence/PayloadAddingPresenceSender.h b/Swiften/Presence/PayloadAddingPresenceSender.h index ae82970..333842a 100644 --- a/Swiften/Presence/PayloadAddingPresenceSender.h +++ b/Swiften/Presence/PayloadAddingPresenceSender.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Presence/PresenceSender.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Presence/PresenceSender.h> +#include <Swiften/Elements/Payload.h> namespace Swift { class StanzaChannel; @@ -21,20 +21,28 @@ namespace Swift { public: PayloadAddingPresenceSender(PresenceSender*); - void sendPresence(Presence::ref); + void sendPresence(boost::shared_ptr<Presence>); bool isAvailable() const; /** * Sets the payload to be added to outgoing presences. * If initial presence has been sent, this will resend the last sent presence * with an updated payload. Initial presence is reset when unavailable presence is - * sent. + * sent, or when reset() is called. */ - void setPayload(Payload::ref); + void setPayload(boost::shared_ptr<Payload>); + + /** + * Resets the presence sender. + * This puts the presence sender back in the initial state (before initial + * presence has been sent). + * This also resets the chained sender. + */ + void reset(); private: - Presence::ref lastSentPresence; + boost::shared_ptr<Presence> lastSentPresence; PresenceSender* sender; - Payload::ref payload; + boost::shared_ptr<Payload> payload; }; } diff --git a/Swiften/Presence/PresenceOracle.cpp b/Swiften/Presence/PresenceOracle.cpp index 90e403c..bfb5a3d 100644 --- a/Swiften/Presence/PresenceOracle.cpp +++ b/Swiften/Presence/PresenceOracle.cpp @@ -8,7 +8,7 @@ #include <boost/bind.hpp> -#include "Swiften/Client/StanzaChannel.h" +#include <Swiften/Client/StanzaChannel.h> namespace Swift { @@ -84,7 +84,7 @@ std::vector<Presence::ref> PresenceOracle::getAllPresence(const JID& bareJID) co } PresenceMap presenceMap = i->second; PresenceMap::const_iterator j = presenceMap.begin(); - for (; j != presenceMap.end(); j++) { + for (; j != presenceMap.end(); ++j) { Presence::ref current = j->second; results.push_back(current); } @@ -99,7 +99,7 @@ Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) con PresenceMap presenceMap = i->second; PresenceMap::const_iterator j = presenceMap.begin(); Presence::ref highest; - for (; j != presenceMap.end(); j++) { + for (; j != presenceMap.end(); ++j) { Presence::ref current = j->second; if (!highest || current->getPriority() > highest->getPriority() diff --git a/Swiften/Presence/PresenceOracle.h b/Swiften/Presence/PresenceOracle.h index f98e1cd..09126ea 100644 --- a/Swiften/Presence/PresenceOracle.h +++ b/Swiften/Presence/PresenceOracle.h @@ -9,9 +9,9 @@ #include <map> #include <string> -#include "Swiften/Elements/Presence.h" +#include <Swiften/Elements/Presence.h> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class StanzaChannel; diff --git a/Swiften/Presence/PresenceSender.cpp b/Swiften/Presence/PresenceSender.cpp index 50d75eb..b75141d 100644 --- a/Swiften/Presence/PresenceSender.cpp +++ b/Swiften/Presence/PresenceSender.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Presence/PresenceSender.h" +#include <Swiften/Presence/PresenceSender.h> namespace Swift { diff --git a/Swiften/Presence/PresenceSender.h b/Swiften/Presence/PresenceSender.h index 5abf2f3..c302074 100644 --- a/Swiften/Presence/PresenceSender.h +++ b/Swiften/Presence/PresenceSender.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Elements/Presence.h" +#include <Swiften/Elements/Presence.h> namespace Swift { class PresenceSender { diff --git a/Swiften/Presence/StanzaChannelPresenceSender.cpp b/Swiften/Presence/StanzaChannelPresenceSender.cpp index 654b7e7..5863a2d 100644 --- a/Swiften/Presence/StanzaChannelPresenceSender.cpp +++ b/Swiften/Presence/StanzaChannelPresenceSender.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Presence/StanzaChannelPresenceSender.h" -#include "Swiften/Client/StanzaChannel.h" +#include <Swiften/Presence/StanzaChannelPresenceSender.h> +#include <Swiften/Client/StanzaChannel.h> namespace Swift { diff --git a/Swiften/Presence/StanzaChannelPresenceSender.h b/Swiften/Presence/StanzaChannelPresenceSender.h index 23230ab..d60d29d 100644 --- a/Swiften/Presence/StanzaChannelPresenceSender.h +++ b/Swiften/Presence/StanzaChannelPresenceSender.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Presence/PresenceSender.h" +#include <Swiften/Presence/PresenceSender.h> namespace Swift { class StanzaChannel; diff --git a/Swiften/Presence/SubscriptionManager.cpp b/Swiften/Presence/SubscriptionManager.cpp index 004309e..01525dd 100644 --- a/Swiften/Presence/SubscriptionManager.cpp +++ b/Swiften/Presence/SubscriptionManager.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Presence/SubscriptionManager.h" +#include <Swiften/Presence/SubscriptionManager.h> #include <boost/bind.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Client/StanzaChannel.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Client/StanzaChannel.h> namespace Swift { diff --git a/Swiften/Presence/SubscriptionManager.h b/Swiften/Presence/SubscriptionManager.h index ad55f9d..efa3e1c 100644 --- a/Swiften/Presence/SubscriptionManager.h +++ b/Swiften/Presence/SubscriptionManager.h @@ -9,9 +9,9 @@ #include <map> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/Base/boost_bsignals.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Presence.h> namespace Swift { class StanzaChannel; diff --git a/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp b/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp index 80f5ebd..5b385c2 100644 --- a/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp +++ b/Swiften/Presence/UnitTest/DirectedPresenceSenderTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Presence/DirectedPresenceSender.h" -#include "Swiften/Presence/StanzaChannelPresenceSender.h" +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/Presence/StanzaChannelPresenceSender.h> using namespace Swift; @@ -41,7 +41,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testSendPresence() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->sendPresence(testPresence); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(channel->sentStanzas.size())); @@ -50,7 +50,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testSendPresence_UndirectedPresenceWithDirectedPresenceReceivers() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); testling->sendPresence(testPresence); @@ -64,7 +64,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testSendPresence_DirectedPresenceWithDirectedPresenceReceivers() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); channel->sentStanzas.clear(); @@ -77,7 +77,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testAddDirectedPresenceReceiver() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->sendPresence(testPresence); channel->sentStanzas.clear(); @@ -90,7 +90,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testAddDirectedPresenceReceiver_WithoutSendingPresence() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->sendPresence(testPresence); channel->sentStanzas.clear(); @@ -100,7 +100,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testAddDirectedPresenceReceiver_AfterSendingDirectedPresence() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->sendPresence(testPresence); secondTestPresence->setTo(JID("foo@bar.com")); testling->sendPresence(secondTestPresence); @@ -115,7 +115,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testRemoveDirectedPresenceReceiver() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::DontSendPresence); testling->removeDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); @@ -127,7 +127,7 @@ class DirectedPresenceSenderTest : public CppUnit::TestFixture { } void testRemoveDirectedPresenceReceiver_WithoutSendingPresence() { - std::auto_ptr<DirectedPresenceSender> testling(createPresenceSender()); + boost::shared_ptr<DirectedPresenceSender> testling(createPresenceSender()); testling->addDirectedPresenceReceiver(JID("alice@wonderland.lit/teaparty"), DirectedPresenceSender::AndSendPresence); channel->sentStanzas.clear(); diff --git a/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp b/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp index 132c865..3a6ab31 100644 --- a/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp +++ b/Swiften/Presence/UnitTest/PayloadAddingPresenceSenderTest.cpp @@ -9,10 +9,10 @@ #include <vector> #include <boost/bind.hpp> -#include "Swiften/Presence/PayloadAddingPresenceSender.h" -#include "Swiften/Presence/StanzaChannelPresenceSender.h" -#include "Swiften/Elements/Body.h" -#include "Swiften/Client/DummyStanzaChannel.h" +#include <Swiften/Presence/PayloadAddingPresenceSender.h> +#include <Swiften/Presence/StanzaChannelPresenceSender.h> +#include <Swiften/Elements/Body.h> +#include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; @@ -23,6 +23,7 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { CPPUNIT_TEST(testSendPresenceDoesNotAlterOriginalPayload); CPPUNIT_TEST(testSetPayloadAfterInitialPresenceResendsPresence); CPPUNIT_TEST(testSetPayloadAfterUnavailablePresenceDoesNotResendPresence); + CPPUNIT_TEST(testSetPayloadAfterResetDoesNotResendPresence); CPPUNIT_TEST(testSendDirectedPresenceIsNotResent); CPPUNIT_TEST_SUITE_END(); @@ -38,7 +39,7 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { } void testSetPayloadAddsPayloadOnPresenceSend() { - std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); testling->setPayload(MyPayload::create("foo")); testling->sendPresence(Presence::create("bar")); @@ -49,7 +50,7 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { } void testSetNullPayloadDoesNotAddPayloadOnPresenceSend() { - std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); testling->setPayload(MyPayload::ref()); testling->sendPresence(Presence::create("bar")); @@ -60,7 +61,7 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { } void testSendPresenceDoesNotAlterOriginalPayload() { - std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); testling->setPayload(MyPayload::create("foo")); Presence::ref presence(Presence::create("bar")); @@ -70,7 +71,7 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { } void testSetPayloadAfterInitialPresenceResendsPresence() { - std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); testling->sendPresence(Presence::create("bar")); testling->setPayload(MyPayload::create("foo")); @@ -81,7 +82,9 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { } void testSetPayloadAfterUnavailablePresenceDoesNotResendPresence() { - std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + + testling->sendPresence(Presence::create("bar")); Presence::ref presence = Presence::create("bar"); presence->setType(Presence::Unavailable); @@ -89,11 +92,21 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { testling->setPayload(MyPayload::create("foo")); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(stanzaChannel->sentStanzas.size())); + } + + void testSetPayloadAfterResetDoesNotResendPresence() { + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); + testling->sendPresence(Presence::create("bar")); + + testling->reset(); + testling->setPayload(MyPayload::create("foo")); + CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); } void testSendDirectedPresenceIsNotResent() { - std::auto_ptr<PayloadAddingPresenceSender> testling(createSender()); + boost::shared_ptr<PayloadAddingPresenceSender> testling(createSender()); testling->sendPresence(Presence::create("bar")); Presence::ref directedPresence = Presence::create("baz"); @@ -106,8 +119,8 @@ class PayloadAddingPresenceSenderTest : public CppUnit::TestFixture { } private: - std::auto_ptr<PayloadAddingPresenceSender> createSender() { - std::auto_ptr<PayloadAddingPresenceSender> sender(new PayloadAddingPresenceSender(presenceSender)); + boost::shared_ptr<PayloadAddingPresenceSender> createSender() { + boost::shared_ptr<PayloadAddingPresenceSender> sender(new PayloadAddingPresenceSender(presenceSender)); return sender; } diff --git a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp index 24cc62c..179538e 100644 --- a/Swiften/Presence/UnitTest/PresenceOracleTest.cpp +++ b/Swiften/Presence/UnitTest/PresenceOracleTest.cpp @@ -9,9 +9,9 @@ #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> -#include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Presence/SubscriptionManager.h" +#include <Swiften/Presence/PresenceOracle.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Presence/SubscriptionManager.h> using namespace Swift; diff --git a/Swiften/QA/ClientTest/ClientTest.cpp b/Swiften/QA/ClientTest/ClientTest.cpp index 35bb096..584f644 100644 --- a/Swiften/QA/ClientTest/ClientTest.cpp +++ b/Swiften/QA/ClientTest/ClientTest.cpp @@ -6,14 +6,15 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> +#include <iostream> -#include "Swiften/Client/Client.h" -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/BoostNetworkFactories.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/Roster/GetRosterRequest.h" -#include "Swiften/Client/ClientXMLTracer.h" +#include <Swiften/Client/Client.h> +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/BoostNetworkFactories.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Roster/GetRosterRequest.h> +#include <Swiften/Client/ClientXMLTracer.h> using namespace Swift; diff --git a/Swiften/QA/DNSSDTest/DNSSDTest.cpp b/Swiften/QA/DNSSDTest/DNSSDTest.cpp index 1bf0965..7e2a189 100644 --- a/Swiften/QA/DNSSDTest/DNSSDTest.cpp +++ b/Swiften/QA/DNSSDTest/DNSSDTest.cpp @@ -9,18 +9,17 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include <algorithm> - -#include "Swiften/Base/sleep.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/EventLoop/DummyEventLoop.h" -#include "Swiften/LinkLocal/LinkLocalServiceInfo.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDQuerier.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h" -#include "Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h" +#include <Swiften/Base/sleep.h> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/EventLoop/DummyEventLoop.h> +#include <Swiften/LinkLocal/LinkLocalServiceInfo.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDQuerier.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDBrowseQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDRegisterQuery.h> +#include <Swiften/LinkLocal/DNSSD/DNSSDResolveServiceQuery.h> #ifdef HAVE_AVAHI -#include "Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h" +#include <Swiften/LinkLocal/DNSSD/Avahi/AvahiQuerier.h> #endif #define SLEEP_INTERVALS 20 @@ -95,7 +94,7 @@ class DNSSDTest : public CppUnit::TestFixture { toRemove.clear(); toRemove.insert(toRemove.begin(), added.begin(), added.end()); registerQuery->unregisterService(); - while (toRemove.size() > 0) { + while (!toRemove.empty()) { Swift::sleep(100); eventLoop->processEvents(); } @@ -112,7 +111,7 @@ class DNSSDTest : public CppUnit::TestFixture { void handleServiceRemoved(const DNSSDServiceID& id) { CPPUNIT_ASSERT(std::find(toRemove.begin(), toRemove.end(), id) != toRemove.end()); - toRemove.erase(std::remove(toRemove.begin(), toRemove.end(), id)); + erase(toRemove, id); } void handleRegisterFinished(boost::optional<DNSSDServiceID> id) { diff --git a/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp b/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp index 82a8be2..14da358 100644 --- a/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp +++ b/Swiften/QA/NetworkTest/BoostConnectionServerTest.cpp @@ -9,9 +9,9 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Network/BoostConnectionServer.h" -#include "Swiften/Network/BoostIOServiceThread.h" -#include "Swiften/EventLoop/DummyEventLoop.h" +#include <Swiften/Network/BoostConnectionServer.h> +#include <Swiften/Network/BoostIOServiceThread.h> +#include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; diff --git a/Swiften/QA/NetworkTest/BoostConnectionTest.cpp b/Swiften/QA/NetworkTest/BoostConnectionTest.cpp index 928e3db..335f2d2 100644 --- a/Swiften/QA/NetworkTest/BoostConnectionTest.cpp +++ b/Swiften/QA/NetworkTest/BoostConnectionTest.cpp @@ -10,12 +10,13 @@ #include <boost/smart_ptr/make_shared.hpp> #include <string> -#include "Swiften/Base/sleep.h" -#include "Swiften/Network/BoostConnection.h" -#include "Swiften/Network/HostAddress.h" -#include "Swiften/Network/HostAddressPort.h" -#include "Swiften/Network/BoostIOServiceThread.h" -#include "Swiften/EventLoop/DummyEventLoop.h" +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/sleep.h> +#include <Swiften/Network/BoostConnection.h> +#include <Swiften/Network/HostAddress.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/Network/BoostIOServiceThread.h> +#include <Swiften/EventLoop/DummyEventLoop.h> const unsigned char* address = reinterpret_cast<const unsigned char*>("\x41\x63\xde\x89"); @@ -70,7 +71,7 @@ class BoostConnectionTest : public CppUnit::TestFixture { testling->onDataRead.connect(boost::bind(&BoostConnectionTest::handleDataRead, this, _1)); testling->onDisconnected.connect(boost::bind(&BoostConnectionTest::handleDisconnected, this)); testling->connect(HostAddressPort(HostAddress("65.99.222.137"), 5222)); - while (receivedData.isEmpty()) { + while (receivedData.empty()) { Swift::sleep(10); eventLoop_->processEvents(); } @@ -83,7 +84,7 @@ class BoostConnectionTest : public CppUnit::TestFixture { testling->onDataRead.connect(boost::bind(&BoostConnectionTest::handleDataRead, this, _1)); testling->onDisconnected.connect(boost::bind(&BoostConnectionTest::handleDisconnected, this)); testling->connect(HostAddressPort(HostAddress("2001:470:1f0e:852::2"), 80)); - while (receivedData.isEmpty()) { + while (receivedData.empty()) { Swift::sleep(10); eventLoop_->processEvents(); } @@ -102,9 +103,9 @@ class BoostConnectionTest : public CppUnit::TestFixture { eventLoop_->processEvents(); } - testling->write(ByteArray("<stream:strea")); - testling->write(ByteArray("m")); - testling->write(ByteArray(">")); + testling->write(createSafeByteArray("<stream:strea")); + testling->write(createSafeByteArray("m")); + testling->write(createSafeByteArray(">")); // Check that we only did one write event, the others are queued /*int runHandlers = */boostIOService->poll(); @@ -112,7 +113,7 @@ class BoostConnectionTest : public CppUnit::TestFixture { // this test doesn't really work any more. We'll have to trust that things are queued. //CPPUNIT_ASSERT_EQUAL(1, runHandlers); // Process the other events - while (receivedData.isEmpty()) { + while (receivedData.empty()) { boostIOService->run_one(); eventLoop_->processEvents(); } @@ -126,12 +127,12 @@ class BoostConnectionTest : public CppUnit::TestFixture { } void doWrite(BoostConnection* connection) { - connection->write(ByteArray("<stream:stream>")); - connection->write(ByteArray("\r\n\r\n")); // Temporarily, while we don't have an xmpp server running on ipv6 + connection->write(createSafeByteArray("<stream:stream>")); + connection->write(createSafeByteArray("\r\n\r\n")); // Temporarily, while we don't have an xmpp server running on ipv6 } - void handleDataRead(const ByteArray& data) { - receivedData += data; + void handleDataRead(boost::shared_ptr<SafeByteArray> data) { + append(receivedData, *data); } void handleDisconnected() { diff --git a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp index a0a7e7b..7cb9ed3 100644 --- a/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp +++ b/Swiften/QA/NetworkTest/DomainNameResolverTest.cpp @@ -10,13 +10,13 @@ #include <algorithm> -#include "Swiften/Base/sleep.h" +#include <Swiften/Base/sleep.h> #include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Network/PlatformDomainNameResolver.h" -#include "Swiften/Network/DomainNameAddressQuery.h" -#include "Swiften/Network/DomainNameServiceQuery.h" -#include "Swiften/EventLoop/DummyEventLoop.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Network/PlatformDomainNameResolver.h> +#include <Swiften/Network/DomainNameAddressQuery.h> +#include <Swiften/Network/DomainNameServiceQuery.h> +#include <Swiften/EventLoop/DummyEventLoop.h> using namespace Swift; diff --git a/Swiften/QA/ProxyProviderTest/.gitignore b/Swiften/QA/ProxyProviderTest/.gitignore new file mode 100644 index 0000000..9d4b9b8 --- /dev/null +++ b/Swiften/QA/ProxyProviderTest/.gitignore @@ -0,0 +1 @@ +ProxyProviderTest diff --git a/Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp b/Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp new file mode 100644 index 0000000..ddaee01 --- /dev/null +++ b/Swiften/QA/ProxyProviderTest/ProxyProviderTest.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010 Thilo Cestonaro + * Licensed under the BSD License. + * See Documentation/Licenses/BSD.txt for more information. + */ + +#include <iostream> + +#include <Swiften/Network/PlatformProxyProvider.h> +#include <Swiften/Base/foreach.h> + +using namespace Swift; + +int main(void) +{ + int ret = 0; + HostAddressPort hap; + + std::cout << "constructing PlatfromProxyProvider instance ..." << std::endl; + PlatformProxyProvider ppp; + + hap = ppp.getSOCKS5Proxy(); + std::cout << "SOCKS5 Proxy configured: " << hap.isValid() << std::endl; + if(hap.isValid()) { + std::cout << "SOCKS5 Proxy: " << hap.getAddress().toString() << ":" << hap.getPort() << std::endl; + } + + hap = ppp.getHTTPConnectProxy(); + std::cout << "HTTPConnect Proxy configured: " << hap.isValid() << std::endl; + if(hap.isValid()) { + std::cout << "HTTPConnect Proxy: " << hap.getAddress().toString() << ":" << hap.getPort() << std::endl; + } + + return ret; +} diff --git a/Swiften/QA/ProxyProviderTest/SConscript b/Swiften/QA/ProxyProviderTest/SConscript new file mode 100644 index 0000000..2eb123d --- /dev/null +++ b/Swiften/QA/ProxyProviderTest/SConscript @@ -0,0 +1,11 @@ +import os + +Import("env") + +myenv = env.Clone() +myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) +myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) + +myenv.Program("ProxyProviderTest", [ + "ProxyProviderTest.cpp", + ]) diff --git a/Swiften/QA/ReconnectTest/ReconnectTest.cpp b/Swiften/QA/ReconnectTest/ReconnectTest.cpp index 117cfa3..933d5d2 100644 --- a/Swiften/QA/ReconnectTest/ReconnectTest.cpp +++ b/Swiften/QA/ReconnectTest/ReconnectTest.cpp @@ -7,14 +7,14 @@ #include <boost/bind.hpp> #include <boost/thread.hpp> -#include "Swiften/Client/Client.h" -#include "Swiften/Network/BoostTimer.h" -#include "Swiften/EventLoop/EventLoop.h" -#include "Swiften/EventLoop/SimpleEventLoop.h" -#include "Swiften/Roster/GetRosterRequest.h" -#include "Swiften/Client/ClientXMLTracer.h" -#include "Swiften/Network/BoostIOServiceThread.h" -#include "Swiften/Network/MainBoostIOServiceThread.h" +#include <Swiften/Client/Client.h> +#include <Swiften/Network/BoostTimer.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/EventLoop/SimpleEventLoop.h> +#include <Swiften/Roster/GetRosterRequest.h> +#include <Swiften/Client/ClientXMLTracer.h> +#include <Swiften/Network/BoostIOServiceThread.h> +#include <Swiften/Network/MainBoostIOServiceThread.h> using namespace Swift; diff --git a/Swiften/QA/SConscript b/Swiften/QA/SConscript index 25ba814..2f2be6e 100644 --- a/Swiften/QA/SConscript +++ b/Swiften/QA/SConscript @@ -5,7 +5,8 @@ SConscript(dirs = [ # "ReconnectTest", "ClientTest", # "DNSSDTest", - "StorageTest", +# "StorageTest", "TLSTest", "ScriptedTests", + "ProxyProviderTest", ]) diff --git a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp index 925c775..e090c6c 100644 --- a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp +++ b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp @@ -7,7 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/FileTransfer/FileReadBytestream.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/FileTransfer/FileReadBytestream.h> #include "SwifTools/Application/PlatformApplicationPathProvider.h" using namespace Swift; @@ -30,24 +31,24 @@ class FileReadBytestreamTest : public CppUnit::TestFixture { } void testRead() { - std::auto_ptr<FileReadBytestream> testling(createTestling()); + boost::shared_ptr<FileReadBytestream> testling(createTestling()); - ByteArray result = testling->read(10); + std::vector<unsigned char> result = testling->read(10); - CPPUNIT_ASSERT_EQUAL(std::string("/*\n * Copy"), result.toString()); + CPPUNIT_ASSERT(ByteArray::create("/*\n * Copy") == result); } void testRead_Twice() { - std::auto_ptr<FileReadBytestream> testling(createTestling()); + boost::shared_ptr<FileReadBytestream> testling(createTestling()); testling->read(10); - ByteArray result = testling->read(10); + ByteArray result(testling->read(10)); CPPUNIT_ASSERT_EQUAL(std::string("right (c) "), result.toString()); } void testIsFinished_NotFinished() { - std::auto_ptr<FileReadBytestream> testling(createTestling()); + boost::shared_ptr<FileReadBytestream> testling(createTestling()); testling->read(10); @@ -55,7 +56,7 @@ class FileReadBytestreamTest : public CppUnit::TestFixture { } void testIsFinished_IsFinished() { - std::auto_ptr<FileReadBytestream> testling(createTestling()); + boost::shared_ptr<FileReadBytestream> testling(createTestling()); testling->read(4096); diff --git a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp index fb51568..7667176 100644 --- a/Swiften/QA/StorageTest/VCardFileStorageTest.cpp +++ b/Swiften/QA/StorageTest/VCardFileStorageTest.cpp @@ -9,10 +9,10 @@ #include <boost/algorithm/string.hpp> #include <sstream> -#include "Swiften/VCards/VCardFileStorage.h" -#include "Swiften/JID/JID.h" +#include <Swiften/VCards/VCardFileStorage.h> +#include <Swiften/JID/JID.h> #include "SwifTools/Application/PlatformApplicationPathProvider.h" -#include "Swiften/Elements/VCard.h" +#include <Swiften/Elements/VCard.h> using namespace Swift; @@ -40,7 +40,7 @@ class VCardFileStorageTest : public CppUnit::TestFixture { } void testSetVCard() { - std::auto_ptr<VCardFileStorage> testling(createTestling()); + boost::shared_ptr<VCardFileStorage> testling(createTestling()); VCard::ref vcard(new VCard()); vcard->setFullName("Alice In Wonderland"); @@ -70,7 +70,7 @@ class VCardFileStorageTest : public CppUnit::TestFixture { } void testGetVCard() { - std::auto_ptr<VCardFileStorage> testling(createTestling()); + boost::shared_ptr<VCardFileStorage> testling(createTestling()); VCard::ref vcard(new VCard()); vcard->setFullName("Alice In Wonderland"); testling->setVCard(JID("alice@wonderland.lit"), vcard); @@ -96,7 +96,7 @@ class VCardFileStorageTest : public CppUnit::TestFixture { } void testGetVCard_FileDoesNotExist() { - std::auto_ptr<VCardFileStorage> testling(createTestling()); + boost::shared_ptr<VCardFileStorage> testling(createTestling()); VCard::ref result = testling->getVCard(JID("alice@wonderland.lit")); CPPUNIT_ASSERT(!result); } diff --git a/Swiften/QA/TLSTest/CertificateTest.cpp b/Swiften/QA/TLSTest/CertificateTest.cpp index 0f37fde..67ca064 100644 --- a/Swiften/QA/TLSTest/CertificateTest.cpp +++ b/Swiften/QA/TLSTest/CertificateTest.cpp @@ -10,7 +10,8 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/bind.hpp> -#include "Swiften/TLS/CertificateFactory.h" +#include <QA/Checker/IO.h> +#include <Swiften/TLS/CertificateFactory.h> #include "SwifTools/Application/PlatformApplicationPathProvider.h" using namespace Swift; @@ -30,7 +31,7 @@ class CertificateTest : public CppUnit::TestFixture { public: void setUp() { pathProvider = new PlatformApplicationPathProvider("FileReadBytestreamTest"); - certificateData.readFromFile((pathProvider->getExecutableDir() / "jabber_org.crt").string()); + readByteArrayFromFile(certificateData, (pathProvider->getExecutableDir() / "jabber_org.crt").string()); certificateFactory = new CERTIFICATE_FACTORY(); } @@ -95,6 +96,6 @@ class CertificateTest : public CppUnit::TestFixture { }; #ifdef HAVE_OPENSSL -#include "Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h" +#include <Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h> CPPUNIT_TEST_SUITE_REGISTRATION(CertificateTest<OpenSSLCertificateFactory>); #endif diff --git a/Swiften/Queries/DummyIQChannel.h b/Swiften/Queries/DummyIQChannel.h index f740b5c..6adcdb1 100644 --- a/Swiften/Queries/DummyIQChannel.h +++ b/Swiften/Queries/DummyIQChannel.h @@ -8,7 +8,7 @@ #include <vector> -#include "Swiften/Queries/IQChannel.h" +#include <Swiften/Queries/IQChannel.h> namespace Swift { class DummyIQChannel : public IQChannel { diff --git a/Swiften/Queries/GenericRequest.h b/Swiften/Queries/GenericRequest.h index a8e3409..9fd934f 100644 --- a/Swiften/Queries/GenericRequest.h +++ b/Swiften/Queries/GenericRequest.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Queries/Request.h" +#include <Swiften/Queries/Request.h> namespace Swift { template<typename PAYLOAD_TYPE> @@ -22,6 +22,15 @@ namespace Swift { Request(type, receiver, payload, router) { } + GenericRequest( + IQ::Type type, + const JID& sender, + const JID& receiver, + boost::shared_ptr<Payload> payload, + IQRouter* router) : + Request(type, sender, receiver, payload, router) { + } + virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { onResponse(boost::dynamic_pointer_cast<PAYLOAD_TYPE>(payload), error); } diff --git a/Swiften/Queries/GetResponder.h b/Swiften/Queries/GetResponder.h index ca3b677..bca507a 100644 --- a/Swiften/Queries/GetResponder.h +++ b/Swiften/Queries/GetResponder.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Queries/Responder.h" +#include <Swiften/Queries/Responder.h> namespace Swift { template<typename T> diff --git a/Swiften/Queries/IQChannel.cpp b/Swiften/Queries/IQChannel.cpp index 959d87d..815a617 100644 --- a/Swiften/Queries/IQChannel.cpp +++ b/Swiften/Queries/IQChannel.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/IQChannel.h" +#include <Swiften/Queries/IQChannel.h> namespace Swift { diff --git a/Swiften/Queries/IQChannel.h b/Swiften/Queries/IQChannel.h index 22b7572..71a6dd4 100644 --- a/Swiften/Queries/IQChannel.h +++ b/Swiften/Queries/IQChannel.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IQChannel_H -#define SWIFTEN_IQChannel_H +#pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Elements/IQ.h" +#include <Swiften/Elements/IQ.h> namespace Swift { class IQChannel { @@ -26,5 +25,3 @@ namespace Swift { boost::signal<void (boost::shared_ptr<IQ>)> onIQReceived; }; } - -#endif diff --git a/Swiften/Queries/IQHandler.cpp b/Swiften/Queries/IQHandler.cpp index fe65c71..01e4387 100644 --- a/Swiften/Queries/IQHandler.cpp +++ b/Swiften/Queries/IQHandler.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/IQHandler.h" -#include "Swiften/Queries/IQRouter.h" +#include <Swiften/Queries/IQHandler.h> +#include <Swiften/Queries/IQRouter.h> namespace Swift { diff --git a/Swiften/Queries/IQHandler.h b/Swiften/Queries/IQHandler.h index 616f9fa..c9af5ea 100644 --- a/Swiften/Queries/IQHandler.h +++ b/Swiften/Queries/IQHandler.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IQHandler_H -#define SWIFTEN_IQHandler_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/IQ.h" +#include <Swiften/Elements/IQ.h> namespace Swift { class IQRouter; @@ -21,5 +20,3 @@ namespace Swift { virtual bool handleIQ(boost::shared_ptr<IQ>) = 0; }; } - -#endif diff --git a/Swiften/Queries/IQRouter.cpp b/Swiften/Queries/IQRouter.cpp index 1bfff70..c84e1bb 100644 --- a/Swiften/Queries/IQRouter.cpp +++ b/Swiften/Queries/IQRouter.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/IQRouter.h" +#include <Swiften/Queries/IQRouter.h> -#include <algorithm> #include <boost/bind.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Queries/IQHandler.h" -#include "Swiften/Queries/IQChannel.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Queries/IQHandler.h> +#include <Swiften/Queries/IQChannel.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { @@ -54,7 +54,7 @@ void IQRouter::handleIQ(boost::shared_ptr<IQ> iq) { void IQRouter::processPendingRemoves() { foreach(boost::shared_ptr<IQHandler> handler, queuedRemoves_) { - handlers_.erase(std::remove(handlers_.begin(), handlers_.end(), handler), handlers_.end()); + erase(handlers_, handler); } queuedRemoves_.clear(); } @@ -76,12 +76,12 @@ void IQRouter::removeHandler(boost::shared_ptr<IQHandler> handler) { queuedRemoves_.push_back(handler); } else { - handlers_.erase(std::remove(handlers_.begin(), handlers_.end(), handler), handlers_.end()); + erase(handlers_, handler); } } void IQRouter::sendIQ(boost::shared_ptr<IQ> iq) { - if (from_.isValid()) { + if (from_.isValid() && !iq->getFrom().isValid()) { iq->setFrom(from_); } channel_->sendIQ(iq); diff --git a/Swiften/Queries/IQRouter.h b/Swiften/Queries/IQRouter.h index a21b24d..8dba334 100644 --- a/Swiften/Queries/IQRouter.h +++ b/Swiften/Queries/IQRouter.h @@ -10,7 +10,7 @@ #include <vector> #include <string> -#include "Swiften/Elements/IQ.h" +#include <Swiften/Elements/IQ.h> namespace Swift { class IQChannel; @@ -63,6 +63,16 @@ namespace Swift { bool isAvailable(); + /** + * Checks whether the given jid is the account JID (i.e. it is either + * the bare JID, or it is the empty JID). + * Can be used to check whether a stanza is sent by the server on behalf + * of the user's account. + */ + bool isAccountJID(const JID& jid) { + return jid.isValid() ? jid_.toBare().equals(jid, JID::WithResource) : true; + } + private: void handleIQ(boost::shared_ptr<IQ> iq); void processPendingRemoves(); diff --git a/Swiften/Queries/RawRequest.h b/Swiften/Queries/RawRequest.h index 477952f..e5b3a1d 100644 --- a/Swiften/Queries/RawRequest.h +++ b/Swiften/Queries/RawRequest.h @@ -31,7 +31,7 @@ namespace Swift { RawRequest(IQ::Type type, const JID& receiver, const std::string& data, IQRouter* router) : Request(type, receiver, boost::make_shared<RawXMLPayload>(data), router) { } - virtual void handleResponse(Payload::ref payload, ErrorPayload::ref error) { + virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { if (error) { onResponse(ErrorSerializer().serializePayload(error)); } diff --git a/Swiften/Queries/Request.cpp b/Swiften/Queries/Request.cpp index 95fd25e..f3f56c9 100644 --- a/Swiften/Queries/Request.cpp +++ b/Swiften/Queries/Request.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/Request.h" -#include "Swiften/Queries/IQRouter.h" +#include <Swiften/Queries/Request.h> +#include <Swiften/Queries/IQRouter.h> #include <Swiften/Elements/RawXMLPayload.h> namespace Swift { @@ -16,6 +16,12 @@ Request::Request(IQ::Type type, const JID& receiver, boost::shared_ptr<Payload> Request::Request(IQ::Type type, const JID& receiver, IQRouter* router) : router_(router), type_(type), receiver_(receiver), sent_(false) { } +Request::Request(IQ::Type type, const JID& sender, const JID& receiver, boost::shared_ptr<Payload> payload, IQRouter* router) : router_(router), type_(type), sender_(sender), receiver_(receiver), payload_(payload), sent_(false) { +} + +Request::Request(IQ::Type type, const JID& sender, const JID& receiver, IQRouter* router) : router_(router), type_(type), sender_(sender), receiver_(receiver), sent_(false) { +} + void Request::send() { assert(payload_); assert(!sent_); @@ -23,6 +29,7 @@ void Request::send() { boost::shared_ptr<IQ> iq(new IQ(type_)); iq->setTo(receiver_); + iq->setFrom(sender_); iq->addPayload(payload_); id_ = router_->getNewIQID(); iq->setID(id_); @@ -67,16 +74,13 @@ bool Request::handleIQ(boost::shared_ptr<IQ> iq) { } bool Request::isCorrectSender(const JID& jid) { - if (isAccountJID(receiver_)) { - return isAccountJID(jid); + if (router_->isAccountJID(receiver_)) { + return router_->isAccountJID(jid); } else { return jid.equals(receiver_, JID::WithResource); } } -bool Request::isAccountJID(const JID& jid) { - return jid.isValid() ? router_->getJID().toBare().equals(jid, JID::WithResource) : true; -} } diff --git a/Swiften/Queries/Request.h b/Swiften/Queries/Request.h index c710548..668ed04 100644 --- a/Swiften/Queries/Request.h +++ b/Swiften/Queries/Request.h @@ -4,19 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_Request_H -#define SWIFTEN_Request_H +#pragma once #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> #include <boost/enable_shared_from_this.hpp> #include <string> -#include "Swiften/Queries/IQHandler.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/JID/JID.h" +#include <Swiften/Queries/IQHandler.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/JID/JID.h> namespace Swift { /** @@ -40,6 +39,19 @@ namespace Swift { const JID& receiver, boost::shared_ptr<Payload> payload, IQRouter* router); + + /** + * Constructs a request of a certain type to a specific receiver from a specific sender, and attaches the given + * payload. + */ + Request( + IQ::Type type, + const JID& sender, + const JID& receiver, + boost::shared_ptr<Payload> payload, + IQRouter* router); + + /** * Constructs a request of a certain type to a specific receiver. */ @@ -48,29 +60,37 @@ namespace Swift { const JID& receiver, IQRouter* router); - virtual void setPayload(Payload::ref payload) { + /** + * Constructs a request of a certain type to a specific receiver from a specific sender. + */ + Request( + IQ::Type type, + const JID& sender, + const JID& receiver, + IQRouter* router); + + + virtual void setPayload(boost::shared_ptr<Payload> payload) { payload_ = payload; } - Payload::ref getPayload() const { + boost::shared_ptr<Payload> getPayload() const { return payload_; } - virtual void handleResponse(Payload::ref, ErrorPayload::ref) = 0; + virtual void handleResponse(boost::shared_ptr<Payload>, boost::shared_ptr<ErrorPayload>) = 0; private: bool handleIQ(boost::shared_ptr<IQ>); bool isCorrectSender(const JID& jid); - bool isAccountJID(const JID& jid); private: IQRouter* router_; IQ::Type type_; + JID sender_; JID receiver_; boost::shared_ptr<Payload> payload_; std::string id_; bool sent_; }; } - -#endif diff --git a/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.cpp b/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.cpp index 5f6be03..337375e 100644 --- a/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.cpp +++ b/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.cpp @@ -4,4 +4,4 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/Requests/GetInBandRegistrationFormRequest.h" +#include <Swiften/Queries/Requests/GetInBandRegistrationFormRequest.h> diff --git a/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.h b/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.h index aa0866a..c0488ad 100644 --- a/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.h +++ b/Swiften/Queries/Requests/GetInBandRegistrationFormRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/InBandRegistrationPayload.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/InBandRegistrationPayload.h> namespace Swift { diff --git a/Swiften/Queries/Requests/GetPrivateStorageRequest.h b/Swiften/Queries/Requests/GetPrivateStorageRequest.h index f0b95d8..b0eefb2 100644 --- a/Swiften/Queries/Requests/GetPrivateStorageRequest.h +++ b/Swiften/Queries/Requests/GetPrivateStorageRequest.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Queries/Request.h" -#include "Swiften/Elements/PrivateStorage.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Queries/Request.h> +#include <Swiften/Elements/PrivateStorage.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { template<typename PAYLOAD_TYPE> diff --git a/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h index 51794da..a6f782b 100644 --- a/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h +++ b/Swiften/Queries/Requests/GetSecurityLabelsCatalogRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/SecurityLabelsCatalog.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/SecurityLabelsCatalog.h> namespace Swift { diff --git a/Swiften/Queries/Requests/GetSoftwareVersionRequest.h b/Swiften/Queries/Requests/GetSoftwareVersionRequest.h index 442ec88..18461bb 100644 --- a/Swiften/Queries/Requests/GetSoftwareVersionRequest.h +++ b/Swiften/Queries/Requests/GetSoftwareVersionRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/SoftwareVersion.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/SoftwareVersion.h> #include <boost/smart_ptr/make_shared.hpp> diff --git a/Swiften/Queries/Requests/SetPrivateStorageRequest.h b/Swiften/Queries/Requests/SetPrivateStorageRequest.h index 69eb001..f795742 100644 --- a/Swiften/Queries/Requests/SetPrivateStorageRequest.h +++ b/Swiften/Queries/Requests/SetPrivateStorageRequest.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Queries/Request.h" -#include "Swiften/Elements/PrivateStorage.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Queries/Request.h> +#include <Swiften/Elements/PrivateStorage.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { template<typename PAYLOAD_TYPE> diff --git a/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.cpp b/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.cpp index f28c878..f010e96 100644 --- a/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.cpp +++ b/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.cpp @@ -4,4 +4,4 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h" +#include <Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h> diff --git a/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h b/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h index 0700c65..8e0862b 100644 --- a/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h +++ b/Swiften/Queries/Requests/SubmitInBandRegistrationFormRequest.h @@ -6,11 +6,11 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Queries/Request.h" -#include "Swiften/Elements/InBandRegistrationPayload.h" +#include <Swiften/Queries/Request.h> +#include <Swiften/Elements/InBandRegistrationPayload.h> namespace Swift { @@ -26,11 +26,11 @@ namespace Swift { SetInBandRegistrationRequest(const JID& to, InBandRegistrationPayload::ref payload, IQRouter* router) : Request(IQ::Set, to, InBandRegistrationPayload::ref(payload), router) { } - virtual void handleResponse(Payload::ref payload, ErrorPayload::ref error) { + virtual void handleResponse(boost::shared_ptr<Payload> payload, ErrorPayload::ref error) { onResponse(payload, error); } public: - boost::signal<void (Payload::ref, ErrorPayload::ref)> onResponse; + boost::signal<void (boost::shared_ptr<Payload>, ErrorPayload::ref)> onResponse; }; } diff --git a/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp b/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp index b7c36cb..f3ecfb7 100644 --- a/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp +++ b/Swiften/Queries/Requests/UnitTest/GetPrivateStorageRequestTest.cpp @@ -9,10 +9,10 @@ #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> -#include "Swiften/Queries/Requests/GetPrivateStorageRequest.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/DummyIQChannel.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Queries/Requests/GetPrivateStorageRequest.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/DummyIQChannel.h> +#include <Swiften/Elements/Payload.h> using namespace Swift; diff --git a/Swiften/Queries/Responder.h b/Swiften/Queries/Responder.h index 2ce8f10..2ba9c24 100644 --- a/Swiften/Queries/Responder.h +++ b/Swiften/Queries/Responder.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Queries/IQHandler.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Queries/IQHandler.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { /** @@ -94,6 +94,10 @@ namespace Swift { router_->sendIQ(IQ::createError(to, from, id, condition, type)); } + IQRouter* getIQRouter() const { + return router_; + } + private: virtual bool handleIQ(boost::shared_ptr<IQ> iq) { if (iq->getType() == IQ::Set || iq->getType() == IQ::Get) { diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.cpp b/Swiften/Queries/Responders/SoftwareVersionResponder.cpp index 445dcc7..3f9616a 100644 --- a/Swiften/Queries/Responders/SoftwareVersionResponder.cpp +++ b/Swiften/Queries/Responders/SoftwareVersionResponder.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Queries/Responders/SoftwareVersionResponder.h" -#include "Swiften/Queries/IQRouter.h" +#include <Swiften/Queries/Responders/SoftwareVersionResponder.h> +#include <Swiften/Queries/IQRouter.h> namespace Swift { diff --git a/Swiften/Queries/Responders/SoftwareVersionResponder.h b/Swiften/Queries/Responders/SoftwareVersionResponder.h index cbda54c..a2929df 100644 --- a/Swiften/Queries/Responders/SoftwareVersionResponder.h +++ b/Swiften/Queries/Responders/SoftwareVersionResponder.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GetResponder.h" -#include "Swiften/Elements/SoftwareVersion.h" +#include <Swiften/Queries/GetResponder.h> +#include <Swiften/Elements/SoftwareVersion.h> namespace Swift { class IQRouter; diff --git a/Swiften/Queries/SetResponder.h b/Swiften/Queries/SetResponder.h index ec3460c..331aa46 100644 --- a/Swiften/Queries/SetResponder.h +++ b/Swiften/Queries/SetResponder.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Queries/Responder.h" +#include <Swiften/Queries/Responder.h> namespace Swift { template<typename T> diff --git a/Swiften/Queries/UnitTest/IQRouterTest.cpp b/Swiften/Queries/UnitTest/IQRouterTest.cpp index ef5da23..f06b967 100644 --- a/Swiften/Queries/UnitTest/IQRouterTest.cpp +++ b/Swiften/Queries/UnitTest/IQRouterTest.cpp @@ -9,9 +9,9 @@ #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> -#include "Swiften/Queries/IQHandler.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/DummyIQChannel.h" +#include <Swiften/Queries/IQHandler.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/DummyIQChannel.h> using namespace Swift; diff --git a/Swiften/Queries/UnitTest/RequestTest.cpp b/Swiften/Queries/UnitTest/RequestTest.cpp index 75e0a1d..52d62fb 100644 --- a/Swiften/Queries/UnitTest/RequestTest.cpp +++ b/Swiften/Queries/UnitTest/RequestTest.cpp @@ -10,10 +10,10 @@ #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/DummyIQChannel.h" -#include "Swiften/Elements/Payload.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/DummyIQChannel.h> +#include <Swiften/Elements/Payload.h> #include <Swiften/Elements/RawXMLPayload.h> using namespace Swift; diff --git a/Swiften/Queries/UnitTest/ResponderTest.cpp b/Swiften/Queries/UnitTest/ResponderTest.cpp index c087827..a256346 100644 --- a/Swiften/Queries/UnitTest/ResponderTest.cpp +++ b/Swiften/Queries/UnitTest/ResponderTest.cpp @@ -9,10 +9,10 @@ #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> -#include "Swiften/Queries/Responder.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Queries/DummyIQChannel.h" -#include "Swiften/Elements/SoftwareVersion.h" +#include <Swiften/Queries/Responder.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Queries/DummyIQChannel.h> +#include <Swiften/Elements/SoftwareVersion.h> using namespace Swift; diff --git a/Swiften/Roster/GetRosterRequest.h b/Swiften/Roster/GetRosterRequest.h index 00cf77f..e7146d2 100644 --- a/Swiften/Roster/GetRosterRequest.h +++ b/Swiften/Roster/GetRosterRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/RosterPayload.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/RosterPayload.h> namespace Swift { @@ -19,6 +19,12 @@ namespace Swift { return ref(new GetRosterRequest(router)); } + static ref create(IQRouter* router, const std::string& version) { + ref result(new GetRosterRequest(router)); + result->getPayloadGeneric()->setVersion(version); + return result; + } + private: GetRosterRequest(IQRouter* router) : GenericRequest<RosterPayload>(IQ::Get, JID(), boost::shared_ptr<Payload>(new RosterPayload()), router) { diff --git a/Swiften/Roster/RosterMemoryStorage.cpp b/Swiften/Roster/RosterMemoryStorage.cpp new file mode 100644 index 0000000..cbf4563 --- /dev/null +++ b/Swiften/Roster/RosterMemoryStorage.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterMemoryStorage.h> + +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + +RosterMemoryStorage::RosterMemoryStorage() { +} + +void RosterMemoryStorage::setRoster(boost::shared_ptr<RosterPayload> r) { + roster.reset(); + if (r) { + roster = boost::make_shared<RosterPayload>(*r); + } +} + +} diff --git a/Swiften/Roster/RosterMemoryStorage.h b/Swiften/Roster/RosterMemoryStorage.h new file mode 100644 index 0000000..b659d77 --- /dev/null +++ b/Swiften/Roster/RosterMemoryStorage.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + class RosterMemoryStorage : public RosterStorage { + public: + RosterMemoryStorage(); + + virtual boost::shared_ptr<RosterPayload> getRoster() const { + return roster; + } + + virtual void setRoster(boost::shared_ptr<RosterPayload>); + + private: + boost::shared_ptr<RosterPayload> roster; + }; +} diff --git a/Swiften/Roster/RosterPushResponder.h b/Swiften/Roster/RosterPushResponder.h index b38914b..7200b2d 100644 --- a/Swiften/Roster/RosterPushResponder.h +++ b/Swiften/Roster/RosterPushResponder.h @@ -6,10 +6,10 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Queries/SetResponder.h" -#include "Swiften/Elements/RosterPayload.h" +#include <Swiften/Queries/SetResponder.h> +#include <Swiften/Elements/RosterPayload.h> namespace Swift { class RosterPushResponder : public SetResponder<RosterPayload> { diff --git a/Swiften/Roster/RosterStorage.cpp b/Swiften/Roster/RosterStorage.cpp new file mode 100644 index 0000000..6bf58de --- /dev/null +++ b/Swiften/Roster/RosterStorage.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/RosterStorage.h> + +namespace Swift { + +RosterStorage::~RosterStorage() { +} + +} diff --git a/Swiften/Roster/RosterStorage.h b/Swiften/Roster/RosterStorage.h new file mode 100644 index 0000000..ba24cb3 --- /dev/null +++ b/Swiften/Roster/RosterStorage.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/RosterPayload.h> + +namespace Swift { + class RosterStorage { + public: + virtual ~RosterStorage(); + + virtual boost::shared_ptr<RosterPayload> getRoster() const = 0; + virtual void setRoster(boost::shared_ptr<RosterPayload>) = 0; + }; +} diff --git a/Swiften/Roster/SetRosterRequest.h b/Swiften/Roster/SetRosterRequest.h index e5ae974..6f4d79d 100644 --- a/Swiften/Roster/SetRosterRequest.h +++ b/Swiften/Roster/SetRosterRequest.h @@ -6,11 +6,11 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Queries/Request.h" -#include "Swiften/Elements/RosterPayload.h" +#include <Swiften/Queries/Request.h> +#include <Swiften/Elements/RosterPayload.h> namespace Swift { @@ -19,11 +19,15 @@ namespace Swift { typedef boost::shared_ptr<SetRosterRequest> ref; static ref create(RosterPayload::ref payload, IQRouter* router) { - return ref(new SetRosterRequest(payload, router)); + return ref(new SetRosterRequest(JID(), payload, router)); + } + + static ref create(RosterPayload::ref payload, const JID& to, IQRouter* router) { + return ref(new SetRosterRequest(to, payload, router)); } private: - SetRosterRequest(boost::shared_ptr<RosterPayload> payload, IQRouter* router) : Request(IQ::Set, JID(), boost::shared_ptr<RosterPayload>(payload), router) { + SetRosterRequest(const JID& to, boost::shared_ptr<RosterPayload> payload, IQRouter* router) : Request(IQ::Set, to, boost::shared_ptr<RosterPayload>(payload), router) { } virtual void handleResponse(boost::shared_ptr<Payload> /*payload*/, ErrorPayload::ref error) { diff --git a/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp b/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp index 4ef1cc1..cb9f46f 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp +++ b/Swiften/Roster/UnitTest/XMPPRosterControllerTest.cpp @@ -8,23 +8,32 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h" -#include "Swiften/Roster/XMPPRosterController.h" -#include "Swiften/Elements/Payload.h" -#include "Swiften/Elements/RosterItemPayload.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h> +#include <Swiften/Roster/XMPPRosterController.h> +#include <Swiften/Elements/Payload.h> +#include <Swiften/Elements/RosterItemPayload.h> +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Roster/XMPPRosterImpl.h> +#include <Swiften/Roster/RosterMemoryStorage.h> using namespace Swift; class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(XMPPRosterControllerTest); + CPPUNIT_TEST(testGet_Response); CPPUNIT_TEST(testGet_EmptyResponse); + CPPUNIT_TEST(testGet_NoRosterInStorage); + CPPUNIT_TEST(testGet_NoVersionInStorage); + CPPUNIT_TEST(testGet_VersionInStorage); + CPPUNIT_TEST(testGet_ServerDoesNotSupportVersion); + CPPUNIT_TEST(testGet_ResponseWithoutNewVersion); + CPPUNIT_TEST(testGet_ResponseWithNewVersion); CPPUNIT_TEST(testAdd); CPPUNIT_TEST(testModify); CPPUNIT_TEST(testRemove); + CPPUNIT_TEST(testRemove_RosterStorageUpdated); CPPUNIT_TEST(testMany); CPPUNIT_TEST_SUITE_END(); @@ -34,20 +43,36 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { router_ = new IQRouter(channel_); xmppRoster_ = new XMPPRosterImpl(); handler_ = new XMPPRosterSignalHandler(xmppRoster_); + rosterStorage_ = new RosterMemoryStorage(); jid1_ = JID("foo@bar.com"); jid2_ = JID("alice@wonderland.lit"); jid3_ = JID("jane@austen.lit"); } void tearDown() { + delete rosterStorage_; delete handler_; delete xmppRoster_; delete router_; delete channel_; } + void testGet_Response() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + + testling->requestRoster(); + boost::shared_ptr<RosterPayload> payload = boost::make_shared<RosterPayload>(); + payload->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + payload->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), payload)); + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + } + void testGet_EmptyResponse() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); controller.requestRoster(); @@ -55,7 +80,7 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { } void testAdd() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload(new RosterPayload()); payload->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); @@ -68,8 +93,115 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Bob"), xmppRoster_->getNameForJID(jid1_)); } + void testGet_NoRosterInStorage() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *roster->getVersion()); + } + + void testGet_NoVersionInStorage() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + rosterStorage_->setRoster(boost::make_shared<RosterPayload>()); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string(""), *roster->getVersion()); + } + + void testGet_VersionInStorage() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> payload(new RosterPayload()); + payload->setVersion("foover"); + rosterStorage_->setRoster(payload); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(roster->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("foover"), *roster->getVersion()); + } + + void testGet_ServerDoesNotSupportVersion() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + boost::shared_ptr<RosterPayload> payload(new RosterPayload()); + payload->setVersion("foover"); + rosterStorage_->setRoster(payload); + + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> roster = channel_->sentStanzas[0]->getPayload<RosterPayload>(); + CPPUNIT_ASSERT(!roster->getVersion()); + } + + void testGet_ResponseWithoutNewVersion() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + storedRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), boost::shared_ptr<RosterPayload>())); + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT_EQUAL(jid2_, handler_->getLastJID()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version10"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + } + + void testGet_ResponseWithNewVersion() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + + boost::shared_ptr<RosterPayload> serverRoster(new RosterPayload()); + serverRoster->setVersion("version12"); + serverRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + std::vector<std::string> groups; + groups.push_back("foo"); + groups.push_back("bar"); + serverRoster->addItem(RosterItemPayload(jid3_, "Rabbit", RosterItemPayload::Both, groups)); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), serverRoster)); + + + CPPUNIT_ASSERT_EQUAL(2, handler_->getEventCount()); + CPPUNIT_ASSERT(!xmppRoster_->getItem(jid1_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid2_)); + CPPUNIT_ASSERT(xmppRoster_->getItem(jid3_)); + CPPUNIT_ASSERT_EQUAL(jid3_, handler_->getLastJID()); + CPPUNIT_ASSERT_EQUAL(Add, handler_->getLastEvent()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version12"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(!rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid3_)); + CPPUNIT_ASSERT_EQUAL(2, static_cast<int>(rosterStorage_->getRoster()->getItem(jid3_)->getGroups().size())); + } + void testModify() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -87,9 +219,9 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("Bob2"), xmppRoster_->getNameForJID(jid1_)); } - + void testRemove() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -107,8 +239,31 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { } + void testRemove_RosterStorageUpdated() { + boost::shared_ptr<XMPPRosterController> testling(createController()); + testling->setUseVersioning(true); + boost::shared_ptr<RosterPayload> storedRoster(new RosterPayload()); + storedRoster->setVersion("version10"); + storedRoster->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); + storedRoster->addItem(RosterItemPayload(jid2_, "Alice", RosterItemPayload::Both)); + rosterStorage_->setRoster(storedRoster); + testling->requestRoster(); + channel_->onIQReceived(IQ::createResult("foo@bar.com", channel_->sentStanzas[0]->getID(), boost::shared_ptr<RosterPayload>())); + + boost::shared_ptr<RosterPayload> payload2(new RosterPayload()); + payload2->setVersion("version15"); + payload2->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Remove)); + channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id2", payload2)); + + CPPUNIT_ASSERT(rosterStorage_->getRoster()); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT_EQUAL(std::string("version15"), *rosterStorage_->getRoster()->getVersion()); + CPPUNIT_ASSERT(!rosterStorage_->getRoster()->getItem(jid1_)); + CPPUNIT_ASSERT(rosterStorage_->getRoster()->getItem(jid2_)); + } + void testMany() { - XMPPRosterController controller(router_, xmppRoster_); + XMPPRosterController controller(router_, xmppRoster_, rosterStorage_); boost::shared_ptr<RosterPayload> payload1(new RosterPayload()); payload1->addItem(RosterItemPayload(jid1_, "Bob", RosterItemPayload::Both)); channel_->onIQReceived(IQ::createRequest(IQ::Set, JID(), "id1", payload1)); @@ -171,12 +326,18 @@ class XMPPRosterControllerTest : public CppUnit::TestFixture { handler_->reset(); } + + private: + XMPPRosterController* createController() { + return new XMPPRosterController(router_, xmppRoster_, rosterStorage_); + } private: DummyStanzaChannel* channel_; IQRouter* router_; XMPPRosterImpl* xmppRoster_; XMPPRosterSignalHandler* handler_; + RosterMemoryStorage* rosterStorage_; JID jid1_; JID jid2_; JID jid3_; diff --git a/Swiften/Roster/UnitTest/XMPPRosterImplTest.cpp b/Swiften/Roster/UnitTest/XMPPRosterImplTest.cpp index edb8271..692779f 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterImplTest.cpp +++ b/Swiften/Roster/UnitTest/XMPPRosterImplTest.cpp @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <boost/bind.hpp> -#include "Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h" -#include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h> +#include <Swiften/Roster/XMPPRosterImpl.h> using namespace Swift; diff --git a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp new file mode 100644 index 0000000..d89644a --- /dev/null +++ b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010-2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h> + +#include <boost/bind.hpp> +#include <cassert> + +using namespace Swift; + +XMPPRosterSignalHandler::XMPPRosterSignalHandler(Swift::XMPPRoster* roster) : eventCount(0) { + lastEvent_ = None; + roster->onJIDAdded.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDAdded, this, _1)); + roster->onJIDRemoved.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDRemoved, this, _1)); + roster->onJIDUpdated.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDUpdated, this, _1, _2, _3)); +} + +void XMPPRosterSignalHandler::handleJIDUpdated(const Swift::JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups) { + assert(lastEvent_ == None); + lastJID_ = jid; + lastOldName_ = oldName; + lastOldGroups_ = oldGroups; + lastEvent_ = Update; + eventCount++; +} diff --git a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h index 1bbd8e9..5c51ec3 100644 --- a/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h +++ b/Swiften/Roster/UnitTest/XMPPRosterSignalHandler.h @@ -3,34 +3,25 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ + #pragma once -#include <boost/shared_ptr.hpp> -#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> #include <vector> - -#include "Swiften/Roster/XMPPRosterImpl.h" - -using namespace Swift; - +#include <Swiften/Roster/XMPPRosterImpl.h> enum XMPPRosterEvents {None, Add, Remove, Update}; class XMPPRosterSignalHandler { public: - XMPPRosterSignalHandler(XMPPRoster* roster) { - lastEvent_ = None; - roster->onJIDAdded.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDAdded, this, _1)); - roster->onJIDRemoved.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDRemoved, this, _1)); - roster->onJIDUpdated.connect(boost::bind(&XMPPRosterSignalHandler::handleJIDUpdated, this, _1, _2, _3)); - } + XMPPRosterSignalHandler(Swift::XMPPRoster* roster); XMPPRosterEvents getLastEvent() { return lastEvent_; } - JID getLastJID() { + Swift::JID getLastJID() { return lastJID_; } @@ -46,28 +37,28 @@ public: lastEvent_ = None; } + int getEventCount() const { + return eventCount; + } + private: - void handleJIDAdded(const JID& jid) { + void handleJIDAdded(const Swift::JID& jid) { lastJID_ = jid; lastEvent_ = Add; + eventCount++; } - void handleJIDRemoved(const JID& jid) { + void handleJIDRemoved(const Swift::JID& jid) { lastJID_ = jid; lastEvent_ = Remove; + eventCount++; } - void handleJIDUpdated(const JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups) { - CPPUNIT_ASSERT_EQUAL(None, lastEvent_); - lastJID_ = jid; - lastOldName_ = oldName; - lastOldGroups_ = oldGroups; - lastEvent_ = Update; - } + void handleJIDUpdated(const Swift::JID& jid, const std::string& oldName, const std::vector<std::string>& oldGroups); XMPPRosterEvents lastEvent_; - JID lastJID_; + Swift::JID lastJID_; std::string lastOldName_; std::vector<std::string> lastOldGroups_; - + int eventCount; }; diff --git a/Swiften/Roster/XMPPRoster.cpp b/Swiften/Roster/XMPPRoster.cpp index 61630b4..730569d 100644 --- a/Swiften/Roster/XMPPRoster.cpp +++ b/Swiften/Roster/XMPPRoster.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Roster/XMPPRoster.h" +#include <Swiften/Roster/XMPPRoster.h> namespace Swift { diff --git a/Swiften/Roster/XMPPRoster.h b/Swiften/Roster/XMPPRoster.h index be3494d..4b18940 100644 --- a/Swiften/Roster/XMPPRoster.h +++ b/Swiften/Roster/XMPPRoster.h @@ -9,11 +9,11 @@ #include <boost/optional.hpp> #include <vector> #include <set> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/RosterItemPayload.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/RosterItemPayload.h> #include <Swiften/Roster/XMPPRosterItem.h> namespace Swift { diff --git a/Swiften/Roster/XMPPRosterController.cpp b/Swiften/Roster/XMPPRosterController.cpp index a294d35..c34c6ec 100644 --- a/Swiften/Roster/XMPPRosterController.cpp +++ b/Swiften/Roster/XMPPRosterController.cpp @@ -4,23 +4,25 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Roster/XMPPRosterController.h" +#include <Swiften/Roster/XMPPRosterController.h> #include <boost/bind.hpp> +#include <iostream> -#include "Swiften/Base/foreach.h" -#include "Swiften/Elements/RosterItemPayload.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Roster/GetRosterRequest.h" -#include "Swiften/Roster/XMPPRosterImpl.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/RosterItemPayload.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Roster/GetRosterRequest.h> +#include <Swiften/Roster/XMPPRosterImpl.h> +#include <Swiften/Roster/RosterStorage.h> namespace Swift { /** * The controller does not gain ownership of these parameters. */ -XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRosterImpl* xmppRoster) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster) { - rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, false)); +XMPPRosterController::XMPPRosterController(IQRouter* iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* rosterStorage) : iqRouter_(iqRouter), rosterPushResponder_(iqRouter), xmppRoster_(xmppRoster), rosterStorage_(rosterStorage), useVersioning(false) { + rosterPushResponder_.onRosterReceived.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, false, boost::shared_ptr<RosterPayload>())); rosterPushResponder_.start(); } @@ -30,12 +32,24 @@ XMPPRosterController::~XMPPRosterController() { void XMPPRosterController::requestRoster() { xmppRoster_->clear(); - GetRosterRequest::ref rosterRequest = GetRosterRequest::create(iqRouter_); - rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, true)); + + boost::shared_ptr<RosterPayload> storedRoster = rosterStorage_->getRoster(); + GetRosterRequest::ref rosterRequest; + if (useVersioning) { + std::string version = ""; + if (storedRoster && storedRoster->getVersion()) { + version = *storedRoster->getVersion(); + } + rosterRequest = GetRosterRequest::create(iqRouter_, version); + } + else { + rosterRequest = GetRosterRequest::create(iqRouter_); + } + rosterRequest->onResponse.connect(boost::bind(&XMPPRosterController::handleRosterReceived, this, _1, true, storedRoster)); rosterRequest->send(); } -void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial) { +void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial, boost::shared_ptr<RosterPayload> previousRoster) { if (rosterPayload) { foreach(const RosterItemPayload& item, rosterPayload->getItems()) { //Don't worry about the updated case, the XMPPRoster sorts that out. @@ -46,9 +60,33 @@ void XMPPRosterController::handleRosterReceived(boost::shared_ptr<RosterPayload> } } } + else if (previousRoster) { + // The cached version hasn't changed; emit all items + foreach(const RosterItemPayload& item, previousRoster->getItems()) { + if (item.getSubscription() != RosterItemPayload::Remove) { + xmppRoster_->addContact(item.getJID(), item.getName(), item.getGroups(), item.getSubscription()); + } + else { + std::cerr << "ERROR: Stored invalid roster item" << std::endl; + } + } + } if (initial) { xmppRoster_->onInitialRosterPopulated(); } + if (rosterPayload && rosterPayload->getVersion() && useVersioning) { + saveRoster(*rosterPayload->getVersion()); + } +} + +void XMPPRosterController::saveRoster(const std::string& version) { + std::vector<XMPPRosterItem> items = xmppRoster_->getItems(); + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion(version); + foreach(const XMPPRosterItem& item, items) { + roster->addItem(RosterItemPayload(item.getJID(), item.getName(), item.getSubscription(), item.getGroups())); + } + rosterStorage_->setRoster(roster); } } diff --git a/Swiften/Roster/XMPPRosterController.h b/Swiften/Roster/XMPPRosterController.h index eeb84f6..f105463 100644 --- a/Swiften/Roster/XMPPRosterController.h +++ b/Swiften/Roster/XMPPRosterController.h @@ -8,31 +8,39 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/JID/JID.h" +#include <Swiften/JID/JID.h> #include <string> -#include "Swiften/Elements/IQ.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Roster/RosterPushResponder.h" -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Elements/IQ.h> +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Roster/RosterPushResponder.h> +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class IQRouter; class XMPPRosterImpl; + class RosterStorage; class XMPPRosterController { public: - XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster); + XMPPRosterController(IQRouter *iqRouter, XMPPRosterImpl* xmppRoster, RosterStorage* storage); ~XMPPRosterController(); void requestRoster(); + void setUseVersioning(bool b) { + useVersioning = b; + } + private: - void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial); + void handleRosterReceived(boost::shared_ptr<RosterPayload> rosterPayload, bool initial, boost::shared_ptr<RosterPayload> previousRoster); + void saveRoster(const std::string& version); private: IQRouter* iqRouter_; RosterPushResponder rosterPushResponder_; XMPPRosterImpl* xmppRoster_; + RosterStorage* rosterStorage_; + bool useVersioning; }; } diff --git a/Swiften/Roster/XMPPRosterImpl.h b/Swiften/Roster/XMPPRosterImpl.h index a44a1ce..cbb3166 100644 --- a/Swiften/Roster/XMPPRosterImpl.h +++ b/Swiften/Roster/XMPPRosterImpl.h @@ -9,7 +9,7 @@ #include <map> #include <set> -#include "Swiften/Roster/XMPPRoster.h" +#include <Swiften/Roster/XMPPRoster.h> namespace Swift { class XMPPRosterImpl : public XMPPRoster { diff --git a/Swiften/SASL/ClientAuthenticator.cpp b/Swiften/SASL/ClientAuthenticator.cpp index 533f172..e0900a3 100644 --- a/Swiften/SASL/ClientAuthenticator.cpp +++ b/Swiften/SASL/ClientAuthenticator.cpp @@ -1,10 +1,10 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2011 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/ClientAuthenticator.h" +#include <Swiften/SASL/ClientAuthenticator.h> namespace Swift { diff --git a/Swiften/SASL/ClientAuthenticator.h b/Swiften/SASL/ClientAuthenticator.h index 33db75f..8710ac8 100644 --- a/Swiften/SASL/ClientAuthenticator.h +++ b/Swiften/SASL/ClientAuthenticator.h @@ -7,9 +7,11 @@ #pragma once #include <boost/optional.hpp> - #include <string> -#include "Swiften/Base/ByteArray.h" +#include <vector> + +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class ClientAuthenticator { @@ -21,13 +23,13 @@ namespace Swift { return name; } - void setCredentials(const std::string& authcid, const std::string& password, const std::string& authzid = std::string()) { + void setCredentials(const std::string& authcid, const SafeByteArray& password, const std::string& authzid = std::string()) { this->authcid = authcid; this->password = password; this->authzid = authzid; } - virtual boost::optional<ByteArray> getResponse() const = 0; + virtual boost::optional<SafeByteArray> getResponse() const = 0; virtual bool setChallenge(const boost::optional<ByteArray>&) = 0; const std::string& getAuthenticationID() const { @@ -38,14 +40,14 @@ namespace Swift { return authzid; } - const std::string& getPassword() const { + const SafeByteArray& getPassword() const { return password; } private: std::string name; std::string authcid; - std::string password; + SafeByteArray password; std::string authzid; }; } diff --git a/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp b/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp index 6892948..5e78ee2 100644 --- a/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp +++ b/Swiften/SASL/DIGESTMD5ClientAuthenticator.cpp @@ -4,21 +4,23 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/DIGESTMD5ClientAuthenticator.h" +#include <Swiften/SASL/DIGESTMD5ClientAuthenticator.h> #include <cassert> -#include "Swiften/StringCodecs/MD5.h" -#include "Swiften/StringCodecs/Hexify.h" +#include <Swiften/StringCodecs/MD5.h> +#include <Swiften/StringCodecs/Hexify.h> +#include <Swiften/Base/Concat.h> +#include <Swiften/Base/Algorithm.h> namespace Swift { DIGESTMD5ClientAuthenticator::DIGESTMD5ClientAuthenticator(const std::string& host, const std::string& nonce) : ClientAuthenticator("DIGEST-MD5"), step(Initial), host(host), cnonce(nonce) { } -boost::optional<ByteArray> DIGESTMD5ClientAuthenticator::getResponse() const { +boost::optional<SafeByteArray> DIGESTMD5ClientAuthenticator::getResponse() const { if (step == Initial) { - return boost::optional<ByteArray>(); + return boost::optional<SafeByteArray>(); } else if (step == Response) { std::string realm; @@ -30,16 +32,20 @@ boost::optional<ByteArray> DIGESTMD5ClientAuthenticator::getResponse() const { std::string nc = "00000001"; // Compute the response value - ByteArray A1 = MD5::getHash(getAuthenticationID() + ":" + realm + ":" + getPassword()) + ":" + *challenge.getValue("nonce") + ":" + cnonce; + ByteArray A1 = concat( + MD5::getHash( + concat(createSafeByteArray(getAuthenticationID().c_str()), createSafeByteArray(":"), createSafeByteArray(realm.c_str()), createSafeByteArray(":"), getPassword())), + createByteArray(":"), createByteArray(*challenge.getValue("nonce")), createByteArray(":"), createByteArray(cnonce)); if (!getAuthorizationID().empty()) { - A1 += ":" + getAuthenticationID(); + append(A1, createByteArray(":" + getAuthenticationID())); } - std::string A2 = "AUTHENTICATE:" + digestURI; + ByteArray A2 = createByteArray("AUTHENTICATE:" + digestURI); + + std::string responseValue = Hexify::hexify(MD5::getHash(createByteArray( + Hexify::hexify(MD5::getHash(A1)) + ":" + + *challenge.getValue("nonce") + ":" + nc + ":" + cnonce + ":" + qop + ":" + + Hexify::hexify(MD5::getHash(A2))))); - std::string responseValue = Hexify::hexify(MD5::getHash( - Hexify::hexify(MD5::getHash(A1)) + ":" - + *challenge.getValue("nonce") + ":" + nc + ":" + cnonce + ":" + qop + ":" - + Hexify::hexify(MD5::getHash(A2)))); DIGESTMD5Properties response; response.setValue("username", getAuthenticationID()); @@ -56,10 +62,10 @@ boost::optional<ByteArray> DIGESTMD5ClientAuthenticator::getResponse() const { if (!getAuthorizationID().empty()) { response.setValue("authzid", getAuthorizationID()); } - return response.serialize(); + return createSafeByteArray(response.serialize()); } else { - return boost::optional<ByteArray>(); + return boost::optional<SafeByteArray>(); } } diff --git a/Swiften/SASL/DIGESTMD5ClientAuthenticator.h b/Swiften/SASL/DIGESTMD5ClientAuthenticator.h index 50dd9aa..55bd592 100644 --- a/Swiften/SASL/DIGESTMD5ClientAuthenticator.h +++ b/Swiften/SASL/DIGESTMD5ClientAuthenticator.h @@ -9,17 +9,18 @@ #include <map> #include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/SASL/ClientAuthenticator.h" -#include "Swiften/SASL/DIGESTMD5Properties.h" +#include <vector> +#include <Swiften/SASL/ClientAuthenticator.h> +#include <Swiften/SASL/DIGESTMD5Properties.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class DIGESTMD5ClientAuthenticator : public ClientAuthenticator { public: DIGESTMD5ClientAuthenticator(const std::string& host, const std::string& nonce); - virtual boost::optional<ByteArray> getResponse() const; - virtual bool setChallenge(const boost::optional<ByteArray>&); + virtual boost::optional<SafeByteArray> getResponse() const; + virtual bool setChallenge(const boost::optional<std::vector<unsigned char> >&); private: enum Step { diff --git a/Swiften/SASL/DIGESTMD5Properties.cpp b/Swiften/SASL/DIGESTMD5Properties.cpp index dfff9c8..6d406e0 100644 --- a/Swiften/SASL/DIGESTMD5Properties.cpp +++ b/Swiften/SASL/DIGESTMD5Properties.cpp @@ -4,20 +4,21 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/DIGESTMD5Properties.h" +#include <Swiften/SASL/DIGESTMD5Properties.h> +#include <Swiften/Base/Algorithm.h> namespace Swift { namespace { bool insideQuotes(const ByteArray& v) { - if (v.getSize() == 0) { + if (v.empty()) { return false; } - else if (v.getSize() == 1) { + else if (v.size() == 1) { return v[0] == '"'; } else if (v[0] == '"') { - return v[v.getSize() - 1] != '"'; + return v[v.size() - 1] != '"'; } else { return false; @@ -25,16 +26,16 @@ namespace { } ByteArray stripQuotes(const ByteArray& v) { - const char* data = reinterpret_cast<const char*>(v.getData()); - size_t size = v.getSize(); + const char* data = reinterpret_cast<const char*>(vecptr(v)); + size_t size = v.size(); if (v[0] == '"') { data++; size--; } - if (v[v.getSize() - 1] == '"') { + if (v[v.size() - 1] == '"') { size--; } - return ByteArray(data, size); + return createByteArray(data, size); } } @@ -46,42 +47,42 @@ DIGESTMD5Properties DIGESTMD5Properties::parse(const ByteArray& data) { bool inKey = true; ByteArray currentKey; ByteArray currentValue; - for (size_t i = 0; i < data.getSize(); ++i) { + for (size_t i = 0; i < data.size(); ++i) { char c = data[i]; if (inKey) { if (c == '=') { inKey = false; } else { - currentKey += c; + currentKey.push_back(c); } } else { if (c == ',' && !insideQuotes(currentValue)) { - std::string key = currentKey.toString(); + std::string key = byteArrayToString(currentKey); if (isQuoted(key)) { - result.setValue(key, stripQuotes(currentValue).toString()); + result.setValue(key, byteArrayToString(stripQuotes(currentValue))); } else { - result.setValue(key, currentValue.toString()); + result.setValue(key, byteArrayToString(currentValue)); } inKey = true; currentKey = ByteArray(); currentValue = ByteArray(); } else { - currentValue += c; + currentValue.push_back(c); } } } - if (!currentKey.isEmpty()) { - std::string key = currentKey.toString(); + if (!currentKey.empty()) { + std::string key = byteArrayToString(currentKey); if (isQuoted(key)) { - result.setValue(key, stripQuotes(currentValue).toString()); + result.setValue(key, byteArrayToString(stripQuotes(currentValue))); } else { - result.setValue(key, currentValue.toString()); + result.setValue(key, byteArrayToString(currentValue)); } } @@ -92,15 +93,17 @@ ByteArray DIGESTMD5Properties::serialize() const { ByteArray result; for(DIGESTMD5PropertiesMap::const_iterator i = properties.begin(); i != properties.end(); ++i) { if (i != properties.begin()) { - result += ','; + result.push_back(','); } - result += i->first; - result += '='; + append(result, createByteArray(i->first)); + result.push_back('='); if (isQuoted(i->first)) { - result += "\"" + i->second + "\""; + append(result, createByteArray("\"")); + append(result, i->second); + append(result, createByteArray("\"")); } else { - result += i->second; + append(result, i->second); } } return result; @@ -109,7 +112,7 @@ ByteArray DIGESTMD5Properties::serialize() const { boost::optional<std::string> DIGESTMD5Properties::getValue(const std::string& key) const { DIGESTMD5PropertiesMap::const_iterator i = properties.find(key); if (i != properties.end()) { - return i->second.toString(); + return byteArrayToString(i->second); } else { return boost::optional<std::string>(); @@ -117,7 +120,7 @@ boost::optional<std::string> DIGESTMD5Properties::getValue(const std::string& ke } void DIGESTMD5Properties::setValue(const std::string& key, const std::string& value) { - properties.insert(DIGESTMD5PropertiesMap::value_type(key, ByteArray(value))); + properties.insert(DIGESTMD5PropertiesMap::value_type(key, createByteArray(value))); } bool DIGESTMD5Properties::isQuoted(const std::string& p) { diff --git a/Swiften/SASL/DIGESTMD5Properties.h b/Swiften/SASL/DIGESTMD5Properties.h index 6e2e592..ef87574 100644 --- a/Swiften/SASL/DIGESTMD5Properties.h +++ b/Swiften/SASL/DIGESTMD5Properties.h @@ -10,7 +10,7 @@ #include <boost/optional.hpp> #include <string> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> namespace Swift { class DIGESTMD5Properties { diff --git a/Swiften/SASL/PLAINClientAuthenticator.cpp b/Swiften/SASL/PLAINClientAuthenticator.cpp index 2ea2425..7872174 100644 --- a/Swiften/SASL/PLAINClientAuthenticator.cpp +++ b/Swiften/SASL/PLAINClientAuthenticator.cpp @@ -4,15 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/PLAINClientAuthenticator.h" +#include <Swiften/SASL/PLAINClientAuthenticator.h> +#include <Swiften/Base/Concat.h> namespace Swift { PLAINClientAuthenticator::PLAINClientAuthenticator() : ClientAuthenticator("PLAIN") { } -boost::optional<ByteArray> PLAINClientAuthenticator::getResponse() const { - return ByteArray(getAuthorizationID()) + '\0' + ByteArray(getAuthenticationID()) + '\0' + ByteArray(getPassword()); +boost::optional<SafeByteArray> PLAINClientAuthenticator::getResponse() const { + return concat(createSafeByteArray(getAuthorizationID()), createSafeByteArray('\0'), createSafeByteArray(getAuthenticationID()), createSafeByteArray('\0'), getPassword()); } bool PLAINClientAuthenticator::setChallenge(const boost::optional<ByteArray>&) { diff --git a/Swiften/SASL/PLAINClientAuthenticator.h b/Swiften/SASL/PLAINClientAuthenticator.h index 959244d..83e45c1 100644 --- a/Swiften/SASL/PLAINClientAuthenticator.h +++ b/Swiften/SASL/PLAINClientAuthenticator.h @@ -6,14 +6,15 @@ #pragma once -#include "Swiften/SASL/ClientAuthenticator.h" +#include <Swiften/SASL/ClientAuthenticator.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class PLAINClientAuthenticator : public ClientAuthenticator { public: PLAINClientAuthenticator(); - virtual boost::optional<ByteArray> getResponse() const; + virtual boost::optional<SafeByteArray> getResponse() const; virtual bool setChallenge(const boost::optional<ByteArray>&); }; } diff --git a/Swiften/SASL/PLAINMessage.cpp b/Swiften/SASL/PLAINMessage.cpp index 3728b39..20ffea7 100644 --- a/Swiften/SASL/PLAINMessage.cpp +++ b/Swiften/SASL/PLAINMessage.cpp @@ -4,41 +4,41 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/PLAINMessage.h" +#include <Swiften/SASL/PLAINMessage.h> +#include <Swiften/Base/Concat.h> namespace Swift { -PLAINMessage::PLAINMessage(const std::string& authcid, const std::string& password, const std::string& authzid) : authcid(authcid), authzid(authzid), password(password) { +PLAINMessage::PLAINMessage(const std::string& authcid, const SafeByteArray& password, const std::string& authzid) : authcid(authcid), authzid(authzid), password(password) { } -PLAINMessage::PLAINMessage(const ByteArray& value) { +PLAINMessage::PLAINMessage(const SafeByteArray& value) { size_t i = 0; - while (i < value.getSize() && value[i] != '\0') { + while (i < value.size() && value[i] != '\0') { authzid += value[i]; ++i; } - if (i == value.getSize()) { + if (i == value.size()) { return; } ++i; - while (i < value.getSize() && value[i] != '\0') { + while (i < value.size() && value[i] != '\0') { authcid += value[i]; ++i; } - if (i == value.getSize()) { + if (i == value.size()) { authcid = ""; return; } ++i; - while (i < value.getSize()) { - password += value[i]; + while (i < value.size()) { + password.push_back(value[i]); ++i; } } -ByteArray PLAINMessage::getValue() const { - std::string s = authzid + '\0' + authcid + '\0' + password; - return ByteArray(s.c_str(), s.size()); +SafeByteArray PLAINMessage::getValue() const { + return concat(createSafeByteArray(authzid), createSafeByteArray('\0'), createSafeByteArray(authcid), createSafeByteArray('\0'), password); } } diff --git a/Swiften/SASL/PLAINMessage.h b/Swiften/SASL/PLAINMessage.h index d08d70d..46ee8f7 100644 --- a/Swiften/SASL/PLAINMessage.h +++ b/Swiften/SASL/PLAINMessage.h @@ -9,21 +9,21 @@ #pragma once #include <string> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class PLAINMessage { public: - PLAINMessage(const std::string& authcid, const std::string& password, const std::string& authzid = ""); - PLAINMessage(const ByteArray& value); + PLAINMessage(const std::string& authcid, const SafeByteArray& password, const std::string& authzid = ""); + PLAINMessage(const SafeByteArray& value); - ByteArray getValue() const; + SafeByteArray getValue() const; const std::string& getAuthenticationID() const { return authcid; } - const std::string& getPassword() const { + const SafeByteArray& getPassword() const { return password; } @@ -34,6 +34,6 @@ namespace Swift { private: std::string authcid; std::string authzid; - std::string password; + SafeByteArray password; }; } diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp index 33de014..7842b4f 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -4,17 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" +#include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h> #include <cassert> #include <map> #include <boost/lexical_cast.hpp> -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/StringCodecs/Base64.h" -#include "Swiften/StringCodecs/HMACSHA1.h" -#include "Swiften/StringCodecs/PBKDF2.h" -#include "Swiften/IDN/StringPrep.h" +#include <Swiften/StringCodecs/SHA1.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/StringCodecs/HMAC_SHA1.h> +#include <Swiften/StringCodecs/PBKDF2.h> +#include <Swiften/IDN/StringPrep.h> +#include <Swiften/Base/Concat.h> namespace Swift { @@ -38,23 +39,23 @@ static std::string escape(const std::string& s) { SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const std::string& nonce, bool useChannelBinding) : ClientAuthenticator(useChannelBinding ? "SCRAM-SHA-1-PLUS" : "SCRAM-SHA-1"), step(Initial), clientnonce(nonce), useChannelBinding(useChannelBinding) { } -boost::optional<ByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const { +boost::optional<SafeByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const { if (step == Initial) { - return getGS2Header() + getInitialBareClientMessage(); + return createSafeByteArray(concat(getGS2Header(), getInitialBareClientMessage())); } else if (step == Proof) { - ByteArray clientKey = HMACSHA1::getResult(saltedPassword, "Client Key"); + ByteArray clientKey = HMAC_SHA1()(saltedPassword, createByteArray("Client Key")); ByteArray storedKey = SHA1::getHash(clientKey); - ByteArray clientSignature = HMACSHA1::getResult(storedKey, authMessage); + ByteArray clientSignature = HMAC_SHA1()(createSafeByteArray(storedKey), authMessage); ByteArray clientProof = clientKey; - for (unsigned int i = 0; i < clientProof.getSize(); ++i) { + for (unsigned int i = 0; i < clientProof.size(); ++i) { clientProof[i] ^= clientSignature[i]; } - ByteArray result = getFinalMessageWithoutProof() + ",p=" + Base64::encode(clientProof); - return result; + ByteArray result = concat(getFinalMessageWithoutProof(), createByteArray(",p="), createByteArray(Base64::encode(clientProof))); + return createSafeByteArray(result); } else { - return boost::optional<ByteArray>(); + return boost::optional<SafeByteArray>(); } } @@ -65,7 +66,7 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray> } initialServerMessage = *challenge; - std::map<char, std::string> keys = parseMap(initialServerMessage.toString()); + std::map<char, std::string> keys = parseMap(byteArrayToString(initialServerMessage)); // Extract the salt ByteArray salt = Base64::decode(keys['s']); @@ -79,7 +80,7 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray> if (receivedClientNonce != clientnonce) { return false; } - serverNonce = clientServerNonce.substr(clientnonce.size(), clientServerNonce.npos); + serverNonce = createByteArray(clientServerNonce.substr(clientnonce.size(), clientServerNonce.npos)); // Extract the number of iterations int iterations = 0; @@ -100,19 +101,19 @@ bool SCRAMSHA1ClientAuthenticator::setChallenge(const boost::optional<ByteArray> // Compute all the values needed for the server signature try { - saltedPassword = PBKDF2::encode(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations); + saltedPassword = PBKDF2::encode<HMAC_SHA1>(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations); } catch (const std::exception&) { } - authMessage = getInitialBareClientMessage() + "," + initialServerMessage + "," + getFinalMessageWithoutProof(); - ByteArray serverKey = HMACSHA1::getResult(saltedPassword, "Server Key"); - serverSignature = HMACSHA1::getResult(serverKey, authMessage); + authMessage = concat(getInitialBareClientMessage(), createByteArray(","), initialServerMessage, createByteArray(","), getFinalMessageWithoutProof()); + ByteArray serverKey = HMAC_SHA1()(saltedPassword, createByteArray("Server Key")); + serverSignature = HMAC_SHA1()(serverKey, authMessage); step = Proof; return true; } else if (step == Proof) { - ByteArray result = ByteArray("v=") + ByteArray(Base64::encode(serverSignature)); + ByteArray result = concat(createByteArray("v="), createByteArray(Base64::encode(serverSignature))); step = Final; return challenge && challenge == result; } @@ -135,7 +136,7 @@ std::map<char, std::string> SCRAMSHA1ClientAuthenticator::parseMap(const std::st i++; } else if (s[i] == ',') { - result[key] = value; + result[static_cast<size_t>(key)] = value; value = ""; expectKey = true; } @@ -152,24 +153,24 @@ std::map<char, std::string> SCRAMSHA1ClientAuthenticator::parseMap(const std::st ByteArray SCRAMSHA1ClientAuthenticator::getInitialBareClientMessage() const { std::string authenticationID; try { - authenticationID = StringPrep::getPrepared(getAuthenticationID(), StringPrep::SASLPrep); + authenticationID = StringPrep::getPrepared(getAuthenticationID(), StringPrep::SASLPrep); } catch (const std::exception&) { } - return ByteArray(std::string("n=" + escape(authenticationID) + ",r=" + clientnonce)); + return createByteArray(std::string("n=" + escape(authenticationID) + ",r=" + clientnonce)); } ByteArray SCRAMSHA1ClientAuthenticator::getGS2Header() const { - ByteArray channelBindingHeader("n"); + ByteArray channelBindingHeader(createByteArray("n")); if (tlsChannelBindingData) { if (useChannelBinding) { - channelBindingHeader = ByteArray("p=tls-unique"); + channelBindingHeader = createByteArray("p=tls-unique"); } else { - channelBindingHeader = ByteArray("y"); + channelBindingHeader = createByteArray("y"); } } - return channelBindingHeader + ByteArray(",") + (getAuthorizationID().empty() ? "" : "a=" + escape(getAuthorizationID())) + ","; + return concat(channelBindingHeader, createByteArray(","), (getAuthorizationID().empty() ? ByteArray() : createByteArray("a=" + escape(getAuthorizationID()))), createByteArray(",")); } void SCRAMSHA1ClientAuthenticator::setTLSChannelBindingData(const ByteArray& channelBindingData) { @@ -181,7 +182,7 @@ ByteArray SCRAMSHA1ClientAuthenticator::getFinalMessageWithoutProof() const { if (useChannelBinding && tlsChannelBindingData) { channelBindData = *tlsChannelBindingData; } - return ByteArray("c=") + Base64::encode(getGS2Header() + channelBindData) + ",r=" + clientnonce + serverNonce; + return concat(createByteArray("c=" + Base64::encode(concat(getGS2Header(), channelBindData)) + ",r=" + clientnonce), serverNonce); } diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h index 602fc94..d140013 100644 --- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h @@ -10,8 +10,8 @@ #include <boost/optional.hpp> #include <string> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/SASL/ClientAuthenticator.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/SASL/ClientAuthenticator.h> namespace Swift { class SCRAMSHA1ClientAuthenticator : public ClientAuthenticator { @@ -20,7 +20,7 @@ namespace Swift { void setTLSChannelBindingData(const ByteArray& channelBindingData); - virtual boost::optional<ByteArray> getResponse() const; + virtual boost::optional<SafeByteArray> getResponse() const; virtual bool setChallenge(const boost::optional<ByteArray>&); private: diff --git a/Swiften/SASL/SConscript b/Swiften/SASL/SConscript index 5a0cdef..085e49d 100644 --- a/Swiften/SASL/SConscript +++ b/Swiften/SASL/SConscript @@ -12,6 +12,7 @@ objects = myenv.SwiftenObject([ "DIGESTMD5ClientAuthenticator.cpp", ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) + env.Append(UNITTEST_SOURCES = [ File("UnitTest/PLAINMessageTest.cpp"), File("UnitTest/PLAINClientAuthenticatorTest.cpp"), diff --git a/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp index 54f0571..38bab15 100644 --- a/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp +++ b/Swiften/SASL/UnitTest/DIGESTMD5ClientAuthenticatorTest.cpp @@ -4,11 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/SASL/DIGESTMD5ClientAuthenticator.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/SASL/DIGESTMD5ClientAuthenticator.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -30,29 +32,29 @@ class DIGESTMD5ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetResponse() { DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh"); - testling.setCredentials("user", "pass", ""); - testling.setChallenge(ByteArray( + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setChallenge(createByteArray( "realm=\"example.com\"," "nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\"," "qop=auth,charset=utf-8,algorithm=md5-sess")); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=088891c800ecff1b842159ad6459104a,username=\"user\""), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=088891c800ecff1b842159ad6459104a,username=\"user\""), response); } void testGetResponse_WithAuthorizationID() { DIGESTMD5ClientAuthenticator testling("xmpp.example.com", "abcdefgh"); - testling.setCredentials("user", "pass", "myauthzid"); - testling.setChallenge(ByteArray( + testling.setCredentials("user", createSafeByteArray("pass"), "myauthzid"); + testling.setChallenge(createByteArray( "realm=\"example.com\"," "nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\"," "qop=auth,charset=utf-8,algorithm=md5-sess")); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("authzid=\"myauthzid\",charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=4293834432b6e7889a2dee7e8fe7dd06,username=\"user\""), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("authzid=\"myauthzid\",charset=utf-8,cnonce=\"abcdefgh\",digest-uri=\"xmpp/xmpp.example.com\",nc=00000001,nonce=\"O6skKPuaCZEny3hteI19qXMBXSadoWs840MchORo\",qop=auth,realm=\"example.com\",response=4293834432b6e7889a2dee7e8fe7dd06,username=\"user\""), response); } }; diff --git a/Swiften/SASL/UnitTest/DIGESTMD5PropertiesTest.cpp b/Swiften/SASL/UnitTest/DIGESTMD5PropertiesTest.cpp index 152a41e..d664f14 100644 --- a/Swiften/SASL/UnitTest/DIGESTMD5PropertiesTest.cpp +++ b/Swiften/SASL/UnitTest/DIGESTMD5PropertiesTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/SASL/DIGESTMD5Properties.h" +#include <Swiften/SASL/DIGESTMD5Properties.h> using namespace Swift; @@ -19,7 +19,7 @@ class DIGESTMD5PropertiesTest : public CppUnit::TestFixture { public: void testParse() { - DIGESTMD5Properties properties = DIGESTMD5Properties::parse(ByteArray( + DIGESTMD5Properties properties = DIGESTMD5Properties::parse(createByteArray( "realm=\"myrealm1\",realm=\"myrealm2\",nonce=\"mynonce\"," "algorithm=md5-sess,charset=utf-8")); @@ -47,8 +47,8 @@ class DIGESTMD5PropertiesTest : public CppUnit::TestFixture { properties.setValue("username", "myuser"); ByteArray result = properties.serialize(); - ByteArray expected("authzid=\"myauthzid\",charset=utf-8,cnonce=\"mycnonce\",digest-uri=\"mydigesturi\",nc=1,nonce=\"mynonce\",qop=auth,realm=\"myrealm\",response=myresponse,username=\"myuser\""); - CPPUNIT_ASSERT_EQUAL(expected.toString(), result.toString()); + ByteArray expected(createByteArray("authzid=\"myauthzid\",charset=utf-8,cnonce=\"mycnonce\",digest-uri=\"mydigesturi\",nc=1,nonce=\"mynonce\",qop=auth,realm=\"myrealm\",response=myresponse,username=\"myuser\"")); + CPPUNIT_ASSERT_EQUAL(byteArrayToString(expected), byteArrayToString(result)); } }; diff --git a/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp index 33914b2..3416923 100644 --- a/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp +++ b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp @@ -4,8 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/SASL/PLAINClientAuthenticator.h" +#include <Swiften/SASL/PLAINClientAuthenticator.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -21,17 +22,17 @@ class PLAINClientAuthenticatorTest : public CppUnit::TestFixture { void testGetResponse_WithoutAuthzID() { PLAINClientAuthenticator testling; - testling.setCredentials("user", "pass"); + testling.setCredentials("user", createSafeByteArray("pass")); - CPPUNIT_ASSERT_EQUAL(*testling.getResponse(), ByteArray("\0user\0pass", 10)); + CPPUNIT_ASSERT_EQUAL(*testling.getResponse(), createSafeByteArray("\0user\0pass", 10)); } void testGetResponse_WithAuthzID() { PLAINClientAuthenticator testling; - testling.setCredentials("user", "pass", "authz"); + testling.setCredentials("user", createSafeByteArray("pass"), "authz"); - CPPUNIT_ASSERT_EQUAL(*testling.getResponse(), ByteArray("authz\0user\0pass", 15)); + CPPUNIT_ASSERT_EQUAL(*testling.getResponse(), createSafeByteArray("authz\0user\0pass", 15)); } }; diff --git a/Swiften/SASL/UnitTest/PLAINMessageTest.cpp b/Swiften/SASL/UnitTest/PLAINMessageTest.cpp index d517f0d..e917af5 100644 --- a/Swiften/SASL/UnitTest/PLAINMessageTest.cpp +++ b/Swiften/SASL/UnitTest/PLAINMessageTest.cpp @@ -4,12 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/SASL/PLAINMessage.h" +#include <Swiften/SASL/PLAINMessage.h> using namespace Swift; @@ -28,39 +29,39 @@ class PLAINMessageTest : public CppUnit::TestFixture PLAINMessageTest() {} void testGetValue_WithoutAuthzID() { - PLAINMessage message("user", "pass"); - CPPUNIT_ASSERT_EQUAL(message.getValue(), ByteArray("\0user\0pass", 10)); + PLAINMessage message("user", createSafeByteArray("pass")); + CPPUNIT_ASSERT_EQUAL(message.getValue(), createSafeByteArray("\0user\0pass", 10)); } void testGetValue_WithAuthzID() { - PLAINMessage message("user", "pass", "authz"); - CPPUNIT_ASSERT_EQUAL(message.getValue(), ByteArray("authz\0user\0pass", 15)); + PLAINMessage message("user", createSafeByteArray("pass"), "authz"); + CPPUNIT_ASSERT_EQUAL(message.getValue(), createSafeByteArray("authz\0user\0pass", 15)); } void testConstructor_WithoutAuthzID() { - PLAINMessage message(ByteArray("\0user\0pass", 10)); + PLAINMessage message(createSafeByteArray("\0user\0pass", 10)); CPPUNIT_ASSERT_EQUAL(std::string(""), message.getAuthorizationID()); CPPUNIT_ASSERT_EQUAL(std::string("user"), message.getAuthenticationID()); - CPPUNIT_ASSERT_EQUAL(std::string("pass"), message.getPassword()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("pass"), message.getPassword()); } void testConstructor_WithAuthzID() { - PLAINMessage message(ByteArray("authz\0user\0pass", 15)); + PLAINMessage message(createSafeByteArray("authz\0user\0pass", 15)); CPPUNIT_ASSERT_EQUAL(std::string("authz"), message.getAuthorizationID()); CPPUNIT_ASSERT_EQUAL(std::string("user"), message.getAuthenticationID()); - CPPUNIT_ASSERT_EQUAL(std::string("pass"), message.getPassword()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("pass"), message.getPassword()); } void testConstructor_NoAuthcid() { - PLAINMessage message(ByteArray("authzid", 7)); + PLAINMessage message(createSafeByteArray("authzid", 7)); CPPUNIT_ASSERT_EQUAL(std::string(""), message.getAuthenticationID()); } void testConstructor_NoPassword() { - PLAINMessage message(ByteArray("authzid\0authcid", 15)); + PLAINMessage message(createSafeByteArray("authzid\0authcid", 15)); CPPUNIT_ASSERT_EQUAL(std::string(""), message.getAuthenticationID()); } diff --git a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp index 5d0edbd..f0ca01c 100644 --- a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp +++ b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp @@ -4,11 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> + #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/SASL/SCRAMSHA1ClientAuthenticator.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -41,179 +43,179 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { void testGetInitialResponse() { SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("n,,n=user,r=abcdefghABCDEFGH"), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("n,,n=user,r=abcdefghABCDEFGH"), response); } void testGetInitialResponse_UsernameHasSpecialChars() { SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); - testling.setCredentials(",us=,er=", "pass", ""); + testling.setCredentials(",us=,er=", createSafeByteArray("pass"), ""); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("n,,n==2Cus=3D=2Cer=3D,r=abcdefghABCDEFGH"), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("n,,n==2Cus=3D=2Cer=3D,r=abcdefghABCDEFGH"), response); } void testGetInitialResponse_WithAuthorizationID() { SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); - testling.setCredentials("user", "pass", "auth"); + testling.setCredentials("user", createSafeByteArray("pass"), "auth"); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("n,a=auth,n=user,r=abcdefghABCDEFGH"), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("n,a=auth,n=user,r=abcdefghABCDEFGH"), response); } void testGetInitialResponse_WithAuthorizationIDWithSpecialChars() { SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); - testling.setCredentials("user", "pass", "a=u,th"); + testling.setCredentials("user", createSafeByteArray("pass"), "a=u,th"); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("n,a=a=3Du=2Cth,n=user,r=abcdefghABCDEFGH"), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("n,a=a=3Du=2Cth,n=user,r=abcdefghABCDEFGH"), response); } void testGetInitialResponse_WithoutChannelBindingWithTLSChannelBindingData() { SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false); - testling.setTLSChannelBindingData("xyza"); - testling.setCredentials("user", "pass", ""); + testling.setTLSChannelBindingData(createByteArray("xyza")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("y,,n=user,r=abcdefghABCDEFGH"), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("y,,n=user,r=abcdefghABCDEFGH"), response); } void testGetInitialResponse_WithChannelBindingWithTLSChannelBindingData() { SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", true); - testling.setTLSChannelBindingData("xyza"); - testling.setCredentials("user", "pass", ""); + testling.setTLSChannelBindingData(createByteArray("xyza")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("p=tls-unique,,n=user,r=abcdefghABCDEFGH"), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("p=tls-unique,,n=user,r=abcdefghABCDEFGH"), response); } void testGetFinalResponse() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); - testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("c=biws,r=abcdefghABCDEFGH,p=CZbjGDpIteIJwQNBgO0P8pKkMGY="), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("c=biws,r=abcdefghABCDEFGH,p=CZbjGDpIteIJwQNBgO0P8pKkMGY="), response); } void testGetFinalResponse_WithoutChannelBindingWithTLSChannelBindingData() { SCRAMSHA1ClientAuthenticator testling("abcdefgh", false); - testling.setCredentials("user", "pass", ""); - testling.setTLSChannelBindingData("xyza"); - testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setTLSChannelBindingData(createByteArray("xyza")); + testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("c=eSws,r=abcdefghABCDEFGH,p=JNpsiFEcxZvNZ1+FFBBqrYvYxMk="), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("c=eSws,r=abcdefghABCDEFGH,p=JNpsiFEcxZvNZ1+FFBBqrYvYxMk="), response); } void testGetFinalResponse_WithChannelBindingWithTLSChannelBindingData() { SCRAMSHA1ClientAuthenticator testling("abcdefgh", true); - testling.setCredentials("user", "pass", ""); - testling.setTLSChannelBindingData("xyza"); - testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setTLSChannelBindingData(createByteArray("xyza")); + testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); - ByteArray response = *testling.getResponse(); + SafeByteArray response = *testling.getResponse(); - CPPUNIT_ASSERT_EQUAL(std::string("c=cD10bHMtdW5pcXVlLCx4eXph,r=abcdefghABCDEFGH,p=i6Rghite81P1ype8XxaVAa5l7v0="), response.toString()); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("c=cD10bHMtdW5pcXVlLCx4eXph,r=abcdefghABCDEFGH,p=i6Rghite81P1ype8XxaVAa5l7v0="), response); } void testSetFinalChallenge() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); - testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); - bool result = testling.setChallenge(ByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo=")); + bool result = testling.setChallenge(createByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo=")); CPPUNIT_ASSERT(result); } void testSetChallenge() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); CPPUNIT_ASSERT(result); } void testSetChallenge_InvalidClientNonce() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefgiABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + bool result = testling.setChallenge(createByteArray("r=abcdefgiABCDEFGH,s=MTIzNDU2NzgK,i=4096")); CPPUNIT_ASSERT(!result); } void testSetChallenge_OnlyClientNonce() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefgh,s=MTIzNDU2NzgK,i=4096")); + bool result = testling.setChallenge(createByteArray("r=abcdefgh,s=MTIzNDU2NzgK,i=4096")); CPPUNIT_ASSERT(!result); } void testSetChallenge_InvalidIterations() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=bla")); + bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=bla")); CPPUNIT_ASSERT(!result); } void testSetChallenge_MissingIterations() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK")); + bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK")); CPPUNIT_ASSERT(!result); } void testSetChallenge_ZeroIterations() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=0")); + bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=0")); CPPUNIT_ASSERT(!result); } void testSetChallenge_NegativeIterations() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); + testling.setCredentials("user", createSafeByteArray("pass"), ""); - bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=-1")); + bool result = testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=-1")); CPPUNIT_ASSERT(!result); } void testSetFinalChallenge_InvalidChallenge() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); - testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); - bool result = testling.setChallenge(ByteArray("v=e26kI69ICb6zosapLLxrER/631A=")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + bool result = testling.setChallenge(createByteArray("v=e26kI69ICb6zosapLLxrER/631A=")); CPPUNIT_ASSERT(!result); } void testGetResponseAfterFinalChallenge() { SCRAMSHA1ClientAuthenticator testling("abcdefgh"); - testling.setCredentials("user", "pass", ""); - testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); - testling.setChallenge(ByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo=")); + testling.setCredentials("user", createSafeByteArray("pass"), ""); + testling.setChallenge(createByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + testling.setChallenge(createByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo=")); CPPUNIT_ASSERT(!testling.getResponse()); } diff --git a/Swiften/SConscript b/Swiften/SConscript index 12c7456..6e129a3 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -1,4 +1,4 @@ -import os, re, Version +import os, re, Version, os.path Import("env") @@ -6,7 +6,7 @@ Import("env") # Flags ################################################################################ -swiften_dep_modules = ["BOOST", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI"] +swiften_dep_modules = ["BOOST", "GCONF", "LIBIDN", "ZLIB", "OPENSSL", "LIBXML", "EXPAT", "AVAHI", "LIBMINIUPNPC", "LIBNATPMP"] if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_VERSION"] = Version.getBuildVersion(env.Dir("#").abspath, "swift") @@ -21,6 +21,7 @@ if env["SCONS_STAGE"] == "flags" : env["SWIFTEN_LIBRARY"] = "Swiften" env["SWIFTEN_LIBRARY_FILE"] = "Swiften" env["SWIFTEN_LIBRARY_ALIASES"] = [] + if ARGUMENTS.get("swiften_dll", False) : if env["PLATFORM"] == "win32" : pass @@ -49,6 +50,7 @@ if env["SCONS_STAGE"] == "flags" : "CPPFLAGS": e.get("CPPFLAGS", []), "LIBPATH": e.get("LIBPATH", []), "LIBS": e.get("LIBS", []), + "FRAMEWORKS": e.get("FRAMEWORKS", []), } ################################################################################ @@ -76,25 +78,38 @@ if env["SCONS_STAGE"] == "build" : "Client/ClientSessionStanzaChannel.cpp", "Client/CoreClient.cpp", "Client/Client.cpp", + "Client/ClientXMLTracer.cpp", "Client/ClientSession.cpp", + "Client/BlockList.cpp", + "Client/BlockListImpl.cpp", + "Client/ClientBlockListManager.cpp", "Client/MemoryStorages.cpp", - "Client/FileStorages.cpp", "Client/NickResolver.cpp", "Client/NickManager.cpp", "Client/NickManagerImpl.cpp", + "Client/Storages.cpp", + "Client/XMLBeautifier.cpp", "Compress/ZLibCodecompressor.cpp", "Compress/ZLibDecompressor.cpp", "Compress/ZLibCompressor.cpp", "Elements/DiscoInfo.cpp", + "Elements/Presence.cpp", "Elements/Form.cpp", + "Elements/StreamFeatures.cpp", "Elements/Element.cpp", "Elements/IQ.cpp", "Elements/Payload.cpp", + "Elements/RosterItemExchangePayload.cpp", "Elements/RosterPayload.cpp", "Elements/Stanza.cpp", + "Elements/StatusShow.cpp", + "Elements/StreamManagementEnabled.cpp", + "Elements/StreamResume.cpp", + "Elements/StreamResumed.cpp", "Elements/VCard.cpp", "Elements/MUCOccupant.cpp", "Entity/Entity.cpp", + "Entity/PayloadPersister.cpp", "MUC/MUC.cpp", "MUC/MUCManager.cpp", "MUC/MUCRegistry.cpp", @@ -106,6 +121,8 @@ if env["SCONS_STAGE"] == "build" : "Queries/Requests/GetInBandRegistrationFormRequest.cpp", "Queries/Requests/SubmitInBandRegistrationFormRequest.cpp", "Queries/Responders/SoftwareVersionResponder.cpp", + "Roster/RosterStorage.cpp", + "Roster/RosterMemoryStorage.cpp", "Roster/XMPPRoster.cpp", "Roster/XMPPRosterImpl.cpp", "Roster/XMPPRosterController.cpp", @@ -116,6 +133,9 @@ if env["SCONS_STAGE"] == "build" : "Serializer/CompressRequestSerializer.cpp", "Serializer/ElementSerializer.cpp", "Serializer/MessageSerializer.cpp", + "Serializer/StreamManagementEnabledSerializer.cpp", + "Serializer/StreamResumeSerializer.cpp", + "Serializer/StreamResumedSerializer.cpp", "Serializer/ComponentHandshakeSerializer.cpp", "Serializer/PayloadSerializer.cpp", "Serializer/PayloadSerializerCollection.cpp", @@ -128,8 +148,11 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp", "Serializer/PayloadSerializers/MUCPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp", + "Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp", "Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp", + "Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.cpp", "Serializer/PayloadSerializers/ResourceBindSerializer.cpp", + "Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp", "Serializer/PayloadSerializers/RosterSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelSerializer.cpp", "Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp", @@ -146,6 +169,14 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/SearchPayloadSerializer.cpp", "Serializer/PayloadSerializers/FormSerializer.cpp", "Serializer/PayloadSerializers/NicknameSerializer.cpp", + "Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp", + "Serializer/PayloadSerializers/JinglePayloadSerializer.cpp", + "Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp", + "Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp", + "Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.cpp", + "Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp", + "Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp", + "Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", "Serializer/StreamErrorSerializer.cpp", @@ -154,13 +185,13 @@ if env["SCONS_STAGE"] == "build" : "Serializer/XML/XMLNode.cpp", "Serializer/XMPPSerializer.cpp", "Session/Session.cpp", + "Session/SessionTracer.cpp", "Session/SessionStream.cpp", "Session/BasicSessionStream.cpp", "StringCodecs/Base64.cpp", "StringCodecs/SHA1.cpp", - "StringCodecs/HMACSHA1.cpp", + "StringCodecs/SHA256.cpp", "StringCodecs/MD5.cpp", - "StringCodecs/PBKDF2.cpp", "StringCodecs/Hexify.cpp", ] @@ -184,16 +215,20 @@ if env["SCONS_STAGE"] == "build" : "LinkLocal", "StreamManagement", "Component", - "Config", + "AdHoc" ]) - SConscript(test_only = True, dirs = [ + if env["build_examples"] : + SConscript(dirs = [ + "Config", + "Examples" + ]) + env.SConscript(test_only = True, dirs = [ "QA", ]) - SConscript(dirs = [ - "Examples" - ]) myenv = swiften_env.Clone() + if myenv["PLATFORM"] != "darwin" and myenv["PLATFORM"] != "win32" and myenv.get("HAVE_GCONF", 0) : + env.MergeFlags(env["GCONF_FLAGS"]) if ARGUMENTS.get("swiften_dll", False) : if myenv["PLATFORM"] == "posix" : myenv.Append(LINKFLAGS = ["-Wl,-soname,libSwiften.so.$SWIFTEN_VERSION_MAJOR"]) @@ -214,6 +249,7 @@ if env["SCONS_STAGE"] == "build" : File("Avatars/UnitTest/CombinedAvatarProviderTest.cpp"), File("Base/UnitTest/IDGeneratorTest.cpp"), File("Base/UnitTest/StringTest.cpp"), + File("Base/UnitTest/DateTimeTest.cpp"), File("Base/UnitTest/ByteArrayTest.cpp"), File("Chat/UnitTest/ChatStateNotifierTest.cpp"), # File("Chat/UnitTest/ChatStateTrackerTest.cpp"), @@ -234,8 +270,6 @@ if env["SCONS_STAGE"] == "build" : File("Elements/UnitTest/FormTest.cpp"), File("EventLoop/UnitTest/EventLoopTest.cpp"), File("EventLoop/UnitTest/SimpleEventLoopTest.cpp"), - File("FileTransfer/UnitTest/SOCKS5BytestreamServerSessionTest.cpp"), - File("FileTransfer/UnitTest/IBBSendSessionTest.cpp"), # File("History/UnitTest/SQLiteHistoryManagerTest.cpp"), File("JID/UnitTest/JIDTest.cpp"), File("LinkLocal/UnitTest/LinkLocalConnectorTest.cpp"), @@ -245,6 +279,8 @@ if env["SCONS_STAGE"] == "build" : File("MUC/UnitTest/MUCTest.cpp"), File("Network/UnitTest/HostAddressTest.cpp"), File("Network/UnitTest/ConnectorTest.cpp"), + File("Network/UnitTest/ChainedConnectorTest.cpp"), + File("Network/UnitTest/HTTPConnectProxiedConnectionTest.cpp"), File("Parser/PayloadParsers/UnitTest/BodyParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/DiscoInfoParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ErrorParserTest.cpp"), @@ -253,8 +289,10 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/PriorityParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RawXMLPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/ResourceBindParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/RosterItemExchangeParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/RosterParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/IBBParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/JingleParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SearchPayloadParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SecurityLabelParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/SecurityLabelsCatalogParserTest.cpp"), @@ -266,8 +304,12 @@ if env["SCONS_STAGE"] == "build" : File("Parser/PayloadParsers/UnitTest/StorageParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/PrivateStorageParserTest.cpp"), File("Parser/PayloadParsers/UnitTest/VCardUpdateParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/ReplaceTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MUCAdminPayloadParserTest.cpp"), + File("Parser/PayloadParsers/UnitTest/MUCUserPayloadParserTest.cpp"), File("Parser/UnitTest/AttributeMapTest.cpp"), File("Parser/UnitTest/IQParserTest.cpp"), + File("Parser/UnitTest/GenericPayloadTreeParserTest.cpp"), File("Parser/UnitTest/MessageParserTest.cpp"), File("Parser/UnitTest/PayloadParserFactoryCollectionTest.cpp"), File("Parser/UnitTest/PresenceParserTest.cpp"), @@ -275,6 +317,7 @@ if env["SCONS_STAGE"] == "build" : File("Parser/UnitTest/SerializingParserTest.cpp"), File("Parser/UnitTest/StanzaParserTest.cpp"), File("Parser/UnitTest/StreamFeaturesParserTest.cpp"), + File("Parser/UnitTest/StreamManagementEnabledParserTest.cpp"), File("Parser/UnitTest/XMLParserTest.cpp"), File("Parser/UnitTest/XMPPParserTest.cpp"), File("Presence/UnitTest/PresenceOracleTest.cpp"), @@ -286,6 +329,7 @@ if env["SCONS_STAGE"] == "build" : File("Queries/UnitTest/ResponderTest.cpp"), File("Roster/UnitTest/XMPPRosterImplTest.cpp"), File("Roster/UnitTest/XMPPRosterControllerTest.cpp"), + File("Roster/UnitTest/XMPPRosterSignalHandler.cpp"), File("Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp"), File("Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp"), @@ -293,6 +337,7 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp"), @@ -306,6 +351,9 @@ if env["SCONS_STAGE"] == "build" : File("Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp"), File("Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp"), + File("Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp"), File("Serializer/UnitTest/StreamFeaturesSerializerTest.cpp"), File("Serializer/UnitTest/AuthSuccessSerializerTest.cpp"), File("Serializer/UnitTest/AuthChallengeSerializerTest.cpp"), @@ -319,9 +367,10 @@ if env["SCONS_STAGE"] == "build" : File("StreamStack/UnitTest/XMPPLayerTest.cpp"), File("StringCodecs/UnitTest/Base64Test.cpp"), File("StringCodecs/UnitTest/SHA1Test.cpp"), + File("StringCodecs/UnitTest/SHA256Test.cpp"), File("StringCodecs/UnitTest/MD5Test.cpp"), File("StringCodecs/UnitTest/HexifyTest.cpp"), - File("StringCodecs/UnitTest/HMACSHA1Test.cpp"), + File("StringCodecs/UnitTest/HMACTest.cpp"), File("StringCodecs/UnitTest/PBKDF2Test.cpp"), File("TLS/UnitTest/ServerIdentityVerifierTest.cpp"), File("TLS/UnitTest/CertificateTest.cpp"), @@ -329,6 +378,9 @@ if env["SCONS_STAGE"] == "build" : ]) # Generate the Swiften header + def relpath(path, start) : + i = len(os.path.commonprefix([path, start])) + return path[i+1:] swiften_header = "#pragma once\n" swiften_includes = [] top_path = env.Dir("..").abspath @@ -338,7 +390,9 @@ if env["SCONS_STAGE"] == "build" : for file in files : if not file.endswith(".h") : continue - include = os.path.relpath(os.path.join(root, file), top_path) + include = relpath(os.path.join(root, file), top_path) + if swiften_env["PLATFORM"] == "win32" : + include = include.replace("\\", "/") swiften_includes.append(include) # Private modules if root.endswith("Config") or root.endswith("Compress") : @@ -349,11 +403,11 @@ if env["SCONS_STAGE"] == "build" : continue # Library-specific files - if file.startswith("CAres") or file.startswith("LibXML") or file.startswith("Expat") or file.startswith("SQLite") : + if file.startswith("CAres") or file.startswith("LibXML") or file.startswith("Expat") or file.startswith("GConf") or file.startswith("MacOSX") or file.startswith("Windows") or file.startswith("SQLite") or file.startswith("NATPMP") or file.startswith("MiniUPnP") : continue # Specific headers we don't want to globally include - if file == "Swiften.h" or file == "foreach.h" or file == "Log.h" or file == "format.h" : + if file == "Swiften.h" or file == "foreach.h" or file == "Log.h" or file == "format.h" or file == "CompressionLayer.h": continue swiften_header += "#include <" + include + ">\n" swiften_includes.append(include) diff --git a/Swiften/Serializer/AuthChallengeSerializer.cpp b/Swiften/Serializer/AuthChallengeSerializer.cpp index dcded43..1ddc165 100644 --- a/Swiften/Serializer/AuthChallengeSerializer.cpp +++ b/Swiften/Serializer/AuthChallengeSerializer.cpp @@ -4,29 +4,30 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/AuthChallengeSerializer.h" +#include <Swiften/Serializer/AuthChallengeSerializer.h> -#include "Swiften/Elements/AuthChallenge.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Elements/AuthChallenge.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { AuthChallengeSerializer::AuthChallengeSerializer() { } -std::string AuthChallengeSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthChallengeSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<AuthChallenge> authChallenge(boost::dynamic_pointer_cast<AuthChallenge>(element)); std::string value; - boost::optional<ByteArray> message = authChallenge->getValue(); + boost::optional<std::vector<unsigned char> > message = authChallenge->getValue(); if (message) { - if ((*message).isEmpty()) { + if ((*message).empty()) { value = "="; } else { - value = Base64::encode(*message); + value = Base64::encode(ByteArray(*message)); } } - return "<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</challenge>"; + return createSafeByteArray("<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</challenge>"); } } diff --git a/Swiften/Serializer/AuthChallengeSerializer.h b/Swiften/Serializer/AuthChallengeSerializer.h index a62efb3..d485473 100644 --- a/Swiften/Serializer/AuthChallengeSerializer.h +++ b/Swiften/Serializer/AuthChallengeSerializer.h @@ -8,14 +8,14 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/AuthChallenge.h" -#include "Swiften/Serializer/GenericElementSerializer.h" +#include <Swiften/Elements/AuthChallenge.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class AuthChallengeSerializer : public GenericElementSerializer<AuthChallenge> { public: AuthChallengeSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; }; } diff --git a/Swiften/Serializer/AuthFailureSerializer.h b/Swiften/Serializer/AuthFailureSerializer.h index 477d98c..090f0c4 100644 --- a/Swiften/Serializer/AuthFailureSerializer.h +++ b/Swiften/Serializer/AuthFailureSerializer.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_AuthFailureSerializer_H -#define SWIFTEN_AuthFailureSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/AuthFailure.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/AuthFailure.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class AuthFailureSerializer : public GenericElementSerializer<AuthFailure> { @@ -19,10 +18,8 @@ namespace Swift { AuthFailureSerializer() : GenericElementSerializer<AuthFailure>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("failure", "urn:ietf:params:xml:ns:xmpp-sasl").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("failure", "urn:ietf:params:xml:ns:xmpp-sasl").serialize()); } }; } - -#endif diff --git a/Swiften/Serializer/AuthRequestSerializer.cpp b/Swiften/Serializer/AuthRequestSerializer.cpp index 0bee302..7f25c93 100644 --- a/Swiften/Serializer/AuthRequestSerializer.cpp +++ b/Swiften/Serializer/AuthRequestSerializer.cpp @@ -4,29 +4,31 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/AuthRequestSerializer.h" +#include <Swiften/Serializer/AuthRequestSerializer.h> -#include "Swiften/Elements/AuthRequest.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Elements/AuthRequest.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/Concat.h> namespace Swift { AuthRequestSerializer::AuthRequestSerializer() { } -std::string AuthRequestSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthRequestSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<AuthRequest> authRequest(boost::dynamic_pointer_cast<AuthRequest>(element)); - std::string value; - boost::optional<ByteArray> message = authRequest->getMessage(); + SafeByteArray value; + boost::optional<SafeByteArray> message = authRequest->getMessage(); if (message) { - if ((*message).isEmpty()) { - value = "="; + if ((*message).empty()) { + value = createSafeByteArray("="); } else { value = Base64::encode(*message); } } - return "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"" + authRequest->getMechanism() + "\">" + value + "</auth>"; + return concat(createSafeByteArray("<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"" + authRequest->getMechanism() + "\">"), value, createSafeByteArray("</auth>")); } } diff --git a/Swiften/Serializer/AuthRequestSerializer.h b/Swiften/Serializer/AuthRequestSerializer.h index 18ef5dd..add7983 100644 --- a/Swiften/Serializer/AuthRequestSerializer.h +++ b/Swiften/Serializer/AuthRequestSerializer.h @@ -4,21 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_AuthRequestSerializer_H -#define SWIFTEN_AuthRequestSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/AuthRequest.h" -#include "Swiften/Serializer/GenericElementSerializer.h" +#include <Swiften/Elements/AuthRequest.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class AuthRequestSerializer : public GenericElementSerializer<AuthRequest> { public: AuthRequestSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; }; } - -#endif diff --git a/Swiften/Serializer/AuthResponseSerializer.cpp b/Swiften/Serializer/AuthResponseSerializer.cpp index a93b4dd..86b7fbe 100644 --- a/Swiften/Serializer/AuthResponseSerializer.cpp +++ b/Swiften/Serializer/AuthResponseSerializer.cpp @@ -4,29 +4,31 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/AuthResponseSerializer.h" +#include <Swiften/Serializer/AuthResponseSerializer.h> -#include "Swiften/Elements/AuthResponse.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Elements/AuthResponse.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/Concat.h> namespace Swift { AuthResponseSerializer::AuthResponseSerializer() { } -std::string AuthResponseSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthResponseSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<AuthResponse> authResponse(boost::dynamic_pointer_cast<AuthResponse>(element)); - std::string value; - boost::optional<ByteArray> message = authResponse->getValue(); + SafeByteArray value; + boost::optional<SafeByteArray> message = authResponse->getValue(); if (message) { - if ((*message).isEmpty()) { - value = "="; + if ((*message).empty()) { + value = createSafeByteArray("="); } else { value = Base64::encode(*message); } } - return "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</response>"; + return concat(createSafeByteArray("<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">"), value, createSafeByteArray("</response>")); } } diff --git a/Swiften/Serializer/AuthResponseSerializer.h b/Swiften/Serializer/AuthResponseSerializer.h index cee8ff3..495f8cc 100644 --- a/Swiften/Serializer/AuthResponseSerializer.h +++ b/Swiften/Serializer/AuthResponseSerializer.h @@ -8,14 +8,14 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/AuthResponse.h" -#include "Swiften/Serializer/GenericElementSerializer.h" +#include <Swiften/Elements/AuthResponse.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class AuthResponseSerializer : public GenericElementSerializer<AuthResponse> { public: AuthResponseSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; }; } diff --git a/Swiften/Serializer/AuthSuccessSerializer.cpp b/Swiften/Serializer/AuthSuccessSerializer.cpp index 443c740..26b58c3 100644 --- a/Swiften/Serializer/AuthSuccessSerializer.cpp +++ b/Swiften/Serializer/AuthSuccessSerializer.cpp @@ -4,29 +4,30 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/AuthSuccessSerializer.h" +#include <Swiften/Serializer/AuthSuccessSerializer.h> -#include "Swiften/Elements/AuthSuccess.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Elements/AuthSuccess.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { AuthSuccessSerializer::AuthSuccessSerializer() { } -std::string AuthSuccessSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray AuthSuccessSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<AuthSuccess> authSuccess(boost::dynamic_pointer_cast<AuthSuccess>(element)); std::string value; - boost::optional<ByteArray> message = authSuccess->getValue(); + boost::optional<std::vector<unsigned char> > message = authSuccess->getValue(); if (message) { - if ((*message).isEmpty()) { + if ((*message).empty()) { value = "="; } else { - value = Base64::encode(*message); + value = Base64::encode(ByteArray(*message)); } } - return "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</success>"; + return createSafeByteArray("<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" + value + "</success>"); } } diff --git a/Swiften/Serializer/AuthSuccessSerializer.h b/Swiften/Serializer/AuthSuccessSerializer.h index eb3279c..8163d16 100644 --- a/Swiften/Serializer/AuthSuccessSerializer.h +++ b/Swiften/Serializer/AuthSuccessSerializer.h @@ -8,14 +8,14 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/AuthSuccess.h" -#include "Swiften/Serializer/GenericElementSerializer.h" +#include <Swiften/Elements/AuthSuccess.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class AuthSuccessSerializer : public GenericElementSerializer<AuthSuccess> { public: AuthSuccessSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; }; } diff --git a/Swiften/Serializer/ComponentHandshakeSerializer.cpp b/Swiften/Serializer/ComponentHandshakeSerializer.cpp index cf44ea4..e7837d3 100644 --- a/Swiften/Serializer/ComponentHandshakeSerializer.cpp +++ b/Swiften/Serializer/ComponentHandshakeSerializer.cpp @@ -4,18 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/ComponentHandshakeSerializer.h" +#include <Swiften/Serializer/ComponentHandshakeSerializer.h> -#include "Swiften/Elements/ComponentHandshake.h" +#include <Swiften/Elements/ComponentHandshake.h> namespace Swift { ComponentHandshakeSerializer::ComponentHandshakeSerializer() { } -std::string ComponentHandshakeSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray ComponentHandshakeSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<ComponentHandshake> handshake(boost::dynamic_pointer_cast<ComponentHandshake>(element)); - return "<handshake>" + handshake->getData() + "</handshake>"; + return createSafeByteArray("<handshake>" + handshake->getData() + "</handshake>"); } } diff --git a/Swiften/Serializer/ComponentHandshakeSerializer.h b/Swiften/Serializer/ComponentHandshakeSerializer.h index 7681e56..1145ed9 100644 --- a/Swiften/Serializer/ComponentHandshakeSerializer.h +++ b/Swiften/Serializer/ComponentHandshakeSerializer.h @@ -8,14 +8,14 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/ComponentHandshake.h" -#include "Swiften/Serializer/GenericElementSerializer.h" +#include <Swiften/Elements/ComponentHandshake.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class ComponentHandshakeSerializer : public GenericElementSerializer<ComponentHandshake> { public: ComponentHandshakeSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; }; } diff --git a/Swiften/Serializer/CompressFailureSerializer.h b/Swiften/Serializer/CompressFailureSerializer.h index 02a4b46..27a638f 100644 --- a/Swiften/Serializer/CompressFailureSerializer.h +++ b/Swiften/Serializer/CompressFailureSerializer.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_CompressFailureSerializer_H -#define SWIFTEN_CompressFailureSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/CompressFailure.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/CompressFailure.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class CompressFailureSerializer : public GenericElementSerializer<CompressFailure> { @@ -19,10 +18,8 @@ namespace Swift { CompressFailureSerializer() : GenericElementSerializer<CompressFailure>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("failure", "http://jabber.org/protocol/compress").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("failure", "http://jabber.org/protocol/compress").serialize()); } }; } - -#endif diff --git a/Swiften/Serializer/CompressRequestSerializer.cpp b/Swiften/Serializer/CompressRequestSerializer.cpp index 7733169..af7f7db 100644 --- a/Swiften/Serializer/CompressRequestSerializer.cpp +++ b/Swiften/Serializer/CompressRequestSerializer.cpp @@ -4,22 +4,22 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/CompressRequestSerializer.h" +#include <Swiften/Serializer/CompressRequestSerializer.h> -#include "Swiften/Elements/CompressRequest.h" +#include <Swiften/Elements/CompressRequest.h> namespace Swift { CompressRequestSerializer::CompressRequestSerializer() { } -std::string CompressRequestSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray CompressRequestSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<CompressRequest> compressRequest(boost::dynamic_pointer_cast<CompressRequest>(element)); - return "<compress xmlns='http://jabber.org/protocol/compress'><method>" + compressRequest->getMethod() + "</method></compress>"; + return createSafeByteArray("<compress xmlns='http://jabber.org/protocol/compress'><method>" + compressRequest->getMethod() + "</method></compress>"); } bool CompressRequestSerializer::canSerialize(boost::shared_ptr<Element> element) const { - return dynamic_cast<CompressRequest*>(element.get()) != 0; + return boost::dynamic_pointer_cast<CompressRequest>(element) != 0; } } diff --git a/Swiften/Serializer/CompressRequestSerializer.h b/Swiften/Serializer/CompressRequestSerializer.h index 0a14fb1..4d68c98 100644 --- a/Swiften/Serializer/CompressRequestSerializer.h +++ b/Swiften/Serializer/CompressRequestSerializer.h @@ -4,21 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_COMPRESSREQUESTSERIALIZER_H -#define SWIFTEN_COMPRESSREQUESTSERIALIZER_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Serializer/ElementSerializer.h" +#include <Swiften/Serializer/ElementSerializer.h> namespace Swift { class CompressRequestSerializer : public ElementSerializer { public: CompressRequestSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; virtual bool canSerialize(boost::shared_ptr<Element> element) const; }; } - -#endif diff --git a/Swiften/Serializer/ElementSerializer.cpp b/Swiften/Serializer/ElementSerializer.cpp index 6b9fdd5..8cfb294 100644 --- a/Swiften/Serializer/ElementSerializer.cpp +++ b/Swiften/Serializer/ElementSerializer.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/ElementSerializer.h" +#include <Swiften/Serializer/ElementSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/ElementSerializer.h b/Swiften/Serializer/ElementSerializer.h index 3abdf08..ba59106 100644 --- a/Swiften/Serializer/ElementSerializer.h +++ b/Swiften/Serializer/ElementSerializer.h @@ -4,22 +4,19 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ELEMENTSERIALIZER_H -#define SWIFTEN_ELEMENTSERIALIZER_H +#pragma once #include <boost/shared_ptr.hpp> -#include <string> -#include "Swiften/Elements/Element.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class ElementSerializer { public: virtual ~ElementSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const = 0; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const = 0; virtual bool canSerialize(boost::shared_ptr<Element> element) const = 0; }; } - -#endif diff --git a/Swiften/Serializer/EnableStreamManagementSerializer.h b/Swiften/Serializer/EnableStreamManagementSerializer.h index e224a9c..384753b 100644 --- a/Swiften/Serializer/EnableStreamManagementSerializer.h +++ b/Swiften/Serializer/EnableStreamManagementSerializer.h @@ -8,9 +8,9 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/EnableStreamManagement.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/EnableStreamManagement.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class EnableStreamManagementSerializer : public GenericElementSerializer<EnableStreamManagement> { @@ -18,8 +18,8 @@ namespace Swift { EnableStreamManagementSerializer() : GenericElementSerializer<EnableStreamManagement>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("enable", "urn:xmpp:sm:2").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("enable", "urn:xmpp:sm:2").serialize()); } }; } diff --git a/Swiften/Serializer/GenericElementSerializer.h b/Swiften/Serializer/GenericElementSerializer.h index 903c205..e56f156 100644 --- a/Swiften/Serializer/GenericElementSerializer.h +++ b/Swiften/Serializer/GenericElementSerializer.h @@ -14,7 +14,7 @@ namespace Swift { template<typename T> class GenericElementSerializer : public ElementSerializer { public: - virtual std::string serialize(boost::shared_ptr<Element> element) const = 0; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const = 0; virtual bool canSerialize(boost::shared_ptr<Element> element) const { return boost::dynamic_pointer_cast<T>(element); diff --git a/Swiften/Serializer/GenericStanzaSerializer.h b/Swiften/Serializer/GenericStanzaSerializer.h index 2f0fccf..4129ca8 100644 --- a/Swiften/Serializer/GenericStanzaSerializer.h +++ b/Swiften/Serializer/GenericStanzaSerializer.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_GENERICSTANZASERIALIZER_H -#define SWIFTEN_GENERICSTANZASERIALIZER_H +#pragma once -#include "Swiften/Serializer/StanzaSerializer.h" +#include <Swiften/Serializer/StanzaSerializer.h> namespace Swift { template<typename STANZA_TYPE> @@ -31,5 +30,3 @@ namespace Swift { XMLElement&) const = 0; }; } - -#endif diff --git a/Swiften/Serializer/IQSerializer.h b/Swiften/Serializer/IQSerializer.h index 21ec300..76a9cb7 100644 --- a/Swiften/Serializer/IQSerializer.h +++ b/Swiften/Serializer/IQSerializer.h @@ -4,14 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_IQSerializer_H -#define SWIFTEN_IQSerializer_H +#pragma once -#include <cassert> - -#include "Swiften/Serializer/GenericStanzaSerializer.h" -#include "Swiften/Elements/IQ.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/GenericStanzaSerializer.h> +#include <Swiften/Elements/IQ.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class IQSerializer : public GenericStanzaSerializer<IQ> { @@ -32,5 +29,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Serializer/MessageSerializer.cpp b/Swiften/Serializer/MessageSerializer.cpp index cea9a1d..c221680 100644 --- a/Swiften/Serializer/MessageSerializer.cpp +++ b/Swiften/Serializer/MessageSerializer.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/MessageSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/MessageSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { diff --git a/Swiften/Serializer/MessageSerializer.h b/Swiften/Serializer/MessageSerializer.h index 873cc5a..8e9e941 100644 --- a/Swiften/Serializer/MessageSerializer.h +++ b/Swiften/Serializer/MessageSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_MessageSerializer_H -#define SWIFTEN_MessageSerializer_H +#pragma once -#include "Swiften/Serializer/GenericStanzaSerializer.h" -#include "Swiften/Elements/Message.h" +#include <Swiften/Serializer/GenericStanzaSerializer.h> +#include <Swiften/Elements/Message.h> namespace Swift { class XMLElement; @@ -23,5 +22,3 @@ namespace Swift { XMLElement& element) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializer.cpp index db13ade..be73676 100644 --- a/Swiften/Serializer/PayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializer.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializer.h b/Swiften/Serializer/PayloadSerializer.h index 34e6679..c4ad23b 100644 --- a/Swiften/Serializer/PayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializer.h @@ -4,15 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PAYLOADSERIALIZER_H -#define SWIFTEN_PAYLOADSERIALIZER_H - -#include <boost/shared_ptr.hpp> +#pragma once #include <string> -#include "Swiften/Elements/Payload.h" +#include <boost/shared_ptr.hpp> namespace Swift { + class Payload; + class PayloadSerializer { public: virtual ~PayloadSerializer(); @@ -21,5 +20,3 @@ namespace Swift { virtual std::string serialize(boost::shared_ptr<Payload>) const = 0; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializerCollection.cpp index 548dd32..ab2b4f4 100644 --- a/Swiften/Serializer/PayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializerCollection.cpp @@ -7,8 +7,8 @@ #include <boost/bind.hpp> #include <algorithm> -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/Serializer/PayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/PayloadSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializerCollection.h b/Swiften/Serializer/PayloadSerializerCollection.h index 1b3cbc5..f922a45 100644 --- a/Swiften/Serializer/PayloadSerializerCollection.h +++ b/Swiften/Serializer/PayloadSerializerCollection.h @@ -9,7 +9,7 @@ #include <vector> #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> namespace Swift { class PayloadSerializer; diff --git a/Swiften/Serializer/PayloadSerializers/BlockSerializer.h b/Swiften/Serializer/PayloadSerializers/BlockSerializer.h new file mode 100644 index 0000000..345463c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/BlockSerializer.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Base/foreach.h> + +namespace Swift { + template<typename BLOCK_ELEMENT> + class BlockSerializer : public GenericPayloadSerializer<BLOCK_ELEMENT> { + public: + BlockSerializer(std::string tag) : GenericPayloadSerializer<BLOCK_ELEMENT>(), tag(tag) { + } + + virtual std::string serializePayload(boost::shared_ptr<BLOCK_ELEMENT> payload) const { + XMLElement element(tag, "urn:xmpp:blocking"); + foreach (const JID& jid, payload->getItems()) { + boost::shared_ptr<XMLElement> item = boost::make_shared<XMLElement>("item"); + item->setAttribute("jid", jid); + } + return element.serialize(); + } + + private: + std::string tag; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/BodySerializer.h b/Swiften/Serializer/PayloadSerializers/BodySerializer.h index 6fc6e6d..99df0f5 100644 --- a/Swiften/Serializer/PayloadSerializers/BodySerializer.h +++ b/Swiften/Serializer/PayloadSerializers/BodySerializer.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_BodySerializer_H -#define SWIFTEN_BodySerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Elements/Body.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Elements/Body.h> namespace Swift { class BodySerializer : public GenericPayloadSerializer<Body> { @@ -22,5 +21,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp index f9b89f3..beb84dd 100644 --- a/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h> #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h b/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h index d9b14db..0e58eb0 100644 --- a/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Bytestreams.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Bytestreams.h> namespace Swift { class PayloadSerializerCollection; diff --git a/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.cpp b/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.cpp index ced0d62..2466958 100644 --- a/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h index de0a871..2587ee0 100644 --- a/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_CapsInfoSerializer_H -#define SWIFTEN_CapsInfoSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/CapsInfo.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/CapsInfo.h> namespace Swift { class CapsInfoSerializer : public GenericPayloadSerializer<CapsInfo> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<CapsInfo>) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp index 3e877eb..ee468bb 100644 --- a/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h b/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h index a786901..d71873d 100644 --- a/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/ChatState.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/ChatState.h> namespace Swift { class ChatStateSerializer : public GenericPayloadSerializer<ChatState> { diff --git a/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp b/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp index 0fa45ce..2fb86b0 100644 --- a/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/CommandSerializer.cpp @@ -4,16 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/CommandSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/CommandSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> namespace Swift { @@ -21,7 +20,7 @@ CommandSerializer::CommandSerializer() { } std::string CommandSerializer::serializePayload(boost::shared_ptr<Command> command) const { - XMLElement commandElement("command", "http://jabber.org/protocol/comands"); + XMLElement commandElement("command", "http://jabber.org/protocol/commands"); commandElement.setAttribute("node", command->getNode()); if (!command->getSessionID().empty()) { diff --git a/Swiften/Serializer/PayloadSerializers/CommandSerializer.h b/Swiften/Serializer/PayloadSerializers/CommandSerializer.h index b1db825..03b6aa0 100644 --- a/Swiften/Serializer/PayloadSerializers/CommandSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/CommandSerializer.h @@ -6,12 +6,10 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Command.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Command.h> namespace Swift { - class PayloadSerializerCollection; - class CommandSerializer : public GenericPayloadSerializer<Command> { public: CommandSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp index 4922042..6148632 100644 --- a/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/DelaySerializer.cpp @@ -4,12 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/DelaySerializer.h" +#include <Swiften/Serializer/PayloadSerializers/DelaySerializer.h> #include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> #include <Swiften/Base/String.h> -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Base/DateTime.h> namespace Swift { @@ -21,16 +23,8 @@ std::string DelaySerializer::serializePayload(boost::shared_ptr<Delay> delay) c if (delay->getFrom()) { delayElement.setAttribute("from", delay->getFrom()->toString()); } - std::string stampString = boostPTimeToXEP0082(delay->getStamp()); - delayElement.setAttribute("stamp", stampString); + delayElement.setAttribute("stamp", dateTimeToString(delay->getStamp())); return delayElement.serialize(); } -std::string DelaySerializer::boostPTimeToXEP0082(const boost::posix_time::ptime& time) { - std::string stampString = std::string(boost::posix_time::to_iso_extended_string(time)); - String::replaceAll(stampString, ',', "."); - stampString += "Z"; - return stampString; -} - } diff --git a/Swiften/Serializer/PayloadSerializers/DelaySerializer.h b/Swiften/Serializer/PayloadSerializers/DelaySerializer.h index c37dc02..06c7665 100644 --- a/Swiften/Serializer/PayloadSerializers/DelaySerializer.h +++ b/Swiften/Serializer/PayloadSerializers/DelaySerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Delay.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Delay.h> namespace Swift { class DelaySerializer : public GenericPayloadSerializer<Delay> { @@ -15,7 +15,6 @@ namespace Swift { DelaySerializer(); virtual std::string serializePayload(boost::shared_ptr<Delay>) const; - static std::string boostPTimeToXEP0082(const boost::posix_time::ptime& time); }; } diff --git a/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.cpp b/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.cpp index 65b0a38..e2c6f59 100644 --- a/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h index 46e7ce2..3e028e1 100644 --- a/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_DiscoInfoSerializer_H -#define SWIFTEN_DiscoInfoSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/DiscoInfo.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/DiscoInfo.h> namespace Swift { class DiscoInfoSerializer : public GenericPayloadSerializer<DiscoInfo> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<DiscoInfo>) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp index cb1b7c1..dd52b70 100644 --- a/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h index 3b00a17..a8785c2 100644 --- a/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/DiscoItems.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/DiscoItems.h> namespace Swift { class DiscoItemsSerializer : public GenericPayloadSerializer<DiscoItems> { diff --git a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp index 15d13d7..e3bfd54 100644 --- a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/ErrorSerializer.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h index 7fc4dad..d06efc8 100644 --- a/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/ErrorSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ErrorSerializer_H -#define SWIFTEN_ErrorSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/ErrorPayload.h> namespace Swift { class ErrorSerializer : public GenericPayloadSerializer<ErrorPayload> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<ErrorPayload> error) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp index 53b4241..7a6bb79 100644 --- a/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.cpp @@ -4,16 +4,17 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> #include <boost/shared_ptr.hpp> #include <iostream> #include <string> -#include "Swiften/Base/String.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" +#include <Swiften/Base/String.h> +#include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> using namespace Swift; @@ -129,14 +130,6 @@ boost::shared_ptr<XMLElement> FormSerializer::fieldToXML(boost::shared_ptr<FormF fieldType = "text-multi"; multiLineify(boost::dynamic_pointer_cast<TextMultiFormField>(field)->getValue(), "value", fieldElement); } - else if (boost::dynamic_pointer_cast<UntypedFormField>(field)) { - std::vector<std::string> lines = boost::dynamic_pointer_cast<UntypedFormField>(field)->getValue(); - foreach(const std::string& line, lines) { - boost::shared_ptr<XMLElement> valueElement(new XMLElement("value")); - valueElement->addNode(XMLTextNode::create(line)); - fieldElement->addNode(valueElement); - } - } else { assert(false); } @@ -162,7 +155,7 @@ boost::shared_ptr<XMLElement> FormSerializer::fieldToXML(boost::shared_ptr<FormF void FormSerializer::multiLineify(const std::string& text, const std::string& elementName, boost::shared_ptr<XMLElement> element) const { std::string unRdText(text); - unRdText.erase(std::remove(unRdText.begin(), unRdText.end(), '\r'), unRdText.end()); + erase(unRdText, '\r'); std::vector<std::string> lines = String::split(unRdText, '\n'); foreach (std::string line, lines) { boost::shared_ptr<XMLElement> lineElement(new XMLElement(elementName)); diff --git a/Swiften/Serializer/PayloadSerializers/FormSerializer.h b/Swiften/Serializer/PayloadSerializers/FormSerializer.h index 86c8dee..43db9e8 100644 --- a/Swiften/Serializer/PayloadSerializers/FormSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/FormSerializer.h @@ -6,10 +6,10 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Form.h" -#include "Swiften/Elements/FormField.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Form.h> +#include <Swiften/Elements/FormField.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class FormSerializer : public GenericPayloadSerializer<Form> { diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 1bbcbf2..f3e22d2 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -4,42 +4,61 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/PayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/IBBSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/BodySerializer.h" -#include "Swiften/Serializer/PayloadSerializers/SubjectSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/PrioritySerializer.h" -#include "Swiften/Serializer/PayloadSerializers/ErrorSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/RosterSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/StatusSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/StorageSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/DelaySerializer.h" -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/CommandSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/NicknameSerializer.h" -#include "Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Elements/BlockPayload.h> +#include <Swiften/Elements/UnblockPayload.h> +#include <Swiften/Elements/BlockListPayload.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/IBBSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/BodySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/BlockSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SubjectSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ChatStateSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PrioritySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StatusSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/DiscoItemsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/BytestreamsSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/VCardSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StorageSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/DelaySerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/CommandSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/NicknameSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/LastSerializer.h> + +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h> namespace Swift { @@ -51,15 +70,21 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new PrioritySerializer()); serializers_.push_back(new ErrorSerializer()); serializers_.push_back(new RosterSerializer()); + serializers_.push_back(new RosterItemExchangeSerializer()); serializers_.push_back(new MUCPayloadSerializer()); - serializers_.push_back(new MUCUserPayloadSerializer()); + serializers_.push_back(new MUCDestroyPayloadSerializer()); + serializers_.push_back(new MUCAdminPayloadSerializer()); serializers_.push_back(new MUCOwnerPayloadSerializer(this)); + serializers_.push_back(new MUCUserPayloadSerializer(this)); serializers_.push_back(new SoftwareVersionSerializer()); serializers_.push_back(new StatusSerializer()); serializers_.push_back(new StatusShowSerializer()); serializers_.push_back(new DiscoInfoSerializer()); serializers_.push_back(new DiscoItemsSerializer()); serializers_.push_back(new CapsInfoSerializer()); + serializers_.push_back(new BlockSerializer<BlockPayload>("block")); + serializers_.push_back(new BlockSerializer<UnblockPayload>("unblock")); + serializers_.push_back(new BlockSerializer<BlockListPayload>("blocklist")); serializers_.push_back(new ResourceBindSerializer()); serializers_.push_back(new StartSessionSerializer()); serializers_.push_back(new SecurityLabelSerializer()); @@ -77,6 +102,19 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new InBandRegistrationPayloadSerializer()); serializers_.push_back(new NicknameSerializer()); serializers_.push_back(new SearchPayloadSerializer()); + serializers_.push_back(new ReplaceSerializer()); + serializers_.push_back(new LastSerializer()); + + serializers_.push_back(new StreamInitiationFileInfoSerializer()); + serializers_.push_back(new JingleContentPayloadSerializer()); + serializers_.push_back(new JingleFileTransferDescriptionSerializer()); + serializers_.push_back(new JingleFileTransferHashSerializer()); + serializers_.push_back(new JingleFileTransferReceivedSerializer()); + serializers_.push_back(new JingleIBBTransportPayloadSerializer()); + serializers_.push_back(new JingleS5BTransportPayloadSerializer()); + serializers_.push_back(new JinglePayloadSerializer(this)); + serializers_.push_back(new S5BProxyRequestSerializer()); + foreach(PayloadSerializer* serializer, serializers_) { addSerializer(serializer); } diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h index bf86f27..bfe7d76 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h @@ -4,12 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_FULLPAYLOADSERIALIZERCOLLECTION_H -#define SWIFTEN_FULLPAYLOADSERIALIZERCOLLECTION_H +#pragma once #include <vector> -#include "Swiften/Serializer/PayloadSerializerCollection.h" +#include <Swiften/Serializer/PayloadSerializerCollection.h> namespace Swift { class FullPayloadSerializerCollection : public PayloadSerializerCollection { @@ -21,5 +20,3 @@ namespace Swift { std::vector<PayloadSerializer*> serializers_; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp b/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp index 7ac4103..f3dad80 100644 --- a/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/IBBSerializer.cpp @@ -4,16 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/IBBSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/IBBSerializer.h> #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/IBBSerializer.h b/Swiften/Serializer/PayloadSerializers/IBBSerializer.h index d750f6f..229f131 100644 --- a/Swiften/Serializer/PayloadSerializers/IBBSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/IBBSerializer.h @@ -6,12 +6,10 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/IBB.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/IBB.h> namespace Swift { - class PayloadSerializerCollection; - class IBBSerializer : public GenericPayloadSerializer<IBB> { public: IBBSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.cpp index e4ae11f..12b1bb5 100644 --- a/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h index 45d49ea..3b88590 100644 --- a/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h @@ -7,12 +7,10 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/InBandRegistrationPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/InBandRegistrationPayload.h> namespace Swift { - class PayloadSerializerCollection; - class InBandRegistrationPayloadSerializer : public GenericPayloadSerializer<InBandRegistrationPayload> { public: InBandRegistrationPayloadSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp new file mode 100644 index 0000000..90bd940 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/smart_ptr/intrusive_ptr.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h> + +#include <Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> + +#include "Swiften/FileTransfer/JingleTransport.h" + +namespace Swift { + +JingleContentPayloadSerializer::JingleContentPayloadSerializer() { +} + +std::string JingleContentPayloadSerializer::serializePayload(boost::shared_ptr<JingleContentPayload> payload) const { + XMLElement payloadXML("content"); + payloadXML.setAttribute("creator", creatorToString(payload->getCreator())); + payloadXML.setAttribute("name", payload->getName()); + + if (!payload->getDescriptions().empty()) { + // JingleFileTransferDescription + JingleFileTransferDescriptionSerializer ftSerializer; + JingleFileTransferDescription::ref filetransfer; + + foreach(JingleDescription::ref desc, payload->getDescriptions()) { + if ((filetransfer = boost::dynamic_pointer_cast<JingleFileTransferDescription>(desc))) { + payloadXML.addNode(boost::make_shared<XMLRawTextNode>(ftSerializer.serializePayload(filetransfer))); + } + } + } + + if (!payload->getTransports().empty()) { + // JingleIBBTransportPayload + JingleIBBTransportPayloadSerializer ibbSerializer; + JingleIBBTransportPayload::ref ibb; + + // JingleS5BTransportPayload + JingleS5BTransportPayloadSerializer s5bSerializer; + JingleS5BTransportPayload::ref s5b; + + foreach(JingleTransportPayload::ref transport, payload->getTransports()) { + if ((ibb = boost::dynamic_pointer_cast<JingleIBBTransportPayload>(transport))) { + payloadXML.addNode(boost::make_shared<XMLRawTextNode>(ibbSerializer.serializePayload(ibb))); + } else if ((s5b = boost::dynamic_pointer_cast<JingleS5BTransportPayload>(transport))) { + payloadXML.addNode(boost::make_shared<XMLRawTextNode>(s5bSerializer.serializePayload(s5b))); + } + } + } + return payloadXML.serialize(); +} + +std::string JingleContentPayloadSerializer::creatorToString(JingleContentPayload::Creator creator) const { + switch(creator) { + case JingleContentPayload::InitiatorCreator: + return "initiator"; + case JingleContentPayload::ResponderCreator: + return "responder"; + case JingleContentPayload::UnknownCreator: + std::cerr << "Serializing unknown creator value." << std::endl; + return "ERROR ERROR ERROR"; + } + assert(false); +} +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h new file mode 100644 index 0000000..2de0064 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleContentPayload.h> + +namespace Swift { + class PayloadSerializerCollection; + + class JingleContentPayloadSerializer : public GenericPayloadSerializer<JingleContentPayload> { + public: + JingleContentPayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleContentPayload>) const; + + private: + std::string creatorToString(JingleContentPayload::Creator creator) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp new file mode 100644 index 0000000..16337ff --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h> + +namespace Swift { + +JingleFileTransferDescriptionSerializer::JingleFileTransferDescriptionSerializer() { +} + +std::string JingleFileTransferDescriptionSerializer::serializePayload(boost::shared_ptr<JingleFileTransferDescription> payload) const { + XMLElement description("description", "urn:xmpp:jingle:apps:file-transfer:3"); + StreamInitiationFileInfoSerializer fileInfoSerializer; + if (!payload->getOffers().empty()) { + boost::shared_ptr<XMLElement> offers = boost::make_shared<XMLElement>("offer"); + foreach(const StreamInitiationFileInfo &fileInfo, payload->getOffers()) { + boost::shared_ptr<XMLRawTextNode> fileInfoXML = boost::make_shared<XMLRawTextNode>(fileInfoSerializer.serialize(boost::make_shared<StreamInitiationFileInfo>(fileInfo))); + offers->addNode(fileInfoXML); + } + description.addNode(offers); + } + if (!payload->getRequests().empty()) { + boost::shared_ptr<XMLElement> requests = boost::make_shared<XMLElement>("request"); + foreach(const StreamInitiationFileInfo &fileInfo, payload->getRequests()) { + boost::shared_ptr<XMLRawTextNode> fileInfoXML = boost::make_shared<XMLRawTextNode>(fileInfoSerializer.serialize(boost::make_shared<StreamInitiationFileInfo>(fileInfo))); + requests->addNode(fileInfoXML); + } + description.addNode(requests); + } + return description.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h new file mode 100644 index 0000000..5131435 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> + + + +namespace Swift { + class PayloadSerializerCollection; + class XMLElement; + + class JingleFileTransferDescriptionSerializer : public GenericPayloadSerializer<JingleFileTransferDescription> { + public: + JingleFileTransferDescriptionSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleFileTransferDescription>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp new file mode 100644 index 0000000..2bd3afa --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h> + +#include <string> +#include <map> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + + +namespace Swift { + +JingleFileTransferHashSerializer::JingleFileTransferHashSerializer() { +} + +std::string JingleFileTransferHashSerializer::serializePayload(boost::shared_ptr<JingleFileTransferHash> payload) const { + // code for version urn:xmpp:jingle:apps:file-transfer:2 + //XMLElement hash("hash", "urn:xmpp:jingle:apps:file-transfer:info:2", payload->getHash()); + + // code for version urn:xmpp:jingle:apps:file-transfer:3 + XMLElement checksum("checksum", "urn:xmpp:jingle:apps:file-transfer:3"); + boost::shared_ptr<XMLElement> file = boost::make_shared<XMLElement>("file"); + checksum.addNode(file); + boost::shared_ptr<XMLElement> hashes = boost::make_shared<XMLElement>("hashes", "urn:xmpp:hashes:0"); + file->addNode(hashes); + foreach(const JingleFileTransferHash::HashesMap::value_type& pair, payload->getHashes()) { + boost::shared_ptr<XMLElement> hash = boost::make_shared<XMLElement>("hash", "", pair.second); + hash->setAttribute("algo", pair.first); + hashes->addNode(hash); + } + + return checksum.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h new file mode 100644 index 0000000..7fa6ac5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleFileTransferHash.h> + +namespace Swift { + class PayloadSerializerCollection; + class XMLElement; + + class JingleFileTransferHashSerializer : public GenericPayloadSerializer<JingleFileTransferHash> { + public: + JingleFileTransferHashSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleFileTransferHash>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.cpp new file mode 100644 index 0000000..40be70e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +namespace Swift { + +JingleFileTransferReceivedSerializer::JingleFileTransferReceivedSerializer() { +} + +std::string JingleFileTransferReceivedSerializer::serializePayload(boost::shared_ptr<JingleFileTransferReceived> payload) const { + XMLElement receivedElement("received", "urn:xmpp:jingle:apps:file-transfer:3"); + XMLElement::ref fileElement = boost::make_shared<XMLElement>("file", "http://jabber.org/protocol/si/profile/file-transfer"); + fileElement->setAttribute("hash", payload->getFileInfo().getHash()); + if (payload->getFileInfo().getAlgo() != "md5") { + fileElement->setAttribute("algo", payload->getFileInfo().getAlgo()); + } + receivedElement.addNode(fileElement); + return receivedElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h new file mode 100644 index 0000000..4151dd0 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleFileTransferReceived.h> + +namespace Swift { + class PayloadSerializerCollection; + class XMLElement; + + class JingleFileTransferReceivedSerializer : public GenericPayloadSerializer<JingleFileTransferReceived> { + public: + JingleFileTransferReceivedSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleFileTransferReceived>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp new file mode 100644 index 0000000..029a5b4 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> + +namespace Swift { + +JingleIBBTransportPayloadSerializer::JingleIBBTransportPayloadSerializer() { +} + +std::string JingleIBBTransportPayloadSerializer::serializePayload(boost::shared_ptr<JingleIBBTransportPayload> payload) const { + XMLElement payloadXML("transport", "urn:xmpp:jingle:transports:ibb:1"); + payloadXML.setAttribute("block-size", boost::lexical_cast<std::string>(payload->getBlockSize())); + payloadXML.setAttribute("sid", payload->getSessionID()); + + return payloadXML.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h new file mode 100644 index 0000000..ac9cba9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> + + + +namespace Swift { + class PayloadSerializerCollection; + class XMLElement; + + class JingleIBBTransportPayloadSerializer : public GenericPayloadSerializer<JingleIBBTransportPayload> { + public: + JingleIBBTransportPayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleIBBTransportPayload>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp new file mode 100644 index 0000000..25d35ff --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/smart_ptr/intrusive_ptr.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/JingleContentPayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h> + +#include <Swiften/Serializer/PayloadSerializerCollection.h> + +#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Elements/JingleContentPayload.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Elements/JingleFileTransferReceived.h> + +namespace Swift { + +JinglePayloadSerializer::JinglePayloadSerializer(PayloadSerializerCollection* serializers) : serializers(serializers) { +} + +std::string JinglePayloadSerializer::serializePayload(boost::shared_ptr<JinglePayload> payload) const { + XMLElement jinglePayload("jingle", "urn:xmpp:jingle:1"); + jinglePayload.setAttribute("action", actionToString(payload->getAction())); + jinglePayload.setAttribute("initiator", payload->getInitiator()); + jinglePayload.setAttribute("sid", payload->getSessionID()); + + if (!payload->getPayloads().empty()) { + foreach(boost::shared_ptr<Payload> subPayload, payload->getPayloads()) { + PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload); + if (serializer) { + jinglePayload.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(subPayload)))); + } + } + } + + if (payload->getReason().is_initialized()) { + boost::shared_ptr<XMLElement> reason = boost::make_shared<XMLElement>("reason"); + reason->addNode(boost::make_shared<XMLElement>(reasonTypeToString(payload->getReason()->type))); + if (!payload->getReason()->text.empty()) { + reason->addNode(boost::make_shared<XMLElement>("desc", "", payload->getReason()->text)); + } + jinglePayload.addNode(reason); + } + + return jinglePayload.serialize(); +} + +std::string JinglePayloadSerializer::actionToString(JinglePayload::Action action) const { + switch(action) { + case JinglePayload::ContentAccept: + return "content-accept"; + case JinglePayload::ContentAdd: + return "content-add"; + case JinglePayload::ContentModify: + return "content-modify"; + case JinglePayload::ContentReject: + return "content-reject"; + case JinglePayload::ContentRemove: + return "content-remove"; + case JinglePayload::DescriptionInfo: + return "description-info"; + case JinglePayload::SecurityInfo: + return "security-info"; + case JinglePayload::SessionAccept: + return "session-accept"; + case JinglePayload::SessionInfo: + return "session-info"; + case JinglePayload::SessionInitiate: + return "session-initiate"; + case JinglePayload::SessionTerminate: + return "session-terminate"; + case JinglePayload::TransportAccept: + return "transport-accept"; + case JinglePayload::TransportInfo: + return "transport-info"; + case JinglePayload::TransportReject: + return "transport-reject"; + case JinglePayload::TransportReplace: + return "transport-replace"; + case JinglePayload::UnknownAction: + std::cerr << "Serializing unknown action value." << std::endl; + return ""; + } + assert(false); +} + +std::string JinglePayloadSerializer::reasonTypeToString(JinglePayload::Reason::Type type) const { + switch(type) { + case JinglePayload::Reason::UnknownType: + std::cerr << "Unknown jingle reason type!" << std::endl; + return ""; + case JinglePayload::Reason::AlternativeSession: + return "alternative-session"; + case JinglePayload::Reason::Busy: + return "busy"; + case JinglePayload::Reason::Cancel: + return "cancel"; + case JinglePayload::Reason::ConnectivityError: + return "connectivity-error"; + case JinglePayload::Reason::Decline: + return "decline"; + case JinglePayload::Reason::Expired: + return "expired"; + case JinglePayload::Reason::FailedApplication: + return "failed-application"; + case JinglePayload::Reason::FailedTransport: + return "failed-transport"; + case JinglePayload::Reason::GeneralError: + return "general-error"; + case JinglePayload::Reason::Gone: + return "gone"; + case JinglePayload::Reason::IncompatibleParameters: + return "incompatible-parameters"; + case JinglePayload::Reason::MediaError: + return "media-error"; + case JinglePayload::Reason::SecurityError: + return "security-error"; + case JinglePayload::Reason::Success: + return "success"; + case JinglePayload::Reason::Timeout: + return "timeout"; + case JinglePayload::Reason::UnsupportedApplications: + return "unsupported-applications"; + case JinglePayload::Reason::UnsupportedTransports: + return "unsupported-transports"; + } + assert(false); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h new file mode 100644 index 0000000..ccdb6d0 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JinglePayload.h> + +namespace Swift { + class PayloadSerializerCollection; + class XMLElement; + + class JinglePayloadSerializer : public GenericPayloadSerializer<JinglePayload> { + public: + JinglePayloadSerializer(PayloadSerializerCollection*); + + virtual std::string serializePayload(boost::shared_ptr<JinglePayload>) const; + + private: + std::string actionToString(JinglePayload::Action action) const; + std::string reasonTypeToString(JinglePayload::Reason::Type type) const; + + private: + PayloadSerializerCollection* serializers; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp new file mode 100644 index 0000000..c5b40d5 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Base/Log.h> + +namespace Swift { + +JingleS5BTransportPayloadSerializer::JingleS5BTransportPayloadSerializer() { +} + +std::string JingleS5BTransportPayloadSerializer::serializePayload(boost::shared_ptr<JingleS5BTransportPayload> payload) const { + XMLElement payloadXML("transport", "urn:xmpp:jingle:transports:s5b:1"); + payloadXML.setAttribute("sid", payload->getSessionID()); + payloadXML.setAttribute("mode", modeToString(payload->getMode())); + + foreach(JingleS5BTransportPayload::Candidate candidate, payload->getCandidates()) { + boost::shared_ptr<XMLElement> candidateXML = boost::make_shared<XMLElement>("candidate"); + candidateXML->setAttribute("cid", candidate.cid); + candidateXML->setAttribute("host", candidate.hostPort.getAddress().toString()); + candidateXML->setAttribute("jid", candidate.jid.toString()); + candidateXML->setAttribute("port", boost::lexical_cast<std::string>(candidate.hostPort.getPort())); + candidateXML->setAttribute("priority", boost::lexical_cast<std::string>(candidate.priority)); + candidateXML->setAttribute("type", typeToString(candidate.type)); + payloadXML.addNode(candidateXML); + } + + if (payload->hasCandidateError()) { + payloadXML.addNode(boost::make_shared<XMLElement>("candidate-error")); + } + if (payload->hasProxyError()) { + payloadXML.addNode(boost::make_shared<XMLElement>("proxy-error")); + } + + if (!payload->getActivated().empty()) { + boost::shared_ptr<XMLElement> activatedXML = boost::make_shared<XMLElement>("activated"); + activatedXML->setAttribute("cid", payload->getActivated()); + payloadXML.addNode(activatedXML); + } + if (!payload->getCandidateUsed().empty()) { + boost::shared_ptr<XMLElement> candusedXML = boost::make_shared<XMLElement>("candidate-used"); + candusedXML->setAttribute("cid", payload->getCandidateUsed()); + payloadXML.addNode(candusedXML); + } + + return payloadXML.serialize(); +} + +std::string JingleS5BTransportPayloadSerializer::modeToString(JingleS5BTransportPayload::Mode mode) const { + switch(mode) { + case JingleS5BTransportPayload::TCPMode: + return "tcp"; + case JingleS5BTransportPayload::UDPMode: + return "udp"; + } + assert(false); +} + +std::string JingleS5BTransportPayloadSerializer::typeToString(JingleS5BTransportPayload::Candidate::Type type) const { + switch(type) { + case JingleS5BTransportPayload::Candidate::AssistedType: + return "assisted"; + case JingleS5BTransportPayload::Candidate::DirectType: + return "direct"; + case JingleS5BTransportPayload::Candidate::ProxyType: + return "proxy"; + case JingleS5BTransportPayload::Candidate::TunnelType: + return "tunnel"; + } + assert(false); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h new file mode 100644 index 0000000..210688d --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> + +namespace Swift { + class PayloadSerializerCollection; + class XMLElement; + + class JingleS5BTransportPayloadSerializer : public GenericPayloadSerializer<JingleS5BTransportPayload> { + public: + JingleS5BTransportPayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleS5BTransportPayload>) const; + + private: + std::string modeToString(JingleS5BTransportPayload::Mode) const; + std::string typeToString(JingleS5BTransportPayload::Candidate::Type) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/LastSerializer.h b/Swiften/Serializer/PayloadSerializers/LastSerializer.h new file mode 100644 index 0000000..e91d702 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/LastSerializer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/lexical_cast.hpp> + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Last.h> + +namespace Swift { + class LastSerializer : public GenericPayloadSerializer<Last> { + public: + LastSerializer() : GenericPayloadSerializer<Last>() {} + + virtual std::string serializePayload(boost::shared_ptr<Last> last) const { + return "<query xmlns='jabber:iq:last' seconds='" + boost::lexical_cast<std::string>(last->getSeconds()) + "'/>"; + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp new file mode 100644 index 0000000..552f7f1 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h> + +#include <sstream> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h> + + +namespace Swift { + +MUCAdminPayloadSerializer::MUCAdminPayloadSerializer() : GenericPayloadSerializer<MUCAdminPayload>() { +} + +std::string MUCAdminPayloadSerializer::serializePayload(boost::shared_ptr<MUCAdminPayload> payload) const { + XMLElement mucElement("query", "http://jabber.org/protocol/muc#admin"); + foreach (const MUCItem item, payload->getItems()) { + mucElement.addNode(MUCItemSerializer::itemToElement(item)); + } + return mucElement.serialize(); +} + + +} diff --git a/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h new file mode 100644 index 0000000..e288cd7 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/MUCAdminPayload.h> + +namespace Swift { + class MUCAdminPayloadSerializer : public GenericPayloadSerializer<MUCAdminPayload> { + public: + MUCAdminPayloadSerializer(); + std::string affiliationToString(MUCOccupant::Affiliation affiliation) const; + std::string roleToString(MUCOccupant::Role role) const; + + virtual std::string serializePayload(boost::shared_ptr<MUCAdminPayload> version) const; + }; +} + diff --git a/Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.cpp new file mode 100644 index 0000000..e78a381 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> + +namespace Swift { + +MUCDestroyPayloadSerializer::MUCDestroyPayloadSerializer() : GenericPayloadSerializer<MUCDestroyPayload>() { +} + +std::string MUCDestroyPayloadSerializer::serializePayload(boost::shared_ptr<MUCDestroyPayload> payload) const { + XMLElement mucElement("destroy", ""); + if (!payload->getReason().empty()) { + XMLElement::ref reason = boost::make_shared<XMLElement>("reason", ""); + reason->addNode(boost::make_shared<XMLTextNode>(payload->getReason())); + mucElement.addNode(reason); + } + if (payload->getNewVenue().isValid()) { + mucElement.setAttribute("jid", payload->getNewVenue().toString()); + } + return mucElement.serialize(); +} + + + + +} diff --git a/Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h new file mode 100644 index 0000000..419a683 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MUCDestroyPayloadSerializer.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/MUCDestroyPayload.h> + +namespace Swift { + class PayloadSerializerCollection; + class MUCDestroyPayloadSerializer : public GenericPayloadSerializer<MUCDestroyPayload> { + public: + MUCDestroyPayloadSerializer(); + virtual std::string serializePayload(boost::shared_ptr<MUCDestroyPayload> version) const; + }; +} + diff --git a/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h new file mode 100644 index 0000000..7cb662c --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/MUCItem.h> +#include <boost/smart_ptr/make_shared.hpp> + +namespace Swift { + class MUCItemSerializer { + public: + static std::string affiliationToString(MUCOccupant::Affiliation affiliation) { + std::string result; + switch (affiliation) { + case MUCOccupant::Owner: result = "owner"; break; + case MUCOccupant::Admin: result = "admin"; break; + case MUCOccupant::Member: result = "member"; break; + case MUCOccupant::Outcast: result = "outcast"; break; + case MUCOccupant::NoAffiliation: result = "none"; break; + default: assert(false); + } + return result; + } + + static std::string roleToString(MUCOccupant::Role role) { + std::string result; + switch (role) { + case MUCOccupant::Moderator: result = "moderator"; break; + case MUCOccupant::NoRole: result = "none"; break; + case MUCOccupant::Participant: result = "participant"; break; + case MUCOccupant::Visitor: result = "visitor"; break; + default: assert(false); + } + return result; + + } + + static boost::shared_ptr<XMLElement> itemToElement(const MUCItem& item) { + boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); + if (item.affiliation) { + itemElement->setAttribute("affiliation", affiliationToString(item.affiliation.get())); + } + if (item.role) { + itemElement->setAttribute("role", roleToString(item.role.get())); + } + if (item.realJID) { + itemElement->setAttribute("jid", item.realJID.get()); + } + if (item.nick) { + itemElement->setAttribute("nick", item.nick.get()); + } + if (item.actor) { + boost::shared_ptr<XMLElement> actorElement(new XMLElement("actor")); + actorElement->setAttribute("jid", item.actor->toString()); + itemElement->addNode(actorElement); + } + if (item.reason) { + boost::shared_ptr<XMLElement> reasonElement(new XMLElement("reason")); + reasonElement->addNode(boost::make_shared<XMLTextNode>(*item.reason)); + itemElement->addNode(reasonElement); + } + return itemElement; + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp index db28514..f86b59e 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h> -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h index 4808744..5e6913a 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/MUCOwnerPayloadSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/MUCOwnerPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/MUCOwnerPayload.h> namespace Swift { class PayloadSerializerCollection; diff --git a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp index d7e1613..7080e14 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.cpp @@ -4,9 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h> -#include "Swiften/Serializer/XML/XMLElement.h" +#include <boost/lexical_cast.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/Serializer/XML/XMLElement.h> #include <Swiften/Base/String.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h index 7038e6e..4bf8d22 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/MUCPayloadSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/MUCPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/MUCPayload.h> namespace Swift { class MUCPayloadSerializer : public GenericPayloadSerializer<MUCPayload> { diff --git a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp index 50746a9..68662b1 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.cpp @@ -4,24 +4,26 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h> #include <sstream> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" - +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/MUCItemSerializer.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> namespace Swift { -MUCUserPayloadSerializer::MUCUserPayloadSerializer() : GenericPayloadSerializer<MUCUserPayload>() { +MUCUserPayloadSerializer::MUCUserPayloadSerializer(PayloadSerializerCollection* serializers) : GenericPayloadSerializer<MUCUserPayload>(), serializers(serializers) { } std::string MUCUserPayloadSerializer::serializePayload(boost::shared_ptr<MUCUserPayload> payload) const { - XMLElement mucElement("x", "http://jabber.org/protocol/muc"); + XMLElement mucElement("x", "http://jabber.org/protocol/muc#user"); foreach (const MUCUserPayload::StatusCode statusCode, payload->getStatusCodes()) { boost::shared_ptr<XMLElement> statusElement(new XMLElement("status")); std::ostringstream code; @@ -29,46 +31,20 @@ std::string MUCUserPayloadSerializer::serializePayload(boost::shared_ptr<MUCUser statusElement->setAttribute("code", code.str()); mucElement.addNode(statusElement); } - foreach (const MUCUserPayload::Item item, payload->getItems()) { - boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); - itemElement->setAttribute("affiliation", affiliationToString(item.affiliation)); - itemElement->setAttribute("role", roleToString(item.role)); - if (item.realJID) { - itemElement->setAttribute("jid", item.realJID.get()); - } - if (item.nick) { - itemElement->setAttribute("nick", item.nick.get()); + foreach (const MUCItem item, payload->getItems()) { + mucElement.addNode(MUCItemSerializer::itemToElement(item)); + } + boost::shared_ptr<Payload> childPayload = payload->getPayload(); + if (childPayload) { + PayloadSerializer* serializer = serializers->getPayloadSerializer(childPayload); + if (serializer) { + mucElement.addNode(boost::shared_ptr<XMLRawTextNode>(new XMLRawTextNode(serializer->serialize(childPayload)))); } - mucElement.addNode(itemElement); } return mucElement.serialize(); } -std::string MUCUserPayloadSerializer::affiliationToString(MUCOccupant::Affiliation affiliation) const { - std::string result; - switch (affiliation) { - case MUCOccupant::Owner: result = "owner"; break; - case MUCOccupant::Admin: result = "admin"; break; - case MUCOccupant::Member: result = "member"; break; - case MUCOccupant::Outcast: result = "outcast"; break; - case MUCOccupant::NoAffiliation: result = "none"; break; - default: assert(false); - } - return result; -} - -std::string MUCUserPayloadSerializer::roleToString(MUCOccupant::Role role) const { - std::string result; - switch (role) { - case MUCOccupant::Moderator: result = "moderator"; break; - case MUCOccupant::NoRole: result = "none"; break; - case MUCOccupant::Participant: result = "participant"; break; - case MUCOccupant::Visitor: result = "visitor"; break; - default: assert(false); - } - return result; -} } diff --git a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h index 54e6aff..8c237e0 100644 --- a/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/MUCUserPayloadSerializer.h @@ -6,17 +6,18 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/MUCUserPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/MUCUserPayload.h> namespace Swift { + class PayloadSerializerCollection; class MUCUserPayloadSerializer : public GenericPayloadSerializer<MUCUserPayload> { public: - MUCUserPayloadSerializer(); - std::string affiliationToString(MUCOccupant::Affiliation affiliation) const; - std::string roleToString(MUCOccupant::Role role) const; + MUCUserPayloadSerializer(PayloadSerializerCollection* serializers); virtual std::string serializePayload(boost::shared_ptr<MUCUserPayload> version) const; + private: + PayloadSerializerCollection* serializers; }; } diff --git a/Swiften/Serializer/PayloadSerializers/NicknameSerializer.cpp b/Swiften/Serializer/PayloadSerializers/NicknameSerializer.cpp index 23d2c25..38a5db5 100644 --- a/Swiften/Serializer/PayloadSerializers/NicknameSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/NicknameSerializer.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/NicknameSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/NicknameSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/NicknameSerializer.h b/Swiften/Serializer/PayloadSerializers/NicknameSerializer.h index e07767b..382ec11 100644 --- a/Swiften/Serializer/PayloadSerializers/NicknameSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/NicknameSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Nickname.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Nickname.h> namespace Swift { class NicknameSerializer : public GenericPayloadSerializer<Nickname> { diff --git a/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h b/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h index cc96ce7..5a2ef27 100644 --- a/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h +++ b/Swiften/Serializer/PayloadSerializers/PrioritySerializer.h @@ -4,13 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PrioritySerializer_H -#define SWIFTEN_PrioritySerializer_H +#pragma once #include <boost/lexical_cast.hpp> -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Priority.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Priority.h> namespace Swift { class PrioritySerializer : public GenericPayloadSerializer<Priority> { @@ -22,5 +21,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.cpp b/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.cpp index 6e1d74d..6cb226c 100644 --- a/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h b/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h index 7b46136..3548cac 100644 --- a/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/PrivateStorageSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/PrivateStorage.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/PrivateStorage.h> namespace Swift { class PayloadSerializerCollection; diff --git a/Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h index 6874569..02a5564 100644 --- a/Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/RawXMLPayloadSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/RawXMLPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/RawXMLPayload.h> namespace Swift { class RawXMLPayloadSerializer : public GenericPayloadSerializer<RawXMLPayload> { diff --git a/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h b/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h new file mode 100644 index 0000000..88ad2b3 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Elements/Replace.h> + +namespace Swift { + class ReplaceSerializer : public GenericPayloadSerializer<Replace> { + public: + ReplaceSerializer() : GenericPayloadSerializer<Replace>() {} + + virtual std::string serializePayload(boost::shared_ptr<Replace> replace) const { + return "<replace id = '" + replace->getID() + "' xmlns='http://swift.im/protocol/replace'/>"; + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.cpp b/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.cpp index cfb3a90..af0c609 100644 --- a/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h b/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h index d259555..133e45e 100644 --- a/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ResourceBindSerializer_H -#define SWIFTEN_ResourceBindSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/ResourceBind.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/ResourceBind.h> namespace Swift { class ResourceBindSerializer : public GenericPayloadSerializer<ResourceBind> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<ResourceBind>) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp new file mode 100644 index 0000000..b60db12 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h> + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +namespace Swift { + +RosterItemExchangeSerializer::RosterItemExchangeSerializer() : GenericPayloadSerializer<RosterItemExchangePayload>() { +} + +std::string RosterItemExchangeSerializer::serializePayload(boost::shared_ptr<RosterItemExchangePayload> roster) const { + XMLElement queryElement("x", "http://jabber.org/protocol/rosterx"); + foreach(const RosterItemExchangePayload::Item& item, roster->getItems()) { + boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); + itemElement->setAttribute("jid", item.getJID()); + itemElement->setAttribute("name", item.getName()); + + switch (item.getAction()) { + case RosterItemExchangePayload::Item::Add: itemElement->setAttribute("action", "add"); break; + case RosterItemExchangePayload::Item::Modify: itemElement->setAttribute("action", "modify"); break; + case RosterItemExchangePayload::Item::Delete: itemElement->setAttribute("action", "delete"); break; + } + + foreach(const std::string& group, item.getGroups()) { + boost::shared_ptr<XMLElement> groupElement(new XMLElement("group")); + groupElement->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(group))); + itemElement->addNode(groupElement); + } + + queryElement.addNode(itemElement); + } + + return queryElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h new file mode 100644 index 0000000..f246f9e --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/RosterItemExchangePayload.h> + +namespace Swift { + class RosterItemExchangeSerializer : public GenericPayloadSerializer<RosterItemExchangePayload> { + public: + RosterItemExchangeSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<RosterItemExchangePayload>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp b/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp index 40faf73..84f36d2 100644 --- a/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/RosterSerializer.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/RosterSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { @@ -20,6 +20,9 @@ RosterSerializer::RosterSerializer() : GenericPayloadSerializer<RosterPayload>() std::string RosterSerializer::serializePayload(boost::shared_ptr<RosterPayload> roster) const { XMLElement queryElement("query", "jabber:iq:roster"); + if (roster->getVersion()) { + queryElement.setAttribute("ver", *roster->getVersion()); + } foreach(const RosterItemPayload& item, roster->getItems()) { boost::shared_ptr<XMLElement> itemElement(new XMLElement("item")); itemElement->setAttribute("jid", item.getJID()); diff --git a/Swiften/Serializer/PayloadSerializers/RosterSerializer.h b/Swiften/Serializer/PayloadSerializers/RosterSerializer.h index 49e194b..52fdb2a 100644 --- a/Swiften/Serializer/PayloadSerializers/RosterSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/RosterSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterSerializer_H -#define SWIFTEN_RosterSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/RosterPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/RosterPayload.h> namespace Swift { class RosterSerializer : public GenericPayloadSerializer<RosterPayload> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<RosterPayload>) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h b/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h new file mode 100644 index 0000000..b523588 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/S5BProxyRequestSerializer.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <boost/lexical_cast.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Elements/S5BProxyRequest.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +namespace Swift { + class PayloadSerializerCollection; + + class S5BProxyRequestSerializer : public GenericPayloadSerializer<S5BProxyRequest> { + public: + virtual std::string serializePayload(boost::shared_ptr<S5BProxyRequest> s5bProxyRequest) const { + XMLElement queryElement("query", "http://jabber.org/protocol/bytestreams"); + if (s5bProxyRequest && s5bProxyRequest->getStreamHost()) { + boost::shared_ptr<XMLElement> streamHost = boost::make_shared<XMLElement>("streamhost"); + streamHost->setAttribute("host", s5bProxyRequest->getStreamHost().get().addressPort.getAddress().toString()); + streamHost->setAttribute("port", boost::lexical_cast<std::string>(s5bProxyRequest->getStreamHost().get().addressPort.getPort())); + streamHost->setAttribute("jid", s5bProxyRequest->getStreamHost().get().jid.toString()); + queryElement.addNode(streamHost); + } else if (s5bProxyRequest && s5bProxyRequest->getActivate()) { + queryElement.setAttribute("sid", s5bProxyRequest->getSID()); + boost::shared_ptr<XMLElement> activate = boost::make_shared<XMLElement>("activate", "", s5bProxyRequest->getActivate().get().toString()); + queryElement.addNode(activate); + } + return queryElement.serialize(); + } + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp index a7a9fda..a5cd634 100644 --- a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h index 2d8ec85..e4dbff8 100644 --- a/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h @@ -7,8 +7,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/SearchPayload.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/SearchPayload.h> namespace Swift { class PayloadSerializerCollection; diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.cpp b/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.cpp index b9ec55e..51079ee 100644 --- a/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h b/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h index a02aeb9..a1915c7 100644 --- a/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelSerializer_H -#define SWIFTEN_SecurityLabelSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/SecurityLabel.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/SecurityLabel.h> namespace Swift { class SecurityLabelSerializer : public GenericPayloadSerializer<SecurityLabel> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<SecurityLabel> version) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp index 7424c98..1078292 100644 --- a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h index 88a1541..02104df 100644 --- a/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SecurityLabelsCatalogSerializer_H -#define SWIFTEN_SecurityLabelsCatalogSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/SecurityLabelsCatalog.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/SecurityLabelsCatalog.h> namespace Swift { class SecurityLabelsCatalogSerializer : public GenericPayloadSerializer<SecurityLabelsCatalog> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<SecurityLabelsCatalog> version) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.cpp index b2eb1ed..e117167 100644 --- a/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h b/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h index 72f4afd..98fa243 100644 --- a/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SoftwareVersionSerializer_H -#define SWIFTEN_SoftwareVersionSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/SoftwareVersion.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/SoftwareVersion.h> namespace Swift { class SoftwareVersionSerializer : public GenericPayloadSerializer<SoftwareVersion> { @@ -18,5 +17,3 @@ namespace Swift { virtual std::string serializePayload(boost::shared_ptr<SoftwareVersion> version) const; }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h b/Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h index dd9ba97..2082f4b 100644 --- a/Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StartSessionSerializer.h @@ -4,13 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartSessionSerializer_H -#define SWIFTEN_StartSessionSerializer_H +#pragma once #include <boost/lexical_cast.hpp> -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/StartSession.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/StartSession.h> namespace Swift { class StartSessionSerializer : public GenericPayloadSerializer<StartSession> { @@ -22,5 +21,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/StatusSerializer.h b/Swiften/Serializer/PayloadSerializers/StatusSerializer.h index 565d554..a8de26f 100644 --- a/Swiften/Serializer/PayloadSerializers/StatusSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StatusSerializer.h @@ -4,13 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StatusSerializer_H -#define SWIFTEN_StatusSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Elements/Status.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Elements/Status.h> namespace Swift { class StatusSerializer : public GenericPayloadSerializer<Status> { @@ -24,5 +23,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h b/Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h index e797e81..e65c1b6 100644 --- a/Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StatusShowSerializer_H -#define SWIFTEN_StatusShowSerializer_H +#pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/StatusShow.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/StatusShow.h> namespace Swift { class StatusShowSerializer : public GenericPayloadSerializer<StatusShow> { @@ -35,5 +34,3 @@ namespace Swift { } }; } - -#endif diff --git a/Swiften/Serializer/PayloadSerializers/StorageSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StorageSerializer.cpp index 049c797..30adf26 100644 --- a/Swiften/Serializer/PayloadSerializers/StorageSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/StorageSerializer.cpp @@ -4,13 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/StorageSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/StorageSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/StorageSerializer.h b/Swiften/Serializer/PayloadSerializers/StorageSerializer.h index bc682a6..6f4f03b 100644 --- a/Swiften/Serializer/PayloadSerializers/StorageSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StorageSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/Storage.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/Storage.h> namespace Swift { class StorageSerializer : public GenericPayloadSerializer<Storage> { diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp new file mode 100644 index 0000000..7b0cad8 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/DateTime.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> + + + +namespace Swift { + +StreamInitiationFileInfoSerializer::StreamInitiationFileInfoSerializer() { +} + +std::string StreamInitiationFileInfoSerializer::serializePayload(boost::shared_ptr<StreamInitiationFileInfo> fileInfo) const { + XMLElement fileElement("file", "http://jabber.org/protocol/si/profile/file-transfer"); + + if (fileInfo->getDate() != stringToDateTime("")) { + fileElement.setAttribute("date", dateTimeToString(fileInfo->getDate())); + } + fileElement.setAttribute("hash", fileInfo->getHash()); + if (fileInfo->getAlgo() != "md5") { + fileElement.setAttribute("algo", fileInfo->getAlgo()); + } + if (!fileInfo->getName().empty()) { + fileElement.setAttribute("name", fileInfo->getName()); + } + if (fileInfo->getSize() != 0) { + fileElement.setAttribute("size", boost::lexical_cast<std::string>(fileInfo->getSize())); + } + if (!fileInfo->getDescription().empty()) { + boost::shared_ptr<XMLElement> desc = boost::make_shared<XMLElement>("desc", "", fileInfo->getDescription()); + fileElement.addNode(desc); + } + if (fileInfo->getSupportsRangeRequests()) { + boost::shared_ptr<XMLElement> range = boost::make_shared<XMLElement>("range"); + if (fileInfo->getRangeOffset() != 0) { + range->setAttribute("offset", boost::lexical_cast<std::string>(fileInfo->getRangeOffset())); + } + fileElement.addNode(range); + } + return fileElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h new file mode 100644 index 0000000..4ac0a0d --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + + +#pragma once + +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/StreamInitiationFileInfo.h> + +#include <Swiften/Serializer/XML/XMLElement.h> + +namespace Swift { + class PayloadSerializerCollection; + + class StreamInitiationFileInfoSerializer : public GenericPayloadSerializer<StreamInitiationFileInfo> { + public: + StreamInitiationFileInfoSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<StreamInitiationFileInfo>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp index 70fb2ac..9ccfab2 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.cpp @@ -4,17 +4,16 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h> #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> #define FILE_TRANSFER_NS "http://jabber.org/protocol/si/profile/file-transfer" @@ -37,19 +36,19 @@ std::string StreamInitiationSerializer::serializePayload(boost::shared_ptr<Strea if (streamInitiation->getFileInfo()) { StreamInitiationFileInfo file = *streamInitiation->getFileInfo(); boost::shared_ptr<XMLElement> fileElement(new XMLElement("file", "http://jabber.org/protocol/si/profile/file-transfer")); - fileElement->setAttribute("name", file.name); - if (file.size != -1) { - fileElement->setAttribute("size", boost::lexical_cast<std::string>(file.size)); + fileElement->setAttribute("name", file.getName()); + if (file.getSize() != 0) { + fileElement->setAttribute("size", boost::lexical_cast<std::string>(file.getSize())); } - if (!file.description.empty()) { + if (!file.getDescription().empty()) { boost::shared_ptr<XMLElement> descElement(new XMLElement("desc")); - descElement->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(file.description))); + descElement->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(file.getDescription()))); fileElement->addNode(descElement); } siElement.addNode(fileElement); } - boost::shared_ptr<XMLElement> featureElement(new XMLElement("feature", "http://jabber.org/protocol/feature-neg")); + boost::shared_ptr<XMLElement> featureElement(new XMLElement("feature", FEATURE_NEG_NS)); if (streamInitiation->getProvidedMethods().size() > 0) { Form::ref form(new Form(Form::FormType)); ListSingleFormField::ref field = ListSingleFormField::create(); diff --git a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h index 0b51519..76f0f45 100644 --- a/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h @@ -6,12 +6,10 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/StreamInitiation.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/StreamInitiation.h> namespace Swift { - class PayloadSerializerCollection; - class StreamInitiationSerializer : public GenericPayloadSerializer<StreamInitiation> { public: StreamInitiationSerializer(); diff --git a/Swiften/Serializer/PayloadSerializers/SubjectSerializer.h b/Swiften/Serializer/PayloadSerializers/SubjectSerializer.h index cf78ddd..fe82499 100644 --- a/Swiften/Serializer/PayloadSerializers/SubjectSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/SubjectSerializer.h @@ -6,9 +6,9 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Elements/Subject.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Elements/Subject.h> namespace Swift { class SubjectSerializer : public GenericPayloadSerializer<Subject> { diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp index 2604331..270d165 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/CapsInfoSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/CapsInfoSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp index 3875efd..32f5f49 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/DiscoInfoSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/DiscoInfoSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp index dd06244..27d4ac5 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ErrorSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/ErrorSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/ErrorSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp index e4a6661..29e7e59 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/FormSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/FormSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/FormSerializer.h> using namespace Swift; @@ -96,13 +96,6 @@ class FormSerializerTest : public CppUnit::TestFixture { field->setDescription("Tell all your friends about your new bot!"); form->addField(field); - std::vector<std::string> values2; - values2.push_back("foo"); - values2.push_back("bar"); - field = UntypedFormField::create(values2); - field->setName("fum"); - form->addField(field); - CPPUNIT_ASSERT_EQUAL(std::string( "<x type=\"form\" xmlns=\"jabber:x:data\">" "<field type=\"hidden\" var=\"FORM_TYPE\">" @@ -139,10 +132,6 @@ class FormSerializerTest : public CppUnit::TestFixture { "<value>foo@bar.com</value>" "<value>baz@fum.org</value>" "</field>" - "<field var=\"fum\">" - "<value>foo</value>" - "<value>bar</value>" - "</field>" "</x>"), testling.serialize(form)); } }; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp index 7020537..df43e69 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/InBandRegistrationPayloadSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/InBandRegistrationPayloadSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp new file mode 100644 index 0000000..e3ec8fc --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2011 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <boost/shared_ptr.hpp> +#include <boost/smart_ptr/make_shared.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationFileInfoSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/JingleIBBTransportPayload.h> +#include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/JingleFileTransferHash.h> +#include <Swiften/Elements/JinglePayload.h> +#include <Swiften/Elements/JingleFileTransferReceived.h> +#include <Swiften/Base/DateTime.h> + +using namespace Swift; + +class JingleSerializersTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(JingleSerializersTest); + CPPUNIT_TEST(testSerialize_StreamInitiationFileInfo); + CPPUNIT_TEST(testSerialize_StreamInitiationFileInfoRange); + + CPPUNIT_TEST(testSerialize_Xep0261_Example1); + CPPUNIT_TEST(testSerialize_Xep0261_Example9); + CPPUNIT_TEST(testSerialize_Xep0261_Example13); + + CPPUNIT_TEST(testSerialize_Xep0234_Example1); + CPPUNIT_TEST(testSerialize_Xep0234_Example3); + CPPUNIT_TEST(testSerialize_Xep0234_Example5); + CPPUNIT_TEST(testSerialize_Xep0234_Example8); + CPPUNIT_TEST(testSerialize_Xep0234_Example10); + CPPUNIT_TEST(testSerialize_Xep0234_Example13); + + CPPUNIT_TEST(testSerialize_Xep0260_Example1); + + CPPUNIT_TEST_SUITE_END(); + + boost::shared_ptr<JinglePayloadSerializer> createTestling() { + return boost::make_shared<JinglePayloadSerializer>(&collection); + } + + + public: + void testSerialize_StreamInitiationFileInfo() { + std::string expected = "<file" + " date=\"1969-07-21T02:56:15Z\"" + " hash=\"552da749930852c69ae5d2141d3766b1\"" + " name=\"test.txt\"" + " size=\"1022\"" + " xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">" + "<desc>This is a test. If this were a real file...</desc>" + "<range/>" + "</file>"; + + StreamInitiationFileInfo::ref fileInfo = boost::make_shared<StreamInitiationFileInfo>(); + fileInfo->setDate(stringToDateTime("1969-07-21T02:56:15Z")); + fileInfo->setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo->setSize(1022); + fileInfo->setName("test.txt"); + fileInfo->setDescription("This is a test. If this were a real file..."); + fileInfo->setSupportsRangeRequests(true); + + boost::shared_ptr<StreamInitiationFileInfoSerializer> serializer = boost::make_shared<StreamInitiationFileInfoSerializer>(); + CPPUNIT_ASSERT_EQUAL(expected, serializer->serializePayload(fileInfo)); + } + + void testSerialize_StreamInitiationFileInfoRange() { + std::string expected = "<file hash=\"552da749930852c69ae5d2141d3766b1\"" + " xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">" + "<range offset=\"270336\"/>" + "</file>"; + + StreamInitiationFileInfo::ref fileInfo = boost::make_shared<StreamInitiationFileInfo>(); + fileInfo->setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo->setSupportsRangeRequests(true); + fileInfo->setRangeOffset(270336); + + boost::shared_ptr<StreamInitiationFileInfoSerializer> serializer = boost::make_shared<StreamInitiationFileInfoSerializer>(); + CPPUNIT_ASSERT_EQUAL(expected, serializer->serializePayload(fileInfo)); + } + + + // IBB Transport Method Examples + + // http://xmpp.org/extensions/xep-0261.html#example-1 + void testSerialize_Xep0261_Example1() { + std::string expected = + "<jingle action=\"session-initiate\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<content creator=\"initiator\" name=\"ex\">" + "<transport block-size=\"4096\"" + " sid=\"ch3d9s71\"" + " xmlns=\"urn:xmpp:jingle:transports:ibb:1\"/>" + "</content>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionInitiate); + payload->setSessionID("a73sjjvkla37jfea"); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + + JingleIBBTransportPayload::ref transport = boost::make_shared<JingleIBBTransportPayload>(); + transport->setBlockSize(4096); + transport->setSessionID("ch3d9s71"); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("ex"); + content->addTransport(transport); + + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0261.html#example-9 + void testSerialize_Xep0261_Example9() { + std::string expected = + "<jingle action=\"transport-info\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<content creator=\"initiator\" name=\"ex\">" + "<transport block-size=\"2048\"" + " sid=\"bt8a71h6\"" + " xmlns=\"urn:xmpp:jingle:transports:ibb:1\"/>" + "</content>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::TransportInfo); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("a73sjjvkla37jfea"); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("ex"); + + JingleIBBTransportPayload::ref transport = boost::make_shared<JingleIBBTransportPayload>(); + transport->setBlockSize(2048); + transport->setSessionID("bt8a71h6"); + + content->addTransport(transport); + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0261.html#example-13 + void testSerialize_Xep0261_Example13() { + std::string expected = + "<jingle action=\"session-terminate\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<reason><success/></reason>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionTerminate); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("a73sjjvkla37jfea"); + payload->setReason(JinglePayload::Reason(JinglePayload::Reason::Success)); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0234.html#example-1 + void testSerialize_Xep0234_Example1() { + std::string expected = "<description xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">" + "<offer>" + "<file" + " date=\"1969-07-21T02:56:15Z\"" + " hash=\"552da749930852c69ae5d2141d3766b1\"" + " name=\"test.txt\"" + " size=\"1022\"" + " xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">" + "<desc>This is a test. If this were a real file...</desc>" + "<range/>" + "</file>" + "</offer>" + "</description>"; + JingleFileTransferDescription::ref desc = boost::make_shared<JingleFileTransferDescription>(); + StreamInitiationFileInfo fileInfo; + + fileInfo.setDate(stringToDateTime("1969-07-21T02:56:15Z")); + fileInfo.setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo.setSize(1022); + fileInfo.setName("test.txt"); + fileInfo.setDescription("This is a test. If this were a real file..."); + fileInfo.setSupportsRangeRequests(true); + + desc->addOffer(fileInfo); + + CPPUNIT_ASSERT_EQUAL(expected, boost::make_shared<JingleFileTransferDescriptionSerializer>()->serialize(desc)); + } + + // http://xmpp.org/extensions/xep-0234.html#example-3 + void testSerialize_Xep0234_Example3() { + std::string expected = + "<jingle action=\"session-accept\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"851ba2\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<content creator=\"initiator\" name=\"a-file-offer\">" + "<description xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">" + "<offer>" + "<file" + " date=\"1969-07-21T02:56:15Z\"" + " hash=\"552da749930852c69ae5d2141d3766b1\"" + " name=\"test.txt\"" + " size=\"1022\"" + " xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">" + "<desc>This is a test. If this were a real file...</desc>" + "<range/>" + "</file>" + "</offer>" + "</description>" + /*"<transport xmlns=\"urn:xmpp:jingle:transports:s5b:1\"" + " mode=\"tcp\"" + " sid=\"vj3hs98y\">" + "<candidate cid=\"ht567dq\"" + " host=\"192.169.1.10\"" + " jid=\"juliet@capulet.lit/balcony\"" + " port=\"6539\"" + " priority=\"8257636\"" + " type=\"direct\"/>" + "<candidate cid=\"hr65dqyd\"" + " host=\"134.102.201.180\"" + " jid=\"juliet@capulet.lit/balcony\"" + " port=\"16453\"" + " priority=\"7929856\"" + " type=\"assisted\"/>" + "<candidate cid=\"grt654q2\"" + " host=\"2001:638:708:30c9:219:d1ff:fea4:a17d\"" + " jid=\"juliet@capulet.lit/balcony\"" + " port=\"6539\"" + " priority=\"8257606\"" + " type=\"direct\"/>" + "</transport>"*/ + "</content>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionAccept); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("851ba2"); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("a-file-offer"); + + JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); + StreamInitiationFileInfo fileInfo; + fileInfo.setName("test.txt"); + fileInfo.setSize(1022); + fileInfo.setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo.setDate(stringToDateTime("1969-07-21T02:56:15Z")); + fileInfo.setDescription("This is a test. If this were a real file..."); + fileInfo.setSupportsRangeRequests(true); + + description->addOffer(fileInfo); + content->addDescription(description); + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0234.html#example-5 + void testSerialize_Xep0234_Example5() { + std::string expected = + "<jingle" + " action=\"transport-info\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<content creator=\"initiator\" name=\"ex\"/>" + /*"<transport" + " sid=\"vj3hs98y\"" + " xmlns=\"urn:xmpp:jingle:transports:s5b:1\">" + "<candidate-used cid=\"hr65dqyd\"/>" + "</transport>"*/ + //"</content>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::TransportInfo); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("a73sjjvkla37jfea"); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("ex"); + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0234.html#example-8 + void testSerialize_Xep0234_Example8() { + std::string expected = + "<jingle" + " action=\"session-info\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<checksum xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">" + "<file>" + "<hashes xmlns=\"urn:xmpp:hashes:0\">" + "<hash algo=\"sha-1\">552da749930852c69ae5d2141d3766b1</hash>" + "</hashes>" + "</file>" + "</checksum>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionInfo); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("a73sjjvkla37jfea"); + + JingleFileTransferHash::ref hash = boost::make_shared<JingleFileTransferHash>(); + hash->setHash("sha-1", "552da749930852c69ae5d2141d3766b1"); + + payload->addPayload(hash); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0234.html#example-10 + void testSerialize_Xep0234_Example10() { + std::string expected = + "<jingle" + " action=\"session-initiate\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"uj3b2\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<content creator=\"initiator\" name=\"a-file-request\">" + "<description" + " xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">" + "<request>" + "<file" + " hash=\"552da749930852c69ae5d2141d3766b1\"" + " xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\">" + "<range offset=\"270336\"/>" + "</file>" + "</request>" + "</description>" + /*"<transport" + " mode=\"tcp\"" + " sid=\"xig361fj\"" + " xmlns=\"urn:xmpp:jingle:transports:s5b:1\">" + "<candidate" + " cid=\"ht567dq\"" + " host=\"192.169.1.10\"" + " jid=\"juliet@capulet.lit/balcony\"" + " port=\"6539\"" + " priority=\"8257636\"" + " type=\"direct\"/>" + "<candidate" + " cid=\"hr65dqyd\"" + " host=\"134.102.201.180\"" + " jid=\"juliet@capulet.lit/balcony\"" + " port=\"16453\"" + " priority=\"7929856\"" + " type=\"assisted\"/>" + "<candidate" + " cid=\"grt654q2\"" + " host=\"2001:638:708:30c9:219:d1ff:fea4:a17d\"" + " jid=\"juliet@capulet.lit/balcony\"" + " port=\"6539\"" + " priority=\"8257606\"" + " type=\"direct\"/>" + "</transport>"*/ + "</content>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionInitiate); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("uj3b2"); + + StreamInitiationFileInfo fileInfo; + fileInfo.setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo.setRangeOffset(270336); + + JingleFileTransferDescription::ref desc = boost::make_shared<JingleFileTransferDescription>(); + desc->addRequest(fileInfo); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("a-file-request"); + content->addDescription(desc); + + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0234.html#example-10 + void testSerialize_Xep0234_Example13() { + std::string expected = + "<jingle" + " action=\"session-info\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<received xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">" + "<file" + " hash=\"a749930852c69ae5d2141d3766b1552d\"" + " xmlns=\"http://jabber.org/protocol/si/profile/file-transfer\"/>" + "</received>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionInfo); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("a73sjjvkla37jfea"); + + JingleFileTransferReceived::ref received = boost::make_shared<JingleFileTransferReceived>(); + + StreamInitiationFileInfo fileInfo; + fileInfo.setHash("a749930852c69ae5d2141d3766b1552d"); + + received->setFileInfo(fileInfo); + payload->addPayload(received); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + // http://xmpp.org/extensions/xep-0260.html#example-1 + void testSerialize_Xep0260_Example1() { + std::string expected = + "<jingle" + " action=\"session-initiate\"" + " initiator=\"romeo@montague.lit/orchard\"" + " sid=\"a73sjjvkla37jfea\"" + " xmlns=\"urn:xmpp:jingle:1\">" + "<content creator=\"initiator\" name=\"ex\">" + "<transport" + " mode=\"tcp\"" + " sid=\"vj3hs98y\"" + " xmlns=\"urn:xmpp:jingle:transports:s5b:1\">" + "<candidate cid=\"hft54dqy\"" + " host=\"192.168.4.1\"" + " jid=\"romeo@montague.lit/orchard\"" + " port=\"5086\"" + " priority=\"8257636\"" + " type=\"direct\"/>" + "<candidate cid=\"hutr46fe\"" + " host=\"24.24.24.1\"" + " jid=\"romeo@montague.lit/orchard\"" + " port=\"5087\"" + " priority=\"8258636\"" + " type=\"direct\"/>" + "</transport>" + "</content>" + "</jingle>"; + + JinglePayload::ref payload = boost::make_shared<JinglePayload>(); + payload->setAction(JinglePayload::SessionInitiate); + payload->setInitiator(JID("romeo@montague.lit/orchard")); + payload->setSessionID("a73sjjvkla37jfea"); + + JingleContentPayload::ref content = boost::make_shared<JingleContentPayload>(); + content->setCreator(JingleContentPayload::InitiatorCreator); + content->setName("ex"); + + JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); + transport->setMode(JingleS5BTransportPayload::TCPMode); + transport->setSessionID("vj3hs98y"); + + JingleS5BTransportPayload::Candidate candidate1; + candidate1.cid = "hft54dqy"; + candidate1.hostPort = HostAddressPort(HostAddress("192.168.4.1"), 5086); + candidate1.jid = JID("romeo@montague.lit/orchard"); + candidate1.priority = 8257636; + candidate1.type = JingleS5BTransportPayload::Candidate::DirectType; + transport->addCandidate(candidate1); + + JingleS5BTransportPayload::Candidate candidate2; + candidate2.cid = "hutr46fe"; + candidate2.hostPort = HostAddressPort(HostAddress("24.24.24.1"), 5087); + candidate2.jid = JID("romeo@montague.lit/orchard"); + candidate2.priority = 8258636; + candidate2.type = JingleS5BTransportPayload::Candidate::DirectType; + transport->addCandidate(candidate2); + + content->addTransport(transport); + + payload->addPayload(content); + + CPPUNIT_ASSERT_EQUAL(expected, createTestling()->serialize(payload)); + } + + private: + FullPayloadSerializerCollection collection; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(JingleSerializersTest); + diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp new file mode 100644 index 0000000..a8acf80 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/MUCAdminPayloadSerializerTest.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/PayloadSerializers/MUCAdminPayloadSerializer.h> + +using namespace Swift; + +class MUCAdminPayloadSerializerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(MUCAdminPayloadSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + MUCAdminPayloadSerializerTest() {} + + void testSerialize() { + MUCAdminPayloadSerializer testling; + boost::shared_ptr<MUCAdminPayload> admin = boost::make_shared<MUCAdminPayload>(); + MUCItem item; + item.affiliation = MUCOccupant::Owner; + item.role = MUCOccupant::Visitor; + item.reason = "malice"; + item.actor = JID("kev@tester.lit"); + admin->addItem(item); + + CPPUNIT_ASSERT_EQUAL(std::string("<query xmlns=\"http://jabber.org/protocol/muc#admin\"><item affiliation=\"owner\" role=\"visitor\"><actor jid=\"kev@tester.lit\"/><reason>malice</reason></item></query>"), testling.serialize(admin)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(MUCAdminPayloadSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp index 481d9c2..9eed97e 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.cpp @@ -4,11 +4,11 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h> #include <cppunit/extensions/HelperMacros.h> -#include "Swiften/Serializer/PayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializer.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h b/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h index 038b616..01f07e4 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h @@ -8,9 +8,9 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Payload.h" +#include <Swiften/Elements/Payload.h> #include <string> -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> namespace Swift { class PayloadsSerializer { diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp index c976b12..f5b8bee 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/PrioritySerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/PrioritySerializer.h" +#include <Swiften/Serializer/PayloadSerializers/PrioritySerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp index b0f4084..23d71aa 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/PrivateStorageSerializerTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h" -#include "Swiften/Elements/PrivateStorage.h" -#include "Swiften/Elements/Storage.h" +#include <Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h> +#include <Swiften/Elements/PrivateStorage.h> +#include <Swiften/Elements/Storage.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp new file mode 100644 index 0000000..3d054cc --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ReplaceSerializerTest.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 Vlad Voicu + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Serializer/PayloadSerializers/ReplaceSerializer.h> + +using namespace Swift; + +class ReplaceSerializerTest: public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ReplaceSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + ReplaceSerializerTest() {} + + void testSerialize() { + ReplaceSerializer testling; + boost::shared_ptr<Replace> replace(new Replace()); + replace->setID("bad1"); + CPPUNIT_ASSERT_EQUAL(std::string("<replace id = 'bad1' xmlns='http://swift.im/protocol/replace'/>"), testling.serialize(replace)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(ReplaceSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp index c7872fe..f8d3d30 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/ResourceBindSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/ResourceBindSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp new file mode 100644 index 0000000..b6a90d9 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterItemExchangeSerializerTest.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Serializer/PayloadSerializers/RosterItemExchangeSerializer.h> + +using namespace Swift; + +class RosterItemExchangeSerializerTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(RosterItemExchangeSerializerTest); + CPPUNIT_TEST(testSerialize); + CPPUNIT_TEST_SUITE_END(); + + public: + RosterItemExchangeSerializerTest() {} + + void testSerialize() { + RosterItemExchangeSerializer testling; + boost::shared_ptr<RosterItemExchangePayload> roster(new RosterItemExchangePayload()); + + RosterItemExchangePayload::Item item1; + item1.setJID("foo@bar.com"); + item1.setName("Foo @ Bar"); + item1.setAction(RosterItemExchangePayload::Item::Add); + item1.addGroup("Group 1"); + item1.addGroup("Group 2"); + roster->addItem(item1); + + RosterItemExchangePayload::Item item2; + item2.setJID("baz@blo.com"); + item2.setName("Baz"); + item2.setAction(RosterItemExchangePayload::Item::Modify); + roster->addItem(item2); + + std::string expectedResult = + "<x xmlns=\"http://jabber.org/protocol/rosterx\">" + "<item action=\"add\" jid=\"foo@bar.com\" name=\"Foo @ Bar\">" + "<group>Group 1</group>" + "<group>Group 2</group>" + "</item>" + "<item action=\"modify\" jid=\"baz@blo.com\" name=\"Baz\"/>" + "</x>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RosterItemExchangeSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp index b8ceac3..9ecddc3 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/RosterSerializerTest.cpp @@ -7,20 +7,19 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/RosterSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/RosterSerializer.h> using namespace Swift; -class RosterSerializerTest : public CppUnit::TestFixture -{ +class RosterSerializerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(RosterSerializerTest); CPPUNIT_TEST(testSerialize); CPPUNIT_TEST(testSerialize_ItemWithUnknownContent); + CPPUNIT_TEST(testSerialize_WithVersion); + CPPUNIT_TEST(testSerialize_WithEmptyVersion); CPPUNIT_TEST_SUITE_END(); public: - RosterSerializerTest() {} - void testSerialize() { RosterSerializer testling; boost::shared_ptr<RosterPayload> roster(new RosterPayload()); @@ -77,6 +76,26 @@ class RosterSerializerTest : public CppUnit::TestFixture CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); } + + void testSerialize_WithVersion() { + RosterSerializer testling; + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion("ver20"); + + std::string expectedResult = "<query ver=\"ver20\" xmlns=\"jabber:iq:roster\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } + + void testSerialize_WithEmptyVersion() { + RosterSerializer testling; + boost::shared_ptr<RosterPayload> roster(new RosterPayload()); + roster->setVersion(""); + + std::string expectedResult = "<query ver=\"\" xmlns=\"jabber:iq:roster\"/>"; + + CPPUNIT_ASSERT_EQUAL(expectedResult, testling.serialize(roster)); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(RosterSerializerTest); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp index e8328b8..d0dcbef 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SearchPayloadSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SearchPayloadSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp index 03bad89..0de509d 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp index a7bf1b9..c060e41 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SecurityLabelsCatalogSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SecurityLabelsCatalogSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/SoftwareVersionSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/SoftwareVersionSerializerTest.cpp index 6fac094..ad1e9b4 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/SoftwareVersionSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/SoftwareVersionSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/SoftwareVersionSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/StatusSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/StatusSerializerTest.cpp index c0b1dc2..af90a0a 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/StatusSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/StatusSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/StatusSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/StatusSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/StatusShowSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/StatusShowSerializerTest.cpp index 2fee152..898c835 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/StatusShowSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/StatusShowSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/StatusShowSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp index 01899a9..b963a9c 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/StorageSerializerTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h" -#include "Swiften/Elements/Storage.h" +#include <Swiften/Serializer/PayloadSerializers/UnitTest/PayloadsSerializer.h> +#include <Swiften/Elements/Storage.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/StreamInitiationSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/StreamInitiationSerializerTest.cpp index d05fdba..7b96298 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/StreamInitiationSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/StreamInitiationSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/StreamInitiationSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp index 8a9a615..3ac1d77 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/VCardSerializer.h> using namespace Swift; @@ -29,7 +29,7 @@ class VCardSerializerTest : public CppUnit::TestFixture vcard->setFamilyName("Wonderland"); vcard->setSuffix("PhD"); vcard->setNickname("DreamGirl"); - vcard->setPhoto("abcdef"); + vcard->setPhoto(createByteArray("abcdef")); vcard->setPhotoType("image/png"); vcard->addUnknownContent("<BDAY>1234</BDAY><MAILER>mutt</MAILER>"); diff --git a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardUpdateSerializerTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardUpdateSerializerTest.cpp index 6f37d61..613b465 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/VCardUpdateSerializerTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/VCardUpdateSerializerTest.cpp @@ -7,7 +7,7 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h> using namespace Swift; diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp index 79e543e..17a6b49 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.cpp @@ -4,15 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/VCardSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/VCardSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/StringCodecs/Base64.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/foreach.h> namespace Swift { @@ -87,14 +87,14 @@ std::string VCardSerializer::serializePayload(boost::shared_ptr<VCard> vcard) c nickElement->addNode(boost::shared_ptr<XMLTextNode>(new XMLTextNode(vcard->getNickname()))); queryElement.addNode(nickElement); } - if (!vcard->getPhoto().isEmpty() || !vcard->getPhotoType().empty()) { + if (!vcard->getPhoto().empty() || !vcard->getPhotoType().empty()) { XMLElement::ref photoElement(new XMLElement("PHOTO")); if (!vcard->getPhotoType().empty()) { XMLElement::ref typeElement(new XMLElement("TYPE")); typeElement->addNode(XMLTextNode::ref(new XMLTextNode(vcard->getPhotoType()))); photoElement->addNode(typeElement); } - if (!vcard->getPhoto().isEmpty()) { + if (!vcard->getPhoto().empty()) { XMLElement::ref binvalElement(new XMLElement("BINVAL")); binvalElement->addNode(XMLTextNode::ref(new XMLTextNode(Base64::encode(vcard->getPhoto())))); photoElement->addNode(binvalElement); diff --git a/Swiften/Serializer/PayloadSerializers/VCardSerializer.h b/Swiften/Serializer/PayloadSerializers/VCardSerializer.h index 7b9a8a9..c73ff18 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/VCardSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/VCard.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/VCard.h> namespace Swift { class VCardSerializer : public GenericPayloadSerializer<VCard> { diff --git a/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.cpp b/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.cpp index e315bc3..c06262f 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h" +#include <Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> namespace Swift { diff --git a/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h b/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h index 46ca154..68084f0 100644 --- a/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h +++ b/Swiften/Serializer/PayloadSerializers/VCardUpdateSerializer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Serializer/GenericPayloadSerializer.h" -#include "Swiften/Elements/VCardUpdate.h" +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/VCardUpdate.h> namespace Swift { class VCardUpdateSerializer : public GenericPayloadSerializer<VCardUpdate> { diff --git a/Swiften/Serializer/PresenceSerializer.cpp b/Swiften/Serializer/PresenceSerializer.cpp index 0de6493..20eda4b 100644 --- a/Swiften/Serializer/PresenceSerializer.cpp +++ b/Swiften/Serializer/PresenceSerializer.cpp @@ -4,10 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/PresenceSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/PresenceSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> -#include "boost/shared_ptr.hpp" +#include <boost/shared_ptr.hpp> namespace Swift { diff --git a/Swiften/Serializer/PresenceSerializer.h b/Swiften/Serializer/PresenceSerializer.h index 3cb9aab..e5d9f30 100644 --- a/Swiften/Serializer/PresenceSerializer.h +++ b/Swiften/Serializer/PresenceSerializer.h @@ -4,13 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PresenceSerializer_H -#define SWIFTEN_PresenceSerializer_H +#pragma once -#include <cassert> - -#include "Swiften/Serializer/GenericStanzaSerializer.h" -#include "Swiften/Elements/Presence.h" +#include <Swiften/Serializer/GenericStanzaSerializer.h> +#include <Swiften/Elements/Presence.h> namespace Swift { class PresenceSerializer : public GenericStanzaSerializer<Presence> { @@ -23,5 +20,3 @@ namespace Swift { XMLElement& element) const; }; } - -#endif diff --git a/Swiften/Serializer/StanzaAckRequestSerializer.h b/Swiften/Serializer/StanzaAckRequestSerializer.h index b03a2c2..fff2a83 100644 --- a/Swiften/Serializer/StanzaAckRequestSerializer.h +++ b/Swiften/Serializer/StanzaAckRequestSerializer.h @@ -8,9 +8,9 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/StanzaAckRequest.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/StanzaAckRequest.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class StanzaAckRequestSerializer : public GenericElementSerializer<StanzaAckRequest> { @@ -18,8 +18,8 @@ namespace Swift { StanzaAckRequestSerializer() : GenericElementSerializer<StanzaAckRequest>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("r", "urn:xmpp:sm:2").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("r", "urn:xmpp:sm:2").serialize()); } }; } diff --git a/Swiften/Serializer/StanzaAckSerializer.h b/Swiften/Serializer/StanzaAckSerializer.h index 984509f..ea1e8ad 100644 --- a/Swiften/Serializer/StanzaAckSerializer.h +++ b/Swiften/Serializer/StanzaAckSerializer.h @@ -9,9 +9,9 @@ #include <boost/shared_ptr.hpp> #include <boost/lexical_cast.hpp> -#include "Swiften/Elements/StanzaAck.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/StanzaAck.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class StanzaAckSerializer : public GenericElementSerializer<StanzaAck> { @@ -19,12 +19,12 @@ namespace Swift { StanzaAckSerializer() : GenericElementSerializer<StanzaAck>() { } - virtual std::string serialize(boost::shared_ptr<Element> element) const { + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const { StanzaAck::ref stanzaAck(boost::dynamic_pointer_cast<StanzaAck>(element)); assert(stanzaAck->isValid()); XMLElement result("a", "urn:xmpp:sm:2"); result.setAttribute("h", std::string(boost::lexical_cast<std::string>(stanzaAck->getHandledStanzasCount()))); - return result.serialize(); + return createSafeByteArray(result.serialize()); } }; } diff --git a/Swiften/Serializer/StanzaSerializer.cpp b/Swiften/Serializer/StanzaSerializer.cpp index cfc9a43..9a4fd2c 100644 --- a/Swiften/Serializer/StanzaSerializer.cpp +++ b/Swiften/Serializer/StanzaSerializer.cpp @@ -4,24 +4,25 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/StanzaSerializer.h" +#include <Swiften/Serializer/StanzaSerializer.h> #include <sstream> #include <typeinfo> #include <iostream> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLRawTextNode.h" -#include "Swiften/Serializer/PayloadSerializer.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/Elements/Stanza.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLRawTextNode.h> +#include <Swiften/Serializer/PayloadSerializer.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Elements/Stanza.h> namespace Swift { StanzaSerializer::StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers) : tag_(tag), payloadSerializers_(payloadSerializers) { } -std::string StanzaSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray StanzaSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<Stanza> stanza(boost::dynamic_pointer_cast<Stanza>(element)); XMLElement stanzaElement(tag_); @@ -50,7 +51,7 @@ std::string StanzaSerializer::serialize(boost::shared_ptr<Element> element) cons stanzaElement.addNode(boost::shared_ptr<XMLNode>(new XMLRawTextNode(serializedPayloads))); } - return stanzaElement.serialize(); + return createSafeByteArray(stanzaElement.serialize()); } } diff --git a/Swiften/Serializer/StanzaSerializer.h b/Swiften/Serializer/StanzaSerializer.h index 505d320..db18aa2 100644 --- a/Swiften/Serializer/StanzaSerializer.h +++ b/Swiften/Serializer/StanzaSerializer.h @@ -4,11 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_STANZASERIALIZER_H -#define SWIFTEN_STANZASERIALIZER_H +#pragma once -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Serializer/ElementSerializer.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Serializer/ElementSerializer.h> #include <string> namespace Swift { @@ -19,7 +18,7 @@ namespace Swift { public: StanzaSerializer(const std::string& tag, PayloadSerializerCollection* payloadSerializers); - virtual std::string serialize(boost::shared_ptr<Element>) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; virtual void setStanzaSpecificAttributes(boost::shared_ptr<Element>, XMLElement&) const = 0; private: @@ -27,5 +26,3 @@ namespace Swift { PayloadSerializerCollection* payloadSerializers_; }; } - -#endif diff --git a/Swiften/Serializer/StartTLSFailureSerializer.h b/Swiften/Serializer/StartTLSFailureSerializer.h index 548a24c..779be92 100644 --- a/Swiften/Serializer/StartTLSFailureSerializer.h +++ b/Swiften/Serializer/StartTLSFailureSerializer.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartTLSFailureSerializer_H -#define SWIFTEN_StartTLSFailureSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/StartTLSFailure.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/StartTLSFailure.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class StartTLSFailureSerializer : public GenericElementSerializer<StartTLSFailure> { @@ -19,10 +18,8 @@ namespace Swift { StartTLSFailureSerializer() : GenericElementSerializer<StartTLSFailure>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("failure", "urn:ietf:params:xml:ns:xmpp-tls").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("failure", "urn:ietf:params:xml:ns:xmpp-tls").serialize()); } }; } - -#endif diff --git a/Swiften/Serializer/StartTLSRequestSerializer.h b/Swiften/Serializer/StartTLSRequestSerializer.h index 2e9ecfa..df914ce 100644 --- a/Swiften/Serializer/StartTLSRequestSerializer.h +++ b/Swiften/Serializer/StartTLSRequestSerializer.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StartTLSRequestSerializer_H -#define SWIFTEN_StartTLSRequestSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/StartTLSRequest.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/StartTLSRequest.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class StartTLSRequestSerializer : public GenericElementSerializer<StartTLSRequest> { @@ -19,10 +18,8 @@ namespace Swift { StartTLSRequestSerializer() : GenericElementSerializer<StartTLSRequest>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("starttls", "urn:ietf:params:xml:ns:xmpp-tls").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("starttls", "urn:ietf:params:xml:ns:xmpp-tls").serialize()); } }; } - -#endif diff --git a/Swiften/Serializer/StreamErrorSerializer.cpp b/Swiften/Serializer/StreamErrorSerializer.cpp index 11f8a30..b3d62a0 100644 --- a/Swiften/Serializer/StreamErrorSerializer.cpp +++ b/Swiften/Serializer/StreamErrorSerializer.cpp @@ -15,7 +15,7 @@ namespace Swift { StreamErrorSerializer::StreamErrorSerializer() : GenericElementSerializer<StreamError>() { } -std::string StreamErrorSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray StreamErrorSerializer::serialize(boost::shared_ptr<Element> element) const { StreamError::ref error = boost::dynamic_pointer_cast<StreamError>(element); XMLElement errorElement("error", "http://etherx.jabber.org/streams"); @@ -53,7 +53,7 @@ std::string StreamErrorSerializer::serialize(boost::shared_ptr<Element> element) errorElement.addNode(boost::make_shared<XMLElement>("text", "urn:ietf:params:xml:ns:xmpp-streams", error->getText())); } - return errorElement.serialize(); + return createSafeByteArray(errorElement.serialize()); } } diff --git a/Swiften/Serializer/StreamErrorSerializer.h b/Swiften/Serializer/StreamErrorSerializer.h index 9d4f60c..bdaa831 100644 --- a/Swiften/Serializer/StreamErrorSerializer.h +++ b/Swiften/Serializer/StreamErrorSerializer.h @@ -14,6 +14,6 @@ namespace Swift { public: StreamErrorSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> error) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> error) const; }; } diff --git a/Swiften/Serializer/StreamFeaturesSerializer.cpp b/Swiften/Serializer/StreamFeaturesSerializer.cpp index 915433c..fb7bb8c 100644 --- a/Swiften/Serializer/StreamFeaturesSerializer.cpp +++ b/Swiften/Serializer/StreamFeaturesSerializer.cpp @@ -4,18 +4,20 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/StreamFeaturesSerializer.h" +#include <Swiften/Serializer/StreamFeaturesSerializer.h> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" -#include "Swiften/Base/foreach.h" +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> +#include <Swiften/Base/foreach.h> namespace Swift { StreamFeaturesSerializer::StreamFeaturesSerializer() { } -std::string StreamFeaturesSerializer::serialize(boost::shared_ptr<Element> element) const { +SafeByteArray StreamFeaturesSerializer::serialize(boost::shared_ptr<Element> element) const { boost::shared_ptr<StreamFeatures> streamFeatures(boost::dynamic_pointer_cast<StreamFeatures>(element)); XMLElement streamFeaturesElement("stream:features"); @@ -49,7 +51,10 @@ std::string StreamFeaturesSerializer::serialize(boost::shared_ptr<Element> eleme if (streamFeatures->hasStreamManagement()) { streamFeaturesElement.addNode(boost::shared_ptr<XMLElement>(new XMLElement("sm", "urn:xmpp:sm:2"))); } - return streamFeaturesElement.serialize(); + if (streamFeatures->hasRosterVersioning()) { + streamFeaturesElement.addNode(boost::make_shared<XMLElement>("ver", "urn:xmpp:features:rosterver")); + } + return createSafeByteArray(streamFeaturesElement.serialize()); } } diff --git a/Swiften/Serializer/StreamFeaturesSerializer.h b/Swiften/Serializer/StreamFeaturesSerializer.h index 3b475e0..5ea3ab1 100644 --- a/Swiften/Serializer/StreamFeaturesSerializer.h +++ b/Swiften/Serializer/StreamFeaturesSerializer.h @@ -4,21 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_StreamFeaturesSerializer_H -#define SWIFTEN_StreamFeaturesSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/StreamFeatures.h" -#include "Swiften/Serializer/GenericElementSerializer.h" +#include <Swiften/Elements/StreamFeatures.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class StreamFeaturesSerializer : public GenericElementSerializer<StreamFeatures> { public: StreamFeaturesSerializer(); - virtual std::string serialize(boost::shared_ptr<Element> element) const; + virtual SafeByteArray serialize(boost::shared_ptr<Element> element) const; }; } - -#endif diff --git a/Swiften/Serializer/StreamManagementEnabledSerializer.cpp b/Swiften/Serializer/StreamManagementEnabledSerializer.cpp new file mode 100644 index 0000000..b559721 --- /dev/null +++ b/Swiften/Serializer/StreamManagementEnabledSerializer.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/StreamManagementEnabledSerializer.h> + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/StreamManagementEnabled.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +StreamManagementEnabledSerializer::StreamManagementEnabledSerializer() : GenericElementSerializer<StreamManagementEnabled>() { +} + +SafeByteArray StreamManagementEnabledSerializer::serialize(boost::shared_ptr<Element> el) const { + boost::shared_ptr<StreamManagementEnabled> e(boost::dynamic_pointer_cast<StreamManagementEnabled>(el)); + XMLElement element("enabled", "urn:xmpp:sm:2"); + if (!e->getResumeID().empty()) { + element.setAttribute("id", e->getResumeID()); + } + if (e->getResumeSupported()) { + element.setAttribute("resume", "true"); + } + return createSafeByteArray(element.serialize()); +} diff --git a/Swiften/Serializer/StreamManagementEnabledSerializer.h b/Swiften/Serializer/StreamManagementEnabledSerializer.h index fc7bd86..5f28a2b 100644 --- a/Swiften/Serializer/StreamManagementEnabledSerializer.h +++ b/Swiften/Serializer/StreamManagementEnabledSerializer.h @@ -8,18 +8,14 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/StreamManagementEnabled.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/StreamManagementEnabled.h> +#include <Swiften/Serializer/GenericElementSerializer.h> namespace Swift { class StreamManagementEnabledSerializer : public GenericElementSerializer<StreamManagementEnabled> { public: - StreamManagementEnabledSerializer() : GenericElementSerializer<StreamManagementEnabled>() { - } + StreamManagementEnabledSerializer(); - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("enabled", "urn:xmpp:sm:2").serialize(); - } + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; }; } diff --git a/Swiften/Serializer/StreamManagementFailedSerializer.h b/Swiften/Serializer/StreamManagementFailedSerializer.h index b22ed0d..f3dcce0 100644 --- a/Swiften/Serializer/StreamManagementFailedSerializer.h +++ b/Swiften/Serializer/StreamManagementFailedSerializer.h @@ -8,9 +8,9 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/StreamManagementFailed.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/StreamManagementFailed.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class StreamManagementFailedSerializer : public GenericElementSerializer<StreamManagementFailed> { @@ -18,8 +18,8 @@ namespace Swift { StreamManagementFailedSerializer() : GenericElementSerializer<StreamManagementFailed>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("failed", "urn:xmpp:sm:2").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("failed", "urn:xmpp:sm:2").serialize()); } }; } diff --git a/Swiften/Serializer/StreamResumeSerializer.cpp b/Swiften/Serializer/StreamResumeSerializer.cpp new file mode 100644 index 0000000..e9e520d --- /dev/null +++ b/Swiften/Serializer/StreamResumeSerializer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/StreamResumeSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Elements/StreamResume.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +StreamResumeSerializer::StreamResumeSerializer() : GenericElementSerializer<StreamResume>() { +} + +SafeByteArray StreamResumeSerializer::serialize(boost::shared_ptr<Element> el) const { + boost::shared_ptr<StreamResume> e(boost::dynamic_pointer_cast<StreamResume>(el)); + XMLElement element("resume", "urn:xmpp:sm:2"); + element.setAttribute("previd", e->getResumeID()); + if (e->getHandledStanzasCount()) { + element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount())); + } + return createSafeByteArray(element.serialize()); +} diff --git a/Swiften/Serializer/StreamResumeSerializer.h b/Swiften/Serializer/StreamResumeSerializer.h new file mode 100644 index 0000000..501d8b6 --- /dev/null +++ b/Swiften/Serializer/StreamResumeSerializer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/StreamResume.h> +#include <Swiften/Serializer/GenericElementSerializer.h> + +namespace Swift { + class StreamResumeSerializer : public GenericElementSerializer<StreamResume> { + public: + StreamResumeSerializer(); + + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; + }; +} diff --git a/Swiften/Serializer/StreamResumedSerializer.cpp b/Swiften/Serializer/StreamResumedSerializer.cpp new file mode 100644 index 0000000..7ae82d1 --- /dev/null +++ b/Swiften/Serializer/StreamResumedSerializer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Serializer/StreamResumedSerializer.h> + +#include <boost/shared_ptr.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Elements/StreamResumed.h> +#include <Swiften/Serializer/XML/XMLElement.h> + +using namespace Swift; + +StreamResumedSerializer::StreamResumedSerializer() : GenericElementSerializer<StreamResumed>() { +} + +SafeByteArray StreamResumedSerializer::serialize(boost::shared_ptr<Element> el) const { + boost::shared_ptr<StreamResumed> e(boost::dynamic_pointer_cast<StreamResumed>(el)); + XMLElement element("resumed", "urn:xmpp:sm:2"); + element.setAttribute("previd", e->getResumeID()); + if (e->getHandledStanzasCount()) { + element.setAttribute("h", boost::lexical_cast<std::string>(e->getHandledStanzasCount())); + } + return createSafeByteArray(element.serialize()); +} diff --git a/Swiften/Serializer/StreamResumedSerializer.h b/Swiften/Serializer/StreamResumedSerializer.h new file mode 100644 index 0000000..7828694 --- /dev/null +++ b/Swiften/Serializer/StreamResumedSerializer.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/shared_ptr.hpp> + +#include <Swiften/Elements/StreamResumed.h> +#include <Swiften/Serializer/GenericElementSerializer.h> + +namespace Swift { + class StreamResumedSerializer : public GenericElementSerializer<StreamResumed> { + public: + StreamResumedSerializer(); + + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const; + }; +} diff --git a/Swiften/Serializer/TLSProceedSerializer.h b/Swiften/Serializer/TLSProceedSerializer.h index 1b08c23..21a8420 100644 --- a/Swiften/Serializer/TLSProceedSerializer.h +++ b/Swiften/Serializer/TLSProceedSerializer.h @@ -4,14 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_TLSProceedSerializer_H -#define SWIFTEN_TLSProceedSerializer_H +#pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/TLSProceed.h" -#include "Swiften/Serializer/GenericElementSerializer.h" -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Elements/TLSProceed.h> +#include <Swiften/Serializer/GenericElementSerializer.h> +#include <Swiften/Serializer/XML/XMLElement.h> namespace Swift { class TLSProceedSerializer : public GenericElementSerializer<TLSProceed> { @@ -19,10 +18,8 @@ namespace Swift { TLSProceedSerializer() : GenericElementSerializer<TLSProceed>() { } - virtual std::string serialize(boost::shared_ptr<Element>) const { - return XMLElement("proceed", "urn:ietf:params:xml:ns:xmpp-tls").serialize(); + virtual SafeByteArray serialize(boost::shared_ptr<Element>) const { + return createSafeByteArray(XMLElement("proceed", "urn:ietf:params:xml:ns:xmpp-tls").serialize()); } }; } - -#endif diff --git a/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp index af857ef..5fb0a4e 100644 --- a/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/AuthChallengeSerializerTest.cpp @@ -3,12 +3,14 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/AuthChallengeSerializer.h" -#include "Swiften/Elements/AuthChallenge.h" +#include <Swiften/Serializer/AuthChallengeSerializer.h> +#include <Swiften/Elements/AuthChallenge.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -23,9 +25,9 @@ class AuthChallengeSerializerTest : public CppUnit::TestFixture { void testSerialize() { AuthChallengeSerializer testling; boost::shared_ptr<AuthChallenge> authChallenge(new AuthChallenge()); - authChallenge->setValue("foo"); + authChallenge->setValue(createByteArray("foo")); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "Zm9v" "</challenge>"), testling.serialize(authChallenge)); @@ -35,7 +37,7 @@ class AuthChallengeSerializerTest : public CppUnit::TestFixture { AuthChallengeSerializer testling; boost::shared_ptr<AuthChallenge> authChallenge(new AuthChallenge()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "</challenge>"), testling.serialize(authChallenge)); } @@ -43,9 +45,9 @@ class AuthChallengeSerializerTest : public CppUnit::TestFixture { void testSerialize_EmptyMessage() { AuthChallengeSerializer testling; boost::shared_ptr<AuthChallenge> authChallenge(new AuthChallenge()); - authChallenge->setValue(ByteArray()); + authChallenge->setValue(std::vector<unsigned char>()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<challenge xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "=" "</challenge>"), testling.serialize(authChallenge)); diff --git a/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp index 9f9f2fa..db36de7 100644 --- a/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/AuthRequestSerializerTest.cpp @@ -3,12 +3,14 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/AuthRequestSerializer.h" -#include "Swiften/Elements/AuthRequest.h" +#include <Swiften/Serializer/AuthRequestSerializer.h> +#include <Swiften/Elements/AuthRequest.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -23,9 +25,9 @@ class AuthRequestSerializerTest : public CppUnit::TestFixture { void testSerialize() { AuthRequestSerializer testling; boost::shared_ptr<AuthRequest> authRequest(new AuthRequest("PLAIN")); - authRequest->setMessage("foo"); + authRequest->setMessage(createSafeByteArray("foo")); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">" "Zm9v" "</auth>"), testling.serialize(authRequest)); @@ -35,7 +37,7 @@ class AuthRequestSerializerTest : public CppUnit::TestFixture { AuthRequestSerializer testling; boost::shared_ptr<AuthRequest> authRequest(new AuthRequest("PLAIN")); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">" "</auth>"), testling.serialize(authRequest)); } @@ -43,9 +45,9 @@ class AuthRequestSerializerTest : public CppUnit::TestFixture { void testSerialize_EmptyMessage() { AuthRequestSerializer testling; boost::shared_ptr<AuthRequest> authRequest(new AuthRequest("PLAIN")); - authRequest->setMessage(ByteArray()); + authRequest->setMessage(SafeByteArray()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"PLAIN\">" "=" "</auth>"), testling.serialize(authRequest)); diff --git a/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp index c93810c..4b846d7 100644 --- a/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/AuthResponseSerializerTest.cpp @@ -3,12 +3,14 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/AuthResponseSerializer.h" -#include "Swiften/Elements/AuthResponse.h" +#include <Swiften/Serializer/AuthResponseSerializer.h> +#include <Swiften/Elements/AuthResponse.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -23,9 +25,9 @@ class AuthResponseSerializerTest : public CppUnit::TestFixture { void testSerialize() { AuthResponseSerializer testling; boost::shared_ptr<AuthResponse> authResponse(new AuthResponse()); - authResponse->setValue("foo"); + authResponse->setValue(createSafeByteArray("foo")); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "Zm9v" "</response>"), testling.serialize(authResponse)); @@ -35,7 +37,7 @@ class AuthResponseSerializerTest : public CppUnit::TestFixture { AuthResponseSerializer testling; boost::shared_ptr<AuthResponse> authResponse(new AuthResponse()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "</response>"), testling.serialize(authResponse)); } @@ -43,9 +45,9 @@ class AuthResponseSerializerTest : public CppUnit::TestFixture { void testSerialize_EmptyMessage() { AuthResponseSerializer testling; boost::shared_ptr<AuthResponse> authResponse(new AuthResponse()); - authResponse->setValue(ByteArray()); + authResponse->setValue(SafeByteArray()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<response xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "=" "</response>"), testling.serialize(authResponse)); diff --git a/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp b/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp index 385c1e5..86e01f5 100644 --- a/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/AuthSuccessSerializerTest.cpp @@ -3,12 +3,14 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/AuthSuccessSerializer.h" -#include "Swiften/Elements/AuthSuccess.h" +#include <Swiften/Serializer/AuthSuccessSerializer.h> +#include <Swiften/Elements/AuthSuccess.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -23,9 +25,9 @@ class AuthSuccessSerializerTest : public CppUnit::TestFixture { void testSerialize() { AuthSuccessSerializer testling; boost::shared_ptr<AuthSuccess> authSuccess(new AuthSuccess()); - authSuccess->setValue("foo"); + authSuccess->setValue(createByteArray("foo")); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "Zm9v" "</success>"), testling.serialize(authSuccess)); @@ -35,7 +37,7 @@ class AuthSuccessSerializerTest : public CppUnit::TestFixture { AuthSuccessSerializer testling; boost::shared_ptr<AuthSuccess> authSuccess(new AuthSuccess()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "</success>"), testling.serialize(authSuccess)); } @@ -43,9 +45,9 @@ class AuthSuccessSerializerTest : public CppUnit::TestFixture { void testSerialize_EmptyMessage() { AuthSuccessSerializer testling; boost::shared_ptr<AuthSuccess> authSuccess(new AuthSuccess()); - authSuccess->setValue(ByteArray()); + authSuccess->setValue(std::vector<unsigned char>()); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<success xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\">" "=" "</success>"), testling.serialize(authSuccess)); diff --git a/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp b/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp index 65caa81..0abb32c 100644 --- a/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/StreamFeaturesSerializerTest.cpp @@ -3,12 +3,14 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/StreamFeaturesSerializer.h" -#include "Swiften/Elements/StreamFeatures.h" +#include <Swiften/Serializer/StreamFeaturesSerializer.h> +#include <Swiften/Elements/StreamFeatures.h> + using namespace Swift; @@ -32,8 +34,9 @@ class StreamFeaturesSerializerTest : public CppUnit::TestFixture streamFeatures->setHasResourceBind(); streamFeatures->setHasSession(); streamFeatures->setHasStreamManagement(); + streamFeatures->setHasRosterVersioning(); - CPPUNIT_ASSERT_EQUAL(std::string( + CPPUNIT_ASSERT_EQUAL(createSafeByteArray( "<stream:features>" "<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>" "<compression xmlns=\"http://jabber.org/features/compress\">" @@ -47,6 +50,7 @@ class StreamFeaturesSerializerTest : public CppUnit::TestFixture "<bind xmlns=\"urn:ietf:params:xml:ns:xmpp-bind\"/>" "<session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/>" "<sm xmlns=\"urn:xmpp:sm:2\"/>" + "<ver xmlns=\"urn:xmpp:features:rosterver\"/>" "</stream:features>"), testling.serialize(streamFeatures)); } }; diff --git a/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp b/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp index 76c1b23..c0ab841 100644 --- a/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp +++ b/Swiften/Serializer/UnitTest/XMPPSerializerTest.cpp @@ -7,10 +7,10 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/XMPPSerializer.h" -#include "Swiften/Elements/AuthChallenge.h" -#include "Swiften/Serializer/PayloadSerializerCollection.h" -#include "Swiften/Elements/ProtocolHeader.h" +#include <Swiften/Serializer/XMPPSerializer.h> +#include <Swiften/Elements/AuthChallenge.h> +#include <Swiften/Serializer/PayloadSerializerCollection.h> +#include <Swiften/Elements/ProtocolHeader.h> using namespace Swift; @@ -31,7 +31,7 @@ class XMPPSerializerTest : public CppUnit::TestFixture { } void testSerializeHeader_Client() { - std::auto_ptr<XMPPSerializer> testling(createSerializer(ClientStreamType)); + boost::shared_ptr<XMPPSerializer> testling(createSerializer(ClientStreamType)); ProtocolHeader protocolHeader; protocolHeader.setFrom("bla@foo.com"); protocolHeader.setTo("foo.com"); @@ -42,7 +42,7 @@ class XMPPSerializerTest : public CppUnit::TestFixture { } void testSerializeHeader_Component() { - std::auto_ptr<XMPPSerializer> testling(createSerializer(ComponentStreamType)); + boost::shared_ptr<XMPPSerializer> testling(createSerializer(ComponentStreamType)); ProtocolHeader protocolHeader; protocolHeader.setFrom("bla@foo.com"); protocolHeader.setTo("foo.com"); @@ -53,7 +53,7 @@ class XMPPSerializerTest : public CppUnit::TestFixture { } void testSerializeHeader_Server() { - std::auto_ptr<XMPPSerializer> testling(createSerializer(ServerStreamType)); + boost::shared_ptr<XMPPSerializer> testling(createSerializer(ServerStreamType)); ProtocolHeader protocolHeader; protocolHeader.setFrom("bla@foo.com"); protocolHeader.setTo("foo.com"); diff --git a/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp b/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp index 8c68f97..897a4f4 100644 --- a/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp +++ b/Swiften/Serializer/XML/UnitTest/XMLElementTest.cpp @@ -7,8 +7,8 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Serializer/XML/XMLElement.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Serializer/XML/XMLElement.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> using namespace Swift; diff --git a/Swiften/Serializer/XML/XMLElement.cpp b/Swiften/Serializer/XML/XMLElement.cpp index 6c90e0d..d39ec39 100644 --- a/Swiften/Serializer/XML/XMLElement.cpp +++ b/Swiften/Serializer/XML/XMLElement.cpp @@ -4,10 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/XML/XMLElement.h" +#include <Swiften/Serializer/XML/XMLElement.h> -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/XML/XMLTextNode.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/XML/XMLTextNode.h> namespace Swift { @@ -28,7 +28,7 @@ std::string XMLElement::serialize() { result += " " + p.first + "=\"" + p.second + "\""; } - if (childNodes_.size() > 0) { + if (!childNodes_.empty()) { result += ">"; foreach (boost::shared_ptr<XMLNode> node, childNodes_) { result += node->serialize(); diff --git a/Swiften/Serializer/XML/XMLElement.h b/Swiften/Serializer/XML/XMLElement.h index 65af7ae..6eacb82 100644 --- a/Swiften/Serializer/XML/XMLElement.h +++ b/Swiften/Serializer/XML/XMLElement.h @@ -12,7 +12,7 @@ #include <string> -#include "Swiften/Serializer/XML/XMLNode.h" +#include <Swiften/Serializer/XML/XMLNode.h> namespace Swift { class XMLElement : public XMLNode { diff --git a/Swiften/Serializer/XML/XMLNode.cpp b/Swiften/Serializer/XML/XMLNode.cpp index cd604f5..7eedeff 100644 --- a/Swiften/Serializer/XML/XMLNode.cpp +++ b/Swiften/Serializer/XML/XMLNode.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/XML/XMLNode.h" +#include <Swiften/Serializer/XML/XMLNode.h> namespace Swift { diff --git a/Swiften/Serializer/XML/XMLNode.h b/Swiften/Serializer/XML/XMLNode.h index 5261888..d222faf 100644 --- a/Swiften/Serializer/XML/XMLNode.h +++ b/Swiften/Serializer/XML/XMLNode.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_XMLNode_H -#define SWIFTEN_XMLNode_H +#pragma once #include <string> @@ -17,5 +16,3 @@ namespace Swift { virtual std::string serialize() = 0; }; } - -#endif diff --git a/Swiften/Serializer/XML/XMLRawTextNode.h b/Swiften/Serializer/XML/XMLRawTextNode.h index 9fa8c40..9e222d5 100644 --- a/Swiften/Serializer/XML/XMLRawTextNode.h +++ b/Swiften/Serializer/XML/XMLRawTextNode.h @@ -4,10 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_XMLRawTextNode_H -#define SWIFTEN_XMLRawTextNode_H +#pragma once -#include "Swiften/Serializer/XML/XMLNode.h" +#include <Swiften/Serializer/XML/XMLNode.h> namespace Swift { class XMLRawTextNode : public XMLNode { @@ -23,5 +22,3 @@ namespace Swift { std::string text_; }; } - -#endif diff --git a/Swiften/Serializer/XML/XMLTextNode.h b/Swiften/Serializer/XML/XMLTextNode.h index 4d55f76..648854f 100644 --- a/Swiften/Serializer/XML/XMLTextNode.h +++ b/Swiften/Serializer/XML/XMLTextNode.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Serializer/XML/XMLNode.h" +#include <Swiften/Serializer/XML/XMLNode.h> #include <Swiften/Base/String.h> namespace Swift { diff --git a/Swiften/Serializer/XMPPSerializer.cpp b/Swiften/Serializer/XMPPSerializer.cpp index 06f3558..389f7cc 100644 --- a/Swiften/Serializer/XMPPSerializer.cpp +++ b/Swiften/Serializer/XMPPSerializer.cpp @@ -4,36 +4,38 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Serializer/XMPPSerializer.h" +#include <Swiften/Serializer/XMPPSerializer.h> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <iostream> #include <cassert> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Base/foreach.h" -#include "Swiften/Serializer/CompressRequestSerializer.h" -#include "Swiften/Serializer/CompressFailureSerializer.h" -#include "Swiften/Serializer/StreamErrorSerializer.h" -#include "Swiften/Serializer/StreamFeaturesSerializer.h" -#include "Swiften/Serializer/AuthRequestSerializer.h" -#include "Swiften/Serializer/AuthFailureSerializer.h" -#include "Swiften/Serializer/AuthSuccessSerializer.h" -#include "Swiften/Serializer/AuthChallengeSerializer.h" -#include "Swiften/Serializer/AuthResponseSerializer.h" -#include "Swiften/Serializer/EnableStreamManagementSerializer.h" -#include "Swiften/Serializer/StreamManagementEnabledSerializer.h" -#include "Swiften/Serializer/StreamManagementFailedSerializer.h" -#include "Swiften/Serializer/StanzaAckSerializer.h" -#include "Swiften/Serializer/StanzaAckRequestSerializer.h" -#include "Swiften/Serializer/StartTLSRequestSerializer.h" -#include "Swiften/Serializer/StartTLSFailureSerializer.h" -#include "Swiften/Serializer/TLSProceedSerializer.h" -#include "Swiften/Serializer/MessageSerializer.h" -#include "Swiften/Serializer/PresenceSerializer.h" -#include "Swiften/Serializer/IQSerializer.h" -#include "Swiften/Serializer/ComponentHandshakeSerializer.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Base/foreach.h> +#include <Swiften/Serializer/CompressRequestSerializer.h> +#include <Swiften/Serializer/CompressFailureSerializer.h> +#include <Swiften/Serializer/StreamErrorSerializer.h> +#include <Swiften/Serializer/StreamFeaturesSerializer.h> +#include <Swiften/Serializer/AuthRequestSerializer.h> +#include <Swiften/Serializer/AuthFailureSerializer.h> +#include <Swiften/Serializer/AuthSuccessSerializer.h> +#include <Swiften/Serializer/AuthChallengeSerializer.h> +#include <Swiften/Serializer/AuthResponseSerializer.h> +#include <Swiften/Serializer/EnableStreamManagementSerializer.h> +#include <Swiften/Serializer/StreamManagementEnabledSerializer.h> +#include <Swiften/Serializer/StreamResumeSerializer.h> +#include <Swiften/Serializer/StreamResumedSerializer.h> +#include <Swiften/Serializer/StreamManagementFailedSerializer.h> +#include <Swiften/Serializer/StanzaAckSerializer.h> +#include <Swiften/Serializer/StanzaAckRequestSerializer.h> +#include <Swiften/Serializer/StartTLSRequestSerializer.h> +#include <Swiften/Serializer/StartTLSFailureSerializer.h> +#include <Swiften/Serializer/TLSProceedSerializer.h> +#include <Swiften/Serializer/MessageSerializer.h> +#include <Swiften/Serializer/PresenceSerializer.h> +#include <Swiften/Serializer/IQSerializer.h> +#include <Swiften/Serializer/ComponentHandshakeSerializer.h> namespace Swift { @@ -56,6 +58,8 @@ XMPPSerializer::XMPPSerializer(PayloadSerializerCollection* payloadSerializers, serializers_.push_back(boost::make_shared<EnableStreamManagementSerializer>()); serializers_.push_back(boost::make_shared<StreamManagementEnabledSerializer>()); serializers_.push_back(boost::make_shared<StreamManagementFailedSerializer>()); + serializers_.push_back(boost::make_shared<StreamResumeSerializer>()); + serializers_.push_back(boost::make_shared<StreamResumedSerializer>()); serializers_.push_back(boost::make_shared<StanzaAckSerializer>()); serializers_.push_back(boost::make_shared<StanzaAckRequestSerializer>()); serializers_.push_back(boost::make_shared<ComponentHandshakeSerializer>()); @@ -79,16 +83,14 @@ std::string XMPPSerializer::serializeHeader(const ProtocolHeader& header) const return result; } -std::string XMPPSerializer::serializeElement(boost::shared_ptr<Element> element) const { - std::vector< boost::shared_ptr<ElementSerializer> >::const_iterator i = std::find_if( - serializers_.begin(), serializers_.end(), - boost::bind(&ElementSerializer::canSerialize, _1, element)); +SafeByteArray XMPPSerializer::serializeElement(boost::shared_ptr<Element> element) const { + std::vector< boost::shared_ptr<ElementSerializer> >::const_iterator i = std::find_if(serializers_.begin(), serializers_.end(), boost::bind(&ElementSerializer::canSerialize, _1, element)); if (i != serializers_.end()) { return (*i)->serialize(element); } else { std::cerr << "Could not find serializer for " << typeid(*(element.get())).name() << std::endl; - return ""; + return createSafeByteArray(""); } } diff --git a/Swiften/Serializer/XMPPSerializer.h b/Swiften/Serializer/XMPPSerializer.h index 4f83857..8727f7a 100644 --- a/Swiften/Serializer/XMPPSerializer.h +++ b/Swiften/Serializer/XMPPSerializer.h @@ -9,10 +9,10 @@ #include <boost/shared_ptr.hpp> #include <vector> -#include "Swiften/Elements/Element.h" -#include "Swiften/Elements/StreamType.h" +#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/StreamType.h> #include <string> -#include "Swiften/Serializer/ElementSerializer.h" +#include <Swiften/Serializer/ElementSerializer.h> namespace Swift { class PayloadSerializerCollection; @@ -24,7 +24,7 @@ namespace Swift { XMPPSerializer(PayloadSerializerCollection*, StreamType type); std::string serializeHeader(const ProtocolHeader&) const; - std::string serializeElement(boost::shared_ptr<Element> stanza) const; + SafeByteArray serializeElement(boost::shared_ptr<Element> stanza) const; std::string serializeFooter() const; private: diff --git a/Swiften/Session/BasicSessionStream.cpp b/Swiften/Session/BasicSessionStream.cpp index c783e01..d08be4f 100644 --- a/Swiften/Session/BasicSessionStream.cpp +++ b/Swiften/Session/BasicSessionStream.cpp @@ -4,18 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Session/BasicSessionStream.h" +#include <Swiften/Session/BasicSessionStream.h> #include <boost/bind.hpp> -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/StreamStack/StreamStack.h" -#include "Swiften/StreamStack/ConnectionLayer.h" -#include "Swiften/StreamStack/WhitespacePingLayer.h" -#include "Swiften/StreamStack/CompressionLayer.h" -#include "Swiften/StreamStack/TLSLayer.h" -#include "Swiften/TLS/TLSContextFactory.h" -#include "Swiften/TLS/TLSContext.h" +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/StreamStack/StreamStack.h> +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <Swiften/StreamStack/WhitespacePingLayer.h> +#include <Swiften/StreamStack/CompressionLayer.h> +#include <Swiften/StreamStack/TLSLayer.h> +#include <Swiften/TLS/TLSContextFactory.h> +#include <Swiften/TLS/TLSContext.h> namespace Swift { @@ -192,12 +192,12 @@ void BasicSessionStream::handleConnectionFinished(const boost::optional<Connecti } } -void BasicSessionStream::handleDataRead(const ByteArray& data) { - onDataRead(data.toString()); +void BasicSessionStream::handleDataRead(const SafeByteArray& data) { + onDataRead(data); } -void BasicSessionStream::handleDataWritten(const ByteArray& data) { - onDataWritten(data.toString()); +void BasicSessionStream::handleDataWritten(const SafeByteArray& data) { + onDataWritten(data); } }; diff --git a/Swiften/Session/BasicSessionStream.h b/Swiften/Session/BasicSessionStream.h index b3f7421..2a1ed8a 100644 --- a/Swiften/Session/BasicSessionStream.h +++ b/Swiften/Session/BasicSessionStream.h @@ -8,9 +8,10 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Network/Connection.h" -#include "Swiften/Session/SessionStream.h" -#include "Swiften/Elements/StreamType.h" +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/Session/SessionStream.h> +#include <Swiften/Elements/StreamType.h> namespace Swift { class TLSContextFactory; @@ -64,8 +65,8 @@ namespace Swift { void handleTLSError(); void handleStreamStartReceived(const ProtocolHeader&); void handleElementReceived(boost::shared_ptr<Element>); - void handleDataRead(const ByteArray& data); - void handleDataWritten(const ByteArray& data); + void handleDataRead(const SafeByteArray& data); + void handleDataWritten(const SafeByteArray& data); private: bool available; diff --git a/Swiften/Session/Session.cpp b/Swiften/Session/Session.cpp index 0c38f07..e8b8308 100644 --- a/Swiften/Session/Session.cpp +++ b/Swiften/Session/Session.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Session/Session.h" +#include <Swiften/Session/Session.h> #include <boost/bind.hpp> -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/StreamStack/StreamStack.h" +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/StreamStack/StreamStack.h> namespace Swift { diff --git a/Swiften/Session/Session.h b/Swiften/Session/Session.h index f8c8f0a..9e954c7 100644 --- a/Swiften/Session/Session.h +++ b/Swiften/Session/Session.h @@ -7,21 +7,21 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/optional.hpp> #include <boost/enable_shared_from_this.hpp> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/Element.h" -#include "Swiften/Network/Connection.h" -#include "Swiften/StreamStack/ConnectionLayer.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Element.h> +#include <Swiften/Network/Connection.h> +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class ProtocolHeader; class StreamStack; class JID; class Element; - class ByteArray; class PayloadParserFactoryCollection; class PayloadSerializerCollection; class XMPPLayer; @@ -63,8 +63,8 @@ namespace Swift { boost::signal<void (boost::shared_ptr<Element>)> onElementReceived; boost::signal<void (const boost::optional<SessionError>&)> onSessionFinished; - boost::signal<void (const ByteArray&)> onDataWritten; - boost::signal<void (const ByteArray&)> onDataRead; + boost::signal<void (const SafeByteArray&)> onDataWritten; + boost::signal<void (const SafeByteArray&)> onDataRead; protected: void setRemoteJID(const JID& j) { diff --git a/Swiften/Session/SessionStream.cpp b/Swiften/Session/SessionStream.cpp index 5bca0aa..0d73b63 100644 --- a/Swiften/Session/SessionStream.cpp +++ b/Swiften/Session/SessionStream.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Session/SessionStream.h" +#include <Swiften/Session/SessionStream.h> namespace Swift { diff --git a/Swiften/Session/SessionStream.h b/Swiften/Session/SessionStream.h index 2753878..e6b9469 100644 --- a/Swiften/Session/SessionStream.h +++ b/Swiften/Session/SessionStream.h @@ -6,16 +6,17 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> #include <boost/optional.hpp> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Elements/Element.h" -#include "Swiften/Base/Error.h" -#include "Swiften/TLS/PKCS12Certificate.h" -#include "Swiften/TLS/Certificate.h" -#include "Swiften/TLS/CertificateVerificationError.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Elements/Element.h> +#include <Swiften/Base/Error.h> +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/TLS/PKCS12Certificate.h> +#include <Swiften/TLS/Certificate.h> +#include <Swiften/TLS/CertificateVerificationError.h> namespace Swift { class SessionStream { @@ -71,8 +72,8 @@ namespace Swift { boost::signal<void (boost::shared_ptr<Element>)> onElementReceived; boost::signal<void (boost::shared_ptr<Error>)> onClosed; boost::signal<void ()> onTLSEncrypted; - boost::signal<void (const std::string&)> onDataRead; - boost::signal<void (const std::string&)> onDataWritten; + boost::signal<void (const SafeByteArray&)> onDataRead; + boost::signal<void (const SafeByteArray&)> onDataWritten; protected: const PKCS12Certificate& getTLSCertificate() const { diff --git a/Swiften/Session/SessionTracer.cpp b/Swiften/Session/SessionTracer.cpp new file mode 100644 index 0000000..e0a39bf --- /dev/null +++ b/Swiften/Session/SessionTracer.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Session/SessionTracer.h> + +#include <iostream> +#include <boost/bind.hpp> + +namespace Swift { + +SessionTracer::SessionTracer(boost::shared_ptr<Session> session) : session(session) { + session->onDataRead.connect(boost::bind(&SessionTracer::printData, this, '<', _1)); + session->onDataWritten.connect(boost::bind(&SessionTracer::printData, this, '>', _1)); +} + +void SessionTracer::printData(char direction, const SafeByteArray& data) { + std::cerr << direction << direction << " " << session->getLocalJID() << " "; + for (unsigned int i = 0; i < 72 - session->getLocalJID().toString().size() - session->getRemoteJID().toString().size(); ++i) { + std::cerr << direction; + } + std::cerr << " " << session->getRemoteJID()<< " " << direction << direction << std::endl; + std::cerr << byteArrayToString(ByteArray(data.begin(), data.end())) << std::endl; +} + +} diff --git a/Swiften/Session/SessionTracer.h b/Swiften/Session/SessionTracer.h index cce45eb..72c93b4 100644 --- a/Swiften/Session/SessionTracer.h +++ b/Swiften/Session/SessionTracer.h @@ -6,29 +6,18 @@ #pragma once -#include <iostream> - -#include "Swiften/Session/Session.h" #include <string> -#include "Swiften/Base/ByteArray.h" + +#include <Swiften/Session/Session.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class SessionTracer { public: - SessionTracer(boost::shared_ptr<Session> session) : session(session) { - session->onDataRead.connect(boost::bind(&SessionTracer::printData, this, '<', _1)); - session->onDataWritten.connect(boost::bind(&SessionTracer::printData, this, '>', _1)); - } + SessionTracer(boost::shared_ptr<Session> session); private: - void printData(char direction, const ByteArray& data) { - std::cerr << direction << direction << " " << session->getLocalJID() << " "; - for (unsigned int i = 0; i < 72 - session->getLocalJID().toString().size() - session->getRemoteJID().toString().size(); ++i) { - std::cerr << direction; - } - std::cerr << " " << session->getRemoteJID()<< " " << direction << direction << std::endl; - std::cerr << data.toString() << std::endl; - } + void printData(char direction, const SafeByteArray& data); boost::shared_ptr<Session> session; }; diff --git a/Swiften/StreamManagement/StanzaAckRequester.cpp b/Swiften/StreamManagement/StanzaAckRequester.cpp index f7d603b..b60b9b0 100644 --- a/Swiften/StreamManagement/StanzaAckRequester.cpp +++ b/Swiften/StreamManagement/StanzaAckRequester.cpp @@ -4,11 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StreamManagement/StanzaAckRequester.h" +#include <Swiften/StreamManagement/StanzaAckRequester.h> #include <boost/numeric/conversion/cast.hpp> +#include <iostream> -#include "Swiften/Elements/Message.h" +#include <Swiften/Elements/Message.h> namespace Swift { @@ -28,7 +29,7 @@ void StanzaAckRequester::handleStanzaSent(boost::shared_ptr<Stanza> stanza) { void StanzaAckRequester::handleAckReceived(unsigned int handledStanzasCount) { unsigned int i = lastHandledStanzasCount; while (i != handledStanzasCount) { - if (unackedStanzas.size() == 0) { + if (unackedStanzas.empty()) { std::cerr << "Warning: Server acked more stanzas than we sent" << std::endl; break; } diff --git a/Swiften/StreamManagement/StanzaAckRequester.h b/Swiften/StreamManagement/StanzaAckRequester.h index 89f068e..e8e4997 100644 --- a/Swiften/StreamManagement/StanzaAckRequester.h +++ b/Swiften/StreamManagement/StanzaAckRequester.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <deque> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class StanzaAckRequester { diff --git a/Swiften/StreamManagement/StanzaAckResponder.cpp b/Swiften/StreamManagement/StanzaAckResponder.cpp index 5b71f91..9295924 100644 --- a/Swiften/StreamManagement/StanzaAckResponder.cpp +++ b/Swiften/StreamManagement/StanzaAckResponder.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StreamManagement/StanzaAckResponder.h" +#include <Swiften/StreamManagement/StanzaAckResponder.h> #include <boost/numeric/conversion/cast.hpp> diff --git a/Swiften/StreamManagement/StanzaAckResponder.h b/Swiften/StreamManagement/StanzaAckResponder.h index bc83aa1..b5888b7 100644 --- a/Swiften/StreamManagement/StanzaAckResponder.h +++ b/Swiften/StreamManagement/StanzaAckResponder.h @@ -8,8 +8,8 @@ #include <boost/shared_ptr.hpp> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Elements/Stanza.h> +#include <Swiften/Base/boost_bsignals.h> namespace Swift { class StanzaAckResponder { diff --git a/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp b/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp index 1028ae7..baccc41 100644 --- a/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp +++ b/Swiften/StreamManagement/UnitTest/StanzaAckRequesterTest.cpp @@ -9,10 +9,10 @@ #include <boost/bind.hpp> #include <boost/numeric/conversion/cast.hpp> -#include "Swiften/StreamManagement/StanzaAckRequester.h" -#include "Swiften/Elements/Message.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/IQ.h" +#include <Swiften/StreamManagement/StanzaAckRequester.h> +#include <Swiften/Elements/Message.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/IQ.h> using namespace Swift; @@ -36,28 +36,28 @@ class StanzaAckRequesterTest : public CppUnit::TestFixture { } void testHandleStanzaSent_MessageRequestsAck() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createMessage("m1")); CPPUNIT_ASSERT_EQUAL(1, acksRequested); } void testHandleStanzaSent_IQDoesNotRequestAck() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createIQ("iq1")); CPPUNIT_ASSERT_EQUAL(0, acksRequested); } void testHandleStanzaSent_PresenceDoesNotRequestAck() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createPresence("p1")); CPPUNIT_ASSERT_EQUAL(0, acksRequested); } void testHandleAckReceived_AcksStanza() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createMessage("m1")); testling->handleAckReceived(1); @@ -67,7 +67,7 @@ class StanzaAckRequesterTest : public CppUnit::TestFixture { } void testHandleAckReceived_AcksMultipleMessages() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createMessage("m1")); testling->handleStanzaSent(createMessage("m2")); @@ -79,7 +79,7 @@ class StanzaAckRequesterTest : public CppUnit::TestFixture { } void testHandleAckReceived_AcksMultipleStanzas() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createIQ("iq1")); testling->handleStanzaSent(createPresence("p1")); testling->handleStanzaSent(createMessage("m1")); @@ -93,7 +93,7 @@ class StanzaAckRequesterTest : public CppUnit::TestFixture { } void testHandleAckReceived_MultipleAcks() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->handleStanzaSent(createMessage("m1")); testling->handleAckReceived(1); @@ -109,7 +109,7 @@ class StanzaAckRequesterTest : public CppUnit::TestFixture { // Handle stanza ack count wrapping, as per the XEP void testHandleAckReceived_WrapAround() { - std::auto_ptr<StanzaAckRequester> testling(createRequester()); + boost::shared_ptr<StanzaAckRequester> testling(createRequester()); testling->lastHandledStanzasCount = boost::numeric_cast<unsigned int>((1ULL<<32) - 1); testling->handleStanzaSent(createMessage("m1")); testling->handleStanzaSent(createMessage("m2")); diff --git a/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp b/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp index b24335f..71a7f94 100644 --- a/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp +++ b/Swiften/StreamManagement/UnitTest/StanzaAckResponderTest.cpp @@ -9,8 +9,8 @@ #include <boost/bind.hpp> #include <boost/numeric/conversion/cast.hpp> -#include "Swiften/StreamManagement/StanzaAckResponder.h" -#include "Swiften/Elements/Message.h" +#include <Swiften/StreamManagement/StanzaAckResponder.h> +#include <Swiften/Elements/Message.h> using namespace Swift; @@ -26,7 +26,7 @@ class StanzaAckResponderTest : public CppUnit::TestFixture { public: void testHandleAckRequestReceived_AcksStanza() { - std::auto_ptr<StanzaAckResponder> testling(createResponder()); + boost::shared_ptr<StanzaAckResponder> testling(createResponder()); testling->handleStanzaReceived(); testling->handleAckRequestReceived(); @@ -36,7 +36,7 @@ class StanzaAckResponderTest : public CppUnit::TestFixture { } void testHandleAckRequestReceived_AcksMultipleStanzas() { - std::auto_ptr<StanzaAckResponder> testling(createResponder()); + boost::shared_ptr<StanzaAckResponder> testling(createResponder()); testling->handleStanzaReceived(); testling->handleStanzaReceived(); @@ -47,7 +47,7 @@ class StanzaAckResponderTest : public CppUnit::TestFixture { } void testHandleAckRequestReceived_MultipleAcks() { - std::auto_ptr<StanzaAckResponder> testling(createResponder()); + boost::shared_ptr<StanzaAckResponder> testling(createResponder()); testling->handleStanzaReceived(); testling->handleAckRequestReceived(); @@ -61,7 +61,7 @@ class StanzaAckResponderTest : public CppUnit::TestFixture { // Handle stanza ack count wrapping, as per the XEP void testHandleAckRequestReceived_WrapAround() { - std::auto_ptr<StanzaAckResponder> testling(createResponder()); + boost::shared_ptr<StanzaAckResponder> testling(createResponder()); testling->handledStanzasCount = boost::numeric_cast<unsigned int>((1ULL<<32) - 1); testling->handleStanzaReceived(); testling->handleStanzaReceived(); diff --git a/Swiften/StreamStack/CompressionLayer.h b/Swiften/StreamStack/CompressionLayer.h index b8293a8..783cfca 100644 --- a/Swiften/StreamStack/CompressionLayer.h +++ b/Swiften/StreamStack/CompressionLayer.h @@ -7,13 +7,13 @@ #pragma once #include <boost/noncopyable.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/StreamStack/StreamLayer.h" -#include "Swiften/Compress/ZLibException.h" -#include "Swiften/Compress/ZLibCompressor.h" -#include "Swiften/Compress/ZLibDecompressor.h" +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/StreamStack/StreamLayer.h> +#include <Swiften/Compress/ZLibException.h> +#include <Swiften/Compress/ZLibCompressor.h> +#include <Swiften/Compress/ZLibDecompressor.h> namespace Swift { class ZLibCompressor; @@ -23,20 +23,20 @@ namespace Swift { public: CompressionLayer() {} - virtual void writeData(const ByteArray& data) { + virtual void writeData(const SafeByteArray& data) { try { writeDataToChildLayer(compressor_.process(data)); } - catch (const ZLibException& e) { + catch (const ZLibException&) { onError(); } } - virtual void handleDataRead(const ByteArray& data) { + virtual void handleDataRead(const SafeByteArray& data) { try { writeDataToParentLayer(decompressor_.process(data)); } - catch (const ZLibException& e) { + catch (const ZLibException&) { onError(); } } diff --git a/Swiften/StreamStack/ConnectionLayer.cpp b/Swiften/StreamStack/ConnectionLayer.cpp new file mode 100644 index 0000000..5ea06eb --- /dev/null +++ b/Swiften/StreamStack/ConnectionLayer.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/StreamStack/ConnectionLayer.h> +#include <boost/bind.hpp> + +namespace Swift { + +ConnectionLayer::ConnectionLayer(boost::shared_ptr<Connection> connection) : connection(connection) { + connection->onDataRead.connect(boost::bind(&ConnectionLayer::handleDataRead, this, _1)); +} + +ConnectionLayer::~ConnectionLayer() { + connection->onDataRead.disconnect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); +} + +void ConnectionLayer::handleDataRead(boost::shared_ptr<SafeByteArray> data) { + writeDataToParentLayer(*data); +} + + +} diff --git a/Swiften/StreamStack/ConnectionLayer.h b/Swiften/StreamStack/ConnectionLayer.h index 0da0900..6776751 100644 --- a/Swiften/StreamStack/ConnectionLayer.h +++ b/Swiften/StreamStack/ConnectionLayer.h @@ -6,29 +6,25 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" #include <boost/shared_ptr.hpp> -#include <boost/bind.hpp> -#include "Swiften/StreamStack/LowLayer.h" -#include "Swiften/Network/Connection.h" +#include <Swiften/StreamStack/LowLayer.h> +#include <Swiften/Network/Connection.h> namespace Swift { class ConnectionLayer : public LowLayer { public: - ConnectionLayer(boost::shared_ptr<Connection> connection) : connection(connection) { - connection->onDataRead.connect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); - } - - ~ConnectionLayer() { - connection->onDataRead.disconnect(boost::bind(&ConnectionLayer::writeDataToParentLayer, this, _1)); - } + ConnectionLayer(boost::shared_ptr<Connection> connection); + ~ConnectionLayer(); - void writeData(const ByteArray& data) { + void writeData(const SafeByteArray& data) { connection->write(data); } private: + void handleDataRead(boost::shared_ptr<SafeByteArray>); + + private: boost::shared_ptr<Connection> connection; }; } diff --git a/Swiften/StreamStack/HighLayer.cpp b/Swiften/StreamStack/HighLayer.cpp index 7203b7f..dc17c2a 100644 --- a/Swiften/StreamStack/HighLayer.cpp +++ b/Swiften/StreamStack/HighLayer.cpp @@ -18,7 +18,7 @@ HighLayer::HighLayer() : childLayer(NULL) { HighLayer::~HighLayer() { } -void HighLayer::writeDataToChildLayer(const ByteArray& data) { +void HighLayer::writeDataToChildLayer(const SafeByteArray& data) { assert(childLayer); childLayer->writeData(data); } diff --git a/Swiften/StreamStack/HighLayer.h b/Swiften/StreamStack/HighLayer.h index ca983f9..06b1d25 100644 --- a/Swiften/StreamStack/HighLayer.h +++ b/Swiften/StreamStack/HighLayer.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class LowLayer; @@ -18,7 +18,7 @@ namespace Swift { HighLayer(); virtual ~HighLayer(); - virtual void handleDataRead(const ByteArray& data) = 0; + virtual void handleDataRead(const SafeByteArray& data) = 0; protected: LowLayer* getChildLayer() { @@ -29,7 +29,7 @@ namespace Swift { this->childLayer = childLayer; } - void writeDataToChildLayer(const ByteArray& data); + void writeDataToChildLayer(const SafeByteArray& data); private: LowLayer* childLayer; diff --git a/Swiften/StreamStack/LowLayer.cpp b/Swiften/StreamStack/LowLayer.cpp index ed93cd2..ff4ca17 100644 --- a/Swiften/StreamStack/LowLayer.cpp +++ b/Swiften/StreamStack/LowLayer.cpp @@ -18,7 +18,7 @@ LowLayer::LowLayer() : parentLayer(NULL) { LowLayer::~LowLayer() { } -void LowLayer::writeDataToParentLayer(const ByteArray& data) { +void LowLayer::writeDataToParentLayer(const SafeByteArray& data) { assert(parentLayer); parentLayer->handleDataRead(data); } diff --git a/Swiften/StreamStack/LowLayer.h b/Swiften/StreamStack/LowLayer.h index 1f9645a..00960ea 100644 --- a/Swiften/StreamStack/LowLayer.h +++ b/Swiften/StreamStack/LowLayer.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class HighLayer; @@ -18,7 +18,7 @@ namespace Swift { LowLayer(); virtual ~LowLayer(); - virtual void writeData(const ByteArray& data) = 0; + virtual void writeData(const SafeByteArray& data) = 0; protected: HighLayer* getParentLayer() { @@ -29,7 +29,7 @@ namespace Swift { this->parentLayer = parentLayer; } - void writeDataToParentLayer(const ByteArray& data); + void writeDataToParentLayer(const SafeByteArray& data); private: HighLayer* parentLayer; diff --git a/Swiften/StreamStack/SConscript b/Swiften/StreamStack/SConscript index 022c695..06fcc03 100644 --- a/Swiften/StreamStack/SConscript +++ b/Swiften/StreamStack/SConscript @@ -6,6 +6,7 @@ sources = [ "HighLayer.cpp", "LowLayer.cpp", "StreamStack.cpp", + "ConnectionLayer.cpp", "TLSLayer.cpp", "WhitespacePingLayer.cpp", "XMPPLayer.cpp", diff --git a/Swiften/StreamStack/StreamLayer.h b/Swiften/StreamStack/StreamLayer.h index bcc5d79..09bb5b3 100644 --- a/Swiften/StreamStack/StreamLayer.h +++ b/Swiften/StreamStack/StreamLayer.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/StreamStack/LowLayer.h" -#include "Swiften/StreamStack/HighLayer.h" +#include <Swiften/StreamStack/LowLayer.h> +#include <Swiften/StreamStack/HighLayer.h> namespace Swift { class StreamLayer : public LowLayer, public HighLayer { diff --git a/Swiften/StreamStack/StreamStack.cpp b/Swiften/StreamStack/StreamStack.cpp index 2a30768..78409f7 100644 --- a/Swiften/StreamStack/StreamStack.cpp +++ b/Swiften/StreamStack/StreamStack.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StreamStack/StreamStack.h" +#include <Swiften/StreamStack/StreamStack.h> #include <boost/bind.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/StreamStack/LowLayer.h" -#include "Swiften/StreamStack/StreamLayer.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/StreamStack/LowLayer.h> +#include <Swiften/StreamStack/StreamLayer.h> namespace Swift { diff --git a/Swiften/StreamStack/StreamStack.h b/Swiften/StreamStack/StreamStack.h index 562245e..30e17ce 100644 --- a/Swiften/StreamStack/StreamStack.h +++ b/Swiften/StreamStack/StreamStack.h @@ -7,11 +7,10 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <vector> -#include "Swiften/Elements/Stanza.h" -#include "Swiften/Base/foreach.h" +#include <Swiften/Elements/Stanza.h> namespace Swift { class XMPPLayer; @@ -30,8 +29,8 @@ namespace Swift { } template<typename T> T* getLayer() { - foreach(StreamLayer* streamLayer, layers_) { - T* layer = dynamic_cast<T*>(streamLayer); + for (size_t i = 0; i < layers_.size(); ++i) { + T* layer = dynamic_cast<T*>(layers_[i]); if (layer) { return layer; } diff --git a/Swiften/StreamStack/TLSLayer.cpp b/Swiften/StreamStack/TLSLayer.cpp index 8a6c008..6f2223d 100644 --- a/Swiften/StreamStack/TLSLayer.cpp +++ b/Swiften/StreamStack/TLSLayer.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StreamStack/TLSLayer.h" +#include <Swiften/StreamStack/TLSLayer.h> #include <boost/bind.hpp> -#include "Swiften/TLS/TLSContextFactory.h" -#include "Swiften/TLS/TLSContext.h" +#include <Swiften/TLS/TLSContextFactory.h> +#include <Swiften/TLS/TLSContext.h> namespace Swift { @@ -29,11 +29,11 @@ void TLSLayer::connect() { context->connect(); } -void TLSLayer::writeData(const ByteArray& data) { +void TLSLayer::writeData(const SafeByteArray& data) { context->handleDataFromApplication(data); } -void TLSLayer::handleDataRead(const ByteArray& data) { +void TLSLayer::handleDataRead(const SafeByteArray& data) { context->handleDataFromNetwork(data); } diff --git a/Swiften/StreamStack/TLSLayer.h b/Swiften/StreamStack/TLSLayer.h index 22e9aef..a8693d5 100644 --- a/Swiften/StreamStack/TLSLayer.h +++ b/Swiften/StreamStack/TLSLayer.h @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/StreamStack/StreamLayer.h" -#include "Swiften/TLS/Certificate.h" -#include "Swiften/TLS/CertificateVerificationError.h" +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/StreamStack/StreamLayer.h> +#include <Swiften/TLS/Certificate.h> +#include <Swiften/TLS/CertificateVerificationError.h> namespace Swift { class TLSContext; @@ -27,8 +27,8 @@ namespace Swift { Certificate::ref getPeerCertificate() const; boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; - void writeData(const ByteArray& data); - void handleDataRead(const ByteArray& data); + void writeData(const SafeByteArray& data); + void handleDataRead(const SafeByteArray& data); TLSContext* getContext() const { return context; diff --git a/Swiften/StreamStack/UnitTest/StreamStackTest.cpp b/Swiften/StreamStack/UnitTest/StreamStackTest.cpp index be16baa..d3c0a7c 100644 --- a/Swiften/StreamStack/UnitTest/StreamStackTest.cpp +++ b/Swiften/StreamStack/UnitTest/StreamStackTest.cpp @@ -4,7 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <vector> #include <boost/bind.hpp> @@ -12,13 +13,14 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/StreamStack/StreamStack.h" -#include "Swiften/StreamStack/LowLayer.h" -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/StreamStack/StreamLayer.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Concat.h> +#include <Swiften/StreamStack/StreamStack.h> +#include <Swiften/StreamStack/LowLayer.h> +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/StreamStack/StreamLayer.h> +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> using namespace Swift; @@ -52,38 +54,38 @@ class StreamStackTest : public CppUnit::TestFixture { xmppStream_->writeData("foo"); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), physicalStream_->data_.size()); - CPPUNIT_ASSERT_EQUAL(ByteArray("foo"), physicalStream_->data_[0]); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("foo"), physicalStream_->data_[0]); } void testWriteData_OneIntermediateStream() { StreamStack testling(xmppStream_, physicalStream_); - std::auto_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); + boost::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); testling.addLayer(xStream.get()); xmppStream_->writeData("foo"); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), physicalStream_->data_.size()); - CPPUNIT_ASSERT_EQUAL(ByteArray("Xfoo"), physicalStream_->data_[0]); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("Xfoo"), physicalStream_->data_[0]); } void testWriteData_TwoIntermediateStreamStack() { StreamStack testling(xmppStream_, physicalStream_); - std::auto_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); - std::auto_ptr<MyStreamLayer> yStream(new MyStreamLayer("Y")); + boost::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); + boost::shared_ptr<MyStreamLayer> yStream(new MyStreamLayer("Y")); testling.addLayer(xStream.get()); testling.addLayer(yStream.get()); xmppStream_->writeData("foo"); CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), physicalStream_->data_.size()); - CPPUNIT_ASSERT_EQUAL(ByteArray("XYfoo"), physicalStream_->data_[0]); + CPPUNIT_ASSERT_EQUAL(createSafeByteArray("XYfoo"), physicalStream_->data_[0]); } void testReadData_NoIntermediateStreamStack() { StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onElement.connect(boost::bind(&StreamStackTest::handleElement, this, _1)); - physicalStream_->onDataRead(ByteArray("<stream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); + physicalStream_->onDataRead(createSafeByteArray("<stream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); CPPUNIT_ASSERT_EQUAL(1, elementsReceived_); } @@ -91,10 +93,10 @@ class StreamStackTest : public CppUnit::TestFixture { void testReadData_OneIntermediateStream() { StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onElement.connect(boost::bind(&StreamStackTest::handleElement, this, _1)); - std::auto_ptr<MyStreamLayer> xStream(new MyStreamLayer("<")); + boost::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("<")); testling.addLayer(xStream.get()); - physicalStream_->onDataRead(ByteArray("stream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); + physicalStream_->onDataRead(createSafeByteArray("stream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); CPPUNIT_ASSERT_EQUAL(1, elementsReceived_); } @@ -102,12 +104,12 @@ class StreamStackTest : public CppUnit::TestFixture { void testReadData_TwoIntermediateStreamStack() { StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onElement.connect(boost::bind(&StreamStackTest::handleElement, this, _1)); - std::auto_ptr<MyStreamLayer> xStream(new MyStreamLayer("s")); - std::auto_ptr<MyStreamLayer> yStream(new MyStreamLayer("<")); + boost::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("s")); + boost::shared_ptr<MyStreamLayer> yStream(new MyStreamLayer("<")); testling.addLayer(xStream.get()); testling.addLayer(yStream.get()); - physicalStream_->onDataRead(ByteArray("tream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); + physicalStream_->onDataRead(createSafeByteArray("tream:stream xmlns:stream='http://etherx.jabber.org/streams'><presence/>")); CPPUNIT_ASSERT_EQUAL(1, elementsReceived_); } @@ -115,7 +117,7 @@ class StreamStackTest : public CppUnit::TestFixture { void testAddLayer_ExistingOnWriteDataSlot() { StreamStack testling(xmppStream_, physicalStream_); xmppStream_->onWriteData.connect(boost::bind(&StreamStackTest::handleWriteData, this, _1)); - std::auto_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); + boost::shared_ptr<MyStreamLayer> xStream(new MyStreamLayer("X")); testling.addLayer(xStream.get()); xmppStream_->writeData("foo"); @@ -127,7 +129,7 @@ class StreamStackTest : public CppUnit::TestFixture { ++elementsReceived_; } - void handleWriteData(ByteArray) { + void handleWriteData(const SafeByteArray&) { ++dataWriteReceived_; } @@ -137,12 +139,12 @@ class StreamStackTest : public CppUnit::TestFixture { MyStreamLayer(const std::string& prepend) : prepend_(prepend) { } - virtual void writeData(const ByteArray& data) { - writeDataToChildLayer(ByteArray(prepend_) + data); + virtual void writeData(const SafeByteArray& data) { + writeDataToChildLayer(concat(createSafeByteArray(prepend_), data)); } - virtual void handleDataRead(const ByteArray& data) { - writeDataToParentLayer(ByteArray(prepend_) + data); + virtual void handleDataRead(const SafeByteArray& data) { + writeDataToParentLayer(concat(createSafeByteArray(prepend_), data)); } private: @@ -154,15 +156,15 @@ class StreamStackTest : public CppUnit::TestFixture { TestLowLayer() { } - virtual void writeData(const ByteArray& data) { + virtual void writeData(const SafeByteArray& data) { data_.push_back(data); } - void onDataRead(const ByteArray& data) { + void onDataRead(const SafeByteArray& data) { writeDataToParentLayer(data); } - std::vector<ByteArray> data_; + std::vector<SafeByteArray> data_; }; diff --git a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp index 9d5e745..bb0ce61 100644 --- a/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp +++ b/Swiften/StreamStack/UnitTest/XMPPLayerTest.cpp @@ -9,13 +9,13 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Elements/ProtocolHeader.h" -#include "Swiften/Elements/Presence.h" -#include "Swiften/Base/ByteArray.h" -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/StreamStack/LowLayer.h" -#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" -#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include <Swiften/Elements/ProtocolHeader.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Base/ByteArray.h> +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/StreamStack/LowLayer.h> +#include <Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h> +#include <Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h> using namespace Swift; @@ -46,7 +46,7 @@ class XMPPLayerTest : public CppUnit::TestFixture { void testParseData_Error() { testling_->onError.connect(boost::bind(&XMPPLayerTest::handleError, this)); - testling_->handleDataRead("<iq>"); + testling_->handleDataRead(createSafeByteArray("<iq>")); CPPUNIT_ASSERT_EQUAL(1, errorReceived_); } @@ -55,10 +55,10 @@ class XMPPLayerTest : public CppUnit::TestFixture { testling_->onElement.connect(boost::bind(&XMPPLayerTest::handleElement, this, _1)); testling_->onError.connect(boost::bind(&XMPPLayerTest::handleError, this)); - testling_->handleDataRead("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" >"); + testling_->handleDataRead(createSafeByteArray("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" >")); testling_->resetParser(); - testling_->handleDataRead("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" >"); - testling_->handleDataRead("<presence/>"); + testling_->handleDataRead(createSafeByteArray("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" >")); + testling_->handleDataRead(createSafeByteArray("<presence/>")); CPPUNIT_ASSERT_EQUAL(1, elementsReceived_); CPPUNIT_ASSERT_EQUAL(0, errorReceived_); @@ -66,8 +66,8 @@ class XMPPLayerTest : public CppUnit::TestFixture { void testResetParser_FromSlot() { testling_->onElement.connect(boost::bind(&XMPPLayerTest::handleElementAndReset, this, _1)); - testling_->handleDataRead("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" ><presence/>"); - testling_->handleDataRead("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" ><presence/>"); + testling_->handleDataRead(createSafeByteArray("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" ><presence/>")); + testling_->handleDataRead(createSafeByteArray("<stream:stream to=\"example.com\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" ><presence/>")); CPPUNIT_ASSERT_EQUAL(2, elementsReceived_); CPPUNIT_ASSERT_EQUAL(0, errorReceived_); @@ -120,8 +120,8 @@ class XMPPLayerTest : public CppUnit::TestFixture { class DummyLowLayer : public LowLayer { public: - virtual void writeData(const ByteArray& data) { - writtenData += data.toString(); + virtual void writeData(const SafeByteArray& data) { + writtenData += byteArrayToString(ByteArray(data.begin(), data.end())); } std::string writtenData; diff --git a/Swiften/StreamStack/WhitespacePingLayer.cpp b/Swiften/StreamStack/WhitespacePingLayer.cpp index 35efc3c..b14f3a2 100644 --- a/Swiften/StreamStack/WhitespacePingLayer.cpp +++ b/Swiften/StreamStack/WhitespacePingLayer.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StreamStack/WhitespacePingLayer.h" +#include <Swiften/StreamStack/WhitespacePingLayer.h> #include <boost/bind.hpp> -#include "Swiften/Network/TimerFactory.h" -#include "Swiften/Network/Timer.h" +#include <Swiften/Network/TimerFactory.h> +#include <Swiften/Network/Timer.h> namespace Swift { @@ -20,17 +20,17 @@ WhitespacePingLayer::WhitespacePingLayer(TimerFactory* timerFactory) : isActive( timer->onTick.connect(boost::bind(&WhitespacePingLayer::handleTimerTick, this)); } -void WhitespacePingLayer::writeData(const ByteArray& data) { +void WhitespacePingLayer::writeData(const SafeByteArray& data) { writeDataToChildLayer(data); } -void WhitespacePingLayer::handleDataRead(const ByteArray& data) { +void WhitespacePingLayer::handleDataRead(const SafeByteArray& data) { writeDataToParentLayer(data); } void WhitespacePingLayer::handleTimerTick() { timer->stop(); - writeDataToChildLayer(" "); + writeDataToChildLayer(createSafeByteArray(" ")); timer->start(); } diff --git a/Swiften/StreamStack/WhitespacePingLayer.h b/Swiften/StreamStack/WhitespacePingLayer.h index 0532bbd..1435842 100644 --- a/Swiften/StreamStack/WhitespacePingLayer.h +++ b/Swiften/StreamStack/WhitespacePingLayer.h @@ -9,7 +9,7 @@ #include <boost/noncopyable.hpp> #include <boost/shared_ptr.hpp> -#include "Swiften/StreamStack/StreamLayer.h" +#include <Swiften/StreamStack/StreamLayer.h> namespace Swift { class Timer; @@ -21,8 +21,8 @@ namespace Swift { void setActive(); void setInactive(); - void writeData(const ByteArray& data); - void handleDataRead(const ByteArray& data); + void writeData(const SafeByteArray& data); + void handleDataRead(const SafeByteArray& data); bool getIsActive() const { return isActive; diff --git a/Swiften/StreamStack/XMPPLayer.cpp b/Swiften/StreamStack/XMPPLayer.cpp index 684dfe6..1dcd84f 100644 --- a/Swiften/StreamStack/XMPPLayer.cpp +++ b/Swiften/StreamStack/XMPPLayer.cpp @@ -4,10 +4,10 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StreamStack/XMPPLayer.h" -#include "Swiften/Parser/XMPPParser.h" -#include "Swiften/Serializer/XMPPSerializer.h" -#include "Swiften/Elements/ProtocolHeader.h" +#include <Swiften/StreamStack/XMPPLayer.h> +#include <Swiften/Parser/XMPPParser.h> +#include <Swiften/Serializer/XMPPSerializer.h> +#include <Swiften/Elements/ProtocolHeader.h> namespace Swift { @@ -29,30 +29,33 @@ XMPPLayer::~XMPPLayer() { } void XMPPLayer::writeHeader(const ProtocolHeader& header) { - writeDataInternal(ByteArray(xmppSerializer_->serializeHeader(header))); + writeDataInternal(createSafeByteArray(xmppSerializer_->serializeHeader(header))); } void XMPPLayer::writeFooter() { - writeDataInternal(ByteArray(xmppSerializer_->serializeFooter())); + writeDataInternal(createSafeByteArray(xmppSerializer_->serializeFooter())); } void XMPPLayer::writeElement(boost::shared_ptr<Element> element) { - writeDataInternal(ByteArray(xmppSerializer_->serializeElement(element))); + writeDataInternal(xmppSerializer_->serializeElement(element)); } void XMPPLayer::writeData(const std::string& data) { - writeDataInternal(ByteArray(data)); + writeDataInternal(createSafeByteArray(data)); } -void XMPPLayer::writeDataInternal(const ByteArray& data) { +void XMPPLayer::writeDataInternal(const SafeByteArray& data) { onWriteData(data); writeDataToChildLayer(data); } -void XMPPLayer::handleDataRead(const ByteArray& data) { +void XMPPLayer::handleDataRead(const SafeByteArray& data) { onDataRead(data); inParser_ = true; - if (!xmppParser_->parse(data.toString())) { + // FIXME: Converting to unsafe string. Should be ok, since we don't take passwords + // from the stream in clients. If servers start using this, and require safe storage, + // we need to fix this. + if (!xmppParser_->parse(byteArrayToString(ByteArray(data.begin(), data.end())))) { inParser_ = false; onError(); return; diff --git a/Swiften/StreamStack/XMPPLayer.h b/Swiften/StreamStack/XMPPLayer.h index 6669cda..54bdd42 100644 --- a/Swiften/StreamStack/XMPPLayer.h +++ b/Swiften/StreamStack/XMPPLayer.h @@ -7,14 +7,14 @@ #pragma once #include <boost/shared_ptr.hpp> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/noncopyable.hpp> #include <Swiften/StreamStack/HighLayer.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Elements/Element.h" -#include "Swiften/Elements/StreamType.h" -#include "Swiften/Parser/XMPPParserClient.h" +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Elements/Element.h> +#include <Swiften/Elements/StreamType.h> +#include <Swiften/Parser/XMPPParserClient.h> namespace Swift { class ProtocolHeader; @@ -39,14 +39,14 @@ namespace Swift { void resetParser(); protected: - void handleDataRead(const ByteArray& data); - void writeDataInternal(const ByteArray& data); + void handleDataRead(const SafeByteArray& data); + void writeDataInternal(const SafeByteArray& data); public: boost::signal<void (const ProtocolHeader&)> onStreamStart; boost::signal<void (boost::shared_ptr<Element>)> onElement; - boost::signal<void (const ByteArray&)> onWriteData; - boost::signal<void (const ByteArray&)> onDataRead; + boost::signal<void (const SafeByteArray&)> onWriteData; + boost::signal<void (const SafeByteArray&)> onDataRead; boost::signal<void ()> onError; private: diff --git a/Swiften/StringCodecs/Base64.cpp b/Swiften/StringCodecs/Base64.cpp index 795d982..e4eaa4e 100644 --- a/Swiften/StringCodecs/Base64.cpp +++ b/Swiften/StringCodecs/Base64.cpp @@ -5,50 +5,63 @@ */ #include <boost/numeric/conversion/cast.hpp> + #include <algorithm> -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/Base/Algorithm.h> namespace Swift { #pragma GCC diagnostic ignored "-Wold-style-cast" -std::string Base64::encode(const ByteArray &s) { - int i; - int len = s.getSize(); - char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - int a, b, c; - - std::string p; - p.resize((len+2)/3*4); - int at = 0; - for( i = 0; i < len; i += 3 ) { - a = ((unsigned char) (s[i]) & 3) << 4; - if(i + 1 < len) { - a += (unsigned char) (s[i + 1]) >> 4; - b = ((unsigned char) (s[i + 1]) & 0xF) << 2; - if(i + 2 < len) { - b += (unsigned char) (s[i + 2]) >> 6; - c = (unsigned char) (s[i + 2]) & 0x3F; +namespace { + template<typename TargetType, typename SourceType> + TargetType base64Encode(const SourceType& s) { + int i; + int len = s.size(); + char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + int a, b, c; + + TargetType p; + p.resize((len+2)/3*4); + int at = 0; + for( i = 0; i < len; i += 3 ) { + a = ((unsigned char) (s[i]) & 3) << 4; + if(i + 1 < len) { + a += (unsigned char) (s[i + 1]) >> 4; + b = ((unsigned char) (s[i + 1]) & 0xF) << 2; + if(i + 2 < len) { + b += (unsigned char) (s[i + 2]) >> 6; + c = (unsigned char) (s[i + 2]) & 0x3F; + } + else + c = 64; + } + else { + b = c = 64; } - else - c = 64; - } - else { - b = c = 64; - } - p[at++] = tbl[(unsigned char) (s[i]) >> 2]; - p[at++] = tbl[a]; - p[at++] = tbl[b]; - p[at++] = tbl[c]; + p[at++] = tbl[(unsigned char) (s[i]) >> 2]; + p[at++] = tbl[a]; + p[at++] = tbl[b]; + p[at++] = tbl[c]; + } + return p; } - return p; +} + +std::string Base64::encode(const ByteArray &s) { + return base64Encode<std::string, ByteArray>(s); +} + +SafeByteArray Base64::encode(const SafeByteArray &s) { + return base64Encode<SafeByteArray, SafeByteArray>(s); } ByteArray Base64::decode(const std::string& input) { std::string inputWithoutNewlines(input); - inputWithoutNewlines.erase(std::remove(inputWithoutNewlines.begin(), inputWithoutNewlines.end(), '\n'), inputWithoutNewlines.end()); + erase(inputWithoutNewlines, '\n'); const std::string& s = inputWithoutNewlines; ByteArray p; diff --git a/Swiften/StringCodecs/Base64.h b/Swiften/StringCodecs/Base64.h index 4b19a9f..2d67971 100644 --- a/Swiften/StringCodecs/Base64.h +++ b/Swiften/StringCodecs/Base64.h @@ -9,12 +9,15 @@ #include <vector> #include <string> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class Base64 { public: static std::string encode(const ByteArray& s); + static SafeByteArray encode(const SafeByteArray& s); + static ByteArray decode(const std::string &s); }; } diff --git a/Swiften/StringCodecs/HMAC.h b/Swiften/StringCodecs/HMAC.h new file mode 100644 index 0000000..cf0abfe --- /dev/null +++ b/Swiften/StringCodecs/HMAC.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Algorithm.h> +#include <cassert> + +namespace Swift { + namespace HMAC_Detail { + template<typename KeyType> struct KeyWrapper; + template<> struct KeyWrapper<ByteArray> { + ByteArray wrap(const ByteArray& hash) const { + return hash; + } + }; + template<> struct KeyWrapper<SafeByteArray> { + SafeByteArray wrap(const ByteArray& hash) const { + return createSafeByteArray(hash); + } + }; + + template<typename Hash, typename KeyType, int BlockSize> + static ByteArray getHMAC(const KeyType& key, const ByteArray& data) { + Hash hash; + + // Create the padded key + KeyType paddedKey(key.size() <= BlockSize ? key : KeyWrapper<KeyType>().wrap(hash(key))); + paddedKey.resize(BlockSize, 0x0); + + // Create the first value + KeyType x(paddedKey); + for (unsigned int i = 0; i < x.size(); ++i) { + x[i] ^= 0x36; + } + append(x, data); + + // Create the second value + KeyType y(paddedKey); + for (unsigned int i = 0; i < y.size(); ++i) { + y[i] ^= 0x5c; + } + append(y, hash(x)); + + return hash(y); + } + }; + + template<typename Hash, int BlockSize> + class HMAC { + private: + + public: + ByteArray operator()(const ByteArray& key, const ByteArray& data) const { + return HMAC_Detail::getHMAC<Hash,ByteArray,BlockSize>(key, data); + } + + ByteArray operator()(const SafeByteArray& key, const ByteArray& data) const { + return HMAC_Detail::getHMAC<Hash,SafeByteArray,BlockSize>(key, data); + } + }; +} diff --git a/Swiften/StringCodecs/HMACSHA1.cpp b/Swiften/StringCodecs/HMACSHA1.cpp deleted file mode 100644 index 6ae5513..0000000 --- a/Swiften/StringCodecs/HMACSHA1.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/StringCodecs/HMACSHA1.h" - -#include <cassert> - -#include "Swiften/StringCodecs/SHA1.h" -#include "Swiften/Base/ByteArray.h" - -namespace Swift { - -static const unsigned int B = 64; - -ByteArray HMACSHA1::getResult(const ByteArray& key, const ByteArray& data) { - assert(key.getSize() <= B); - - // Create the padded key - ByteArray paddedKey(key); - paddedKey.resize(B, 0x0); - - // Create the first value - ByteArray x(paddedKey); - for (unsigned int i = 0; i < x.getSize(); ++i) { - x[i] ^= 0x36; - } - x += data; - - // Create the second value - ByteArray y(paddedKey); - for (unsigned int i = 0; i < y.getSize(); ++i) { - y[i] ^= 0x5c; - } - y += SHA1::getHash(x); - - return SHA1::getHash(y); -} - -#if 0 - -// A tweaked version of HMACSHA1 that is more than twice as fast as the one above. -// After this, more than 80% is spent in SHA1. -// Optimizations: -// - Avoids using ByteArray/std::vector -// - Uses openssl's SHA1, which is slightly faster -// - Does 'xor' on word basis -// - Passes return value as a parameter - -#include <openssl/sha.h> - -void HMACSHA1::getResult(const ByteArray& key, const ByteArray& data, ByteArray& result) { - // Create first value - size_t xSize = B + data.getSize(); - unsigned char* x = (unsigned char*) malloc(xSize * sizeof(unsigned char)); - memset(x, 0, B); - memcpy(x, key.getData(), key.getSize()); - for (unsigned int i = 0; i < (B>>32); ++i) { - x[i<<32] ^= 0x36363636; - } - memcpy(x + B, data.getData(), data.getSize()); - - // Create the second value - unsigned char y[B + 20]; - memset(y, 0, B); - memcpy(y, key.getData(), key.getSize()); - for (unsigned int i = 0; i < (B>>32); ++i) { - y[i<<32] ^= 0x5c5c5c5c; - } - ::SHA1(x, xSize, y + B); - free(x); - - ::SHA1(y, B + 20, (unsigned char*) result.getData()); -} - -#endif - -} diff --git a/Swiften/StringCodecs/HMACSHA1.h b/Swiften/StringCodecs/HMAC_SHA1.h index cc6cb04..8f403c6 100644 --- a/Swiften/StringCodecs/HMACSHA1.h +++ b/Swiften/StringCodecs/HMAC_SHA1.h @@ -6,11 +6,9 @@ #pragma once -namespace Swift { - class ByteArray; +#include <Swiften/StringCodecs/HMAC.h> +#include <Swiften/StringCodecs/SHA1.h> - class HMACSHA1 { - public: - static ByteArray getResult(const ByteArray& key, const ByteArray& data); - }; +namespace Swift { + typedef HMAC<SHA1, 64> HMAC_SHA1; } diff --git a/Swiften/StringCodecs/HMAC_SHA256.h b/Swiften/StringCodecs/HMAC_SHA256.h new file mode 100644 index 0000000..2d856cb --- /dev/null +++ b/Swiften/StringCodecs/HMAC_SHA256.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/StringCodecs/HMAC.h> +#include <Swiften/StringCodecs/SHA256.h> + +namespace Swift { + typedef HMAC<SHA256, 64> HMAC_SHA256; +} diff --git a/Swiften/StringCodecs/Hexify.cpp b/Swiften/StringCodecs/Hexify.cpp index 61732b0..668079b 100644 --- a/Swiften/StringCodecs/Hexify.cpp +++ b/Swiften/StringCodecs/Hexify.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/StringCodecs/Hexify.h" +#include <Swiften/StringCodecs/Hexify.h> #include <sstream> #include <iomanip> #include <boost/numeric/conversion/cast.hpp> #include <string> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> namespace Swift { @@ -25,10 +25,28 @@ std::string Hexify::hexify(const ByteArray& data) { std::ostringstream result; result << std::hex; - for (unsigned int i = 0; i < data.getSize(); ++i) { + for (unsigned int i = 0; i < data.size(); ++i) { result << std::setw(2) << std::setfill('0') << boost::numeric_cast<unsigned int>(static_cast<unsigned char>(data[i])); } return std::string(result.str()); } +ByteArray Hexify::unhexify(const std::string& hexstring) { + if (hexstring.size() % 2) { + return ByteArray(); + } + ByteArray result = ByteArray(hexstring.size() / 2); + for (size_t pos = 0; pos < hexstring.size() - 1; pos += 2) { + char c; + c = hexstring[pos]; + int a = (c>='0'&&c<='9') ? c-'0' : (c>='A'&&c<='Z') ? c-'A' + 10 : (c>='a'&&c<='z') ? c-'a' + 10 : -1; + c = hexstring[pos+1]; + int b = (c>='0'&&c<='9') ? c-'0' : (c>='A'&&c<='Z') ? c-'A' + 10 : (c>='a'&&c<='z') ? c-'a' + 10 : -1; + if (a == -1 || b == -1) return ByteArray(); // fail + result[pos/2] = (a<<4) | b; + + } + return result; +} + } diff --git a/Swiften/StringCodecs/Hexify.h b/Swiften/StringCodecs/Hexify.h index f85db15..c016448 100644 --- a/Swiften/StringCodecs/Hexify.h +++ b/Swiften/StringCodecs/Hexify.h @@ -6,15 +6,13 @@ #pragma once -#include <string> +#include <Swiften/Base/ByteArray.h> namespace Swift { - - class ByteArray; - class Hexify { public: static std::string hexify(unsigned char byte); static std::string hexify(const ByteArray& data); + static ByteArray unhexify(const std::string& hexstring); }; } diff --git a/Swiften/StringCodecs/MD5.cpp b/Swiften/StringCodecs/MD5.cpp index 718f52e..6871f79 100644 --- a/Swiften/StringCodecs/MD5.cpp +++ b/Swiften/StringCodecs/MD5.cpp @@ -33,12 +33,13 @@ #pragma GCC diagnostic ignored "-Wold-style-cast" -#include "Swiften/StringCodecs/MD5.h" +#include <Swiften/StringCodecs/MD5.h> #include <cassert> +#include <string.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/Base/Platform.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Platform.h> namespace Swift { @@ -124,13 +125,13 @@ static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; -#ifdef SWIFTEN_BIG_ENDIAN - /* Define storage only for big-endian CPUs. */ - md5_word_t X[16]; -#else +#ifdef SWIFTEN_LITTLE_ENDIAN /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; +#else + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; #endif { @@ -350,16 +351,48 @@ md5_finish(md5_state_t *pms, md5_byte_t digest[16]) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } -ByteArray MD5::getHash(const ByteArray& data) { +namespace { + template<typename SourceType> + ByteArray getMD5Hash(const SourceType& data) { + ByteArray digest; + digest.resize(16); + + md5_state_t state; + md5_init(&state); + md5_append(&state, reinterpret_cast<const md5_byte_t*>(vecptr(data)), data.size()); + md5_finish(&state, reinterpret_cast<md5_byte_t*>(vecptr(digest))); + + return digest; + } +} + +MD5::MD5() { + state = new md5_state_t; + md5_init(state); +} + +MD5::~MD5() { + delete state; +} + +MD5& MD5::update(const std::vector<unsigned char>& input) { + md5_append(state, reinterpret_cast<const md5_byte_t*>(vecptr(input)), input.size()); + return *this; +} + +std::vector<unsigned char> MD5::getHash() { ByteArray digest; digest.resize(16); + md5_finish(state, reinterpret_cast<md5_byte_t*>(vecptr(digest))); + return digest; +} - md5_state_t state; - md5_init(&state); - md5_append(&state, reinterpret_cast<const md5_byte_t*>(data.getData()), data.getSize()); - md5_finish(&state, reinterpret_cast<md5_byte_t*>(digest.getData())); +ByteArray MD5::getHash(const ByteArray& data) { + return getMD5Hash(data); +} - return digest; +ByteArray MD5::getHash(const SafeByteArray& data) { + return getMD5Hash(data); } } diff --git a/Swiften/StringCodecs/MD5.h b/Swiften/StringCodecs/MD5.h index b896529..09473c2 100644 --- a/Swiften/StringCodecs/MD5.h +++ b/Swiften/StringCodecs/MD5.h @@ -6,11 +6,24 @@ #pragma once +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> + namespace Swift { - class ByteArray; + struct md5_state_s; class MD5 { public: + MD5(); + ~MD5(); + + MD5& update(const std::vector<unsigned char>& data); + std::vector<unsigned char> getHash(); + static ByteArray getHash(const ByteArray& data); + static ByteArray getHash(const SafeByteArray& data); + + private: + md5_state_s* state; }; } diff --git a/Swiften/StringCodecs/PBKDF2.cpp b/Swiften/StringCodecs/PBKDF2.cpp deleted file mode 100644 index a652242..0000000 --- a/Swiften/StringCodecs/PBKDF2.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/StringCodecs/PBKDF2.h" -#include "Swiften/StringCodecs/HMACSHA1.h" - -namespace Swift { - -ByteArray PBKDF2::encode(const ByteArray& password, const ByteArray& salt, int iterations) { - ByteArray u = HMACSHA1::getResult(password, salt + ByteArray("\0\0\0\1", 4)); - ByteArray result = u; - int i = 1; - while (i < iterations) { - u = HMACSHA1::getResult(password, u); - for (unsigned int j = 0; j < u.getSize(); ++j) { - result[j] ^= u[j]; - } - ++i; - } - return result; -} - -} diff --git a/Swiften/StringCodecs/PBKDF2.h b/Swiften/StringCodecs/PBKDF2.h index 7f87af7..0c04145 100644 --- a/Swiften/StringCodecs/PBKDF2.h +++ b/Swiften/StringCodecs/PBKDF2.h @@ -6,11 +6,26 @@ #pragma once -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/Base/Concat.h> namespace Swift { class PBKDF2 { public: - static ByteArray encode(const ByteArray& password, const ByteArray& salt, int iterations); + template<typename PRF> + static ByteArray encode(const SafeByteArray& password, const ByteArray& salt, int iterations) { + PRF prf; + ByteArray u = prf(password, concat(salt, createByteArray("\0\0\0\1", 4))); + ByteArray result(u); + int i = 1; + while (i < iterations) { + u = prf(password, u); + for (unsigned int j = 0; j < u.size(); ++j) { + result[j] ^= u[j]; + } + ++i; + } + return result; + } }; } diff --git a/Swiften/StringCodecs/SHA1.cpp b/Swiften/StringCodecs/SHA1.cpp index 9882f70..e4081f4 100644 --- a/Swiften/StringCodecs/SHA1.cpp +++ b/Swiften/StringCodecs/SHA1.cpp @@ -4,10 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/Platform.h" +#include <Swiften/StringCodecs/SHA1.h> + +#include <Swiften/Base/Platform.h> #pragma GCC diagnostic ignored "-Wold-style-cast" +using namespace Swift; + /* SHA-1 in C By Steve Reid <steve@edmweb.com> @@ -25,21 +29,9 @@ A million repetitions of "a" /* #define LITTLE_ENDIAN * This should be #define'd if true. */ /* #define SHA1HANDSOFF * Copies data before messing with it. */ -#include <boost/cstdint.hpp> #include <stdio.h> #include <string.h> -typedef struct { - boost::uint32_t state[5]; - boost::uint32_t count[2]; - boost::uint8_t buffer[64]; -} SHA1_CTX; - -void SHA1Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]); -void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len); -void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context); - #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) /* blk0() and blk() perform the initial expand. */ @@ -63,7 +55,7 @@ void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context); /* Hash a single 512-bit block. This is the core of the algorithm. */ -void SHA1Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) +void SHA1::Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]) { boost::uint32_t a, b, c, d, e; typedef union { @@ -118,7 +110,7 @@ static boost::uint8_t workspace[64]; /* SHA1Init - Initialize new context */ -void SHA1Init(SHA1_CTX* context) +void SHA1::Init(SHA1::CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; @@ -132,7 +124,7 @@ void SHA1Init(SHA1_CTX* context) /* Run your data through this. */ -void SHA1Update(SHA1_CTX* context, boost::uint8_t* data, unsigned int len) +void SHA1::Update(SHA1::CTX* context, boost::uint8_t* data, unsigned int len) { unsigned int i, j; @@ -141,9 +133,9 @@ unsigned int i, j; context->count[1] += (len >> 29); if ((j + len) > 63) { memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); + Transform(context->state, context->buffer); for ( ; i + 63 < len; i += 64) { - SHA1Transform(context->state, &data[i]); + Transform(context->state, &data[i]); } j = 0; } @@ -154,7 +146,7 @@ unsigned int i, j; /* Add padding and return the message digest. */ -void SHA1Final(boost::uint8_t digest[20], SHA1_CTX* context) +void SHA1::Final(boost::uint8_t digest[20], SHA1::CTX* context) { boost::uint32_t i, j; boost::uint8_t finalcount[8]; @@ -163,11 +155,11 @@ boost::uint8_t finalcount[8]; finalcount[i] = (boost::uint8_t) ((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ } - SHA1Update(context, (boost::uint8_t *)("\200"), 1); + Update(context, (boost::uint8_t *)("\200"), 1); while ((context->count[0] & 504) != 448) { - SHA1Update(context, (boost::uint8_t *)("\0"), 1); + Update(context, (boost::uint8_t *)("\0"), 1); } - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ for (i = 0; i < 20; i++) { digest[i] = (boost::uint8_t) ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); @@ -179,25 +171,54 @@ boost::uint8_t finalcount[8]; memset(context->count, 0, 8); memset(&finalcount, 0, 8); #ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */ - SHA1Transform(context->state, context->buffer); + Transform(context->state, context->buffer); #endif } // ----------------------------------------------------------------------------- -#include "Swiften/StringCodecs/SHA1.h" - namespace Swift { -ByteArray SHA1::getHash(const ByteArray& input) { - ByteArray inputCopy(input); +SHA1::SHA1() { + Init(&context); +} + +SHA1& SHA1::update(const std::vector<unsigned char>& input) { + std::vector<unsigned char> inputCopy(input); + Update(&context, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); + return *this; +} + +std::vector<unsigned char> SHA1::getHash() const { + std::vector<unsigned char> digest; + digest.resize(20); + CTX contextCopy(context); + Final((boost::uint8_t*) vecptr(digest), &contextCopy); + return digest; +} + +template<typename Container> +ByteArray SHA1::getHashInternal(const Container& input) { + CTX context; + Init(&context); + + Container inputCopy(input); + Update(&context, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); + ByteArray digest; digest.resize(20); - SHA1_CTX context; - SHA1Init(&context); - SHA1Update(&context, (boost::uint8_t*) inputCopy.getData(), inputCopy.getSize()); - SHA1Final((boost::uint8_t*) digest.getData(), &context); + Final((boost::uint8_t*) vecptr(digest), &context); + return digest; } +ByteArray SHA1::getHash(const ByteArray& input) { + return getHashInternal(input); +} + +ByteArray SHA1::getHash(const SafeByteArray& input) { + return getHashInternal(input); +} + + } diff --git a/Swiften/StringCodecs/SHA1.h b/Swiften/StringCodecs/SHA1.h index fc5ba0e..19488cb 100644 --- a/Swiften/StringCodecs/SHA1.h +++ b/Swiften/StringCodecs/SHA1.h @@ -6,11 +6,50 @@ #pragma once -#include "Swiften/Base/ByteArray.h" +#include <vector> +#include <boost/cstdint.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class SHA1 { public: + SHA1(); + + SHA1& update(const std::vector<unsigned char>& data); + std::vector<unsigned char> getHash() const; + + /** + * Equivalent of: + * SHA1().update(data),getHash(), but slightly more efficient and + * convenient. + */ static ByteArray getHash(const ByteArray& data); + static ByteArray getHash(const SafeByteArray& data); + + ByteArray operator()(const SafeByteArray& data) { + return getHash(data); + } + + ByteArray operator()(const ByteArray& data) { + return getHash(data); + } + + private: + typedef struct { + boost::uint32_t state[5]; + boost::uint32_t count[2]; + boost::uint8_t buffer[64]; + } CTX; + static void Init(CTX* context); + static void Transform(boost::uint32_t state[5], boost::uint8_t buffer[64]); + static void Update(CTX* context, boost::uint8_t* data, unsigned int len); + static void Final(boost::uint8_t digest[20], CTX* context); + + template<typename Container> static ByteArray getHashInternal(const Container& input); + + private: + CTX context; }; } diff --git a/Swiften/StringCodecs/SHA256.cpp b/Swiften/StringCodecs/SHA256.cpp new file mode 100644 index 0000000..f92e7af --- /dev/null +++ b/Swiften/StringCodecs/SHA256.cpp @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2011 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/StringCodecs/SHA256.h> + +#include <cassert> +#include <algorithm> +#include <string.h> + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +using namespace Swift; + +// Copied & adapted from LibTomCrypt, by Tom St Denis, tomstdenis@gmail.com, http://libtom.org +// Substituted some macros by the platform-independent (slower) variants + +#include <stdlib.h> + +#define CRYPT_OK 0 +#define CRYPT_INVALID_ARG -1 +#define LTC_ARGCHK assert + +#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) +#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) + +#define LOAD32H(x, y) \ + { x = ((unsigned long)((y)[0] & 255)<<24) | \ + ((unsigned long)((y)[1] & 255)<<16) | \ + ((unsigned long)((y)[2] & 255)<<8) | \ + ((unsigned long)((y)[3] & 255)); } + +#define STORE32H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ + (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } + +#define STORE64H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } + +/* a simple macro for making hash "process" functions */ +#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \ +int func_name (State * md, const unsigned char *in, unsigned int inlen) \ +{ \ + unsigned long n; \ + int err; \ + LTC_ARGCHK(md != NULL); \ + LTC_ARGCHK(in != NULL || inlen == 0); \ + if (md-> curlen > sizeof(md->buf)) { \ + return CRYPT_INVALID_ARG; \ + } \ + while (inlen > 0) { \ + if (md->curlen == 0 && inlen >= block_size) { \ + if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) { \ + return err; \ + } \ + md-> length += block_size * 8; \ + in += block_size; \ + inlen -= block_size; \ + } else { \ + n = std::min(inlen, (block_size - md-> curlen)); \ + memcpy(md-> buf + md-> curlen, in, (size_t)n); \ + md-> curlen += n; \ + in += n; \ + inlen -= n; \ + if (md-> curlen == block_size) { \ + if ((err = compress_name (md, md-> buf)) != CRYPT_OK) { \ + return err; \ + } \ + md-> length += 8*block_size; \ + md-> curlen = 0; \ + } \ + } \ + } \ + return CRYPT_OK; \ +} + +#ifdef LTC_SMALL_CODE +/* the K array */ +static const boost::uint32_t K[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL +}; +#endif + +/* Various logical functions */ +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + +#ifdef LTC_CLEAN_STACK +int SHA256::_compress(State * md, unsigned char *buf) +#else +int SHA256::compress(State * md, unsigned char *buf) +#endif +{ + boost::uint32_t S[8], W[64], t0, t1; +#ifdef LTC_SMALL_CODE + boost::uint32_t t; +#endif + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 512-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD32H(W[i], buf + (4*i)); + } + + /* fill W[16..63] */ + for (i = 16; i < 64; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + + /* Compress */ +#ifdef LTC_SMALL_CODE +#define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 64; ++i) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i); + t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; + S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t; + } +#else +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + +#endif + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + return CRYPT_OK; +} + +#ifdef LTC_CLEAN_STACK +int SHA256::compress(State * md, unsigned char *buf) +{ + int err; + err = SHA256::_compress(md, buf); + burn_stack(sizeof(boost::uint32_t) * 74); + return err; +} +#endif + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return CRYPT_OK if successful +*/ +int SHA256::init(State * md) +{ + LTC_ARGCHK(md != NULL); + + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; + return CRYPT_OK; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return CRYPT_OK if successful +*/ +HASH_PROCESS(SHA256::process, SHA256::compress, sha256, 64) + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (32 bytes) + @return CRYPT_OK if successful +*/ +int SHA256::done(State * md, unsigned char *out) +{ + int i; + + LTC_ARGCHK(md != NULL); + LTC_ARGCHK(out != NULL); + + if (md->curlen >= sizeof(md->buf)) { + return CRYPT_INVALID_ARG; + } + + + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < 64) { + md->buf[md->curlen++] = (unsigned char)0; + } + SHA256::compress(md, md->buf); + md->curlen = 0; + } + + /* pad upto 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->length, md->buf+56); + SHA256::compress(md, md->buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE32H(md->state[i], out+(4*i)); + } +#ifdef LTC_CLEAN_STACK + zeromem(md, sizeof(State)); +#endif + return CRYPT_OK; +} + +// End copied code + +namespace Swift { + +SHA256::SHA256() { + init(&state); +} + +SHA256& SHA256::update(const std::vector<unsigned char>& input) { + std::vector<unsigned char> inputCopy(input); + process(&state, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); + return *this; +} + +std::vector<unsigned char> SHA256::getHash() const { + std::vector<unsigned char> digest; + digest.resize(256/8); + State contextCopy(state); + done(&contextCopy, (boost::uint8_t*) vecptr(digest)); + return digest; +} + +template<typename Container> +ByteArray SHA256::getHashInternal(const Container& input) { + State context; + init(&context); + + Container inputCopy(input); + process(&context, (boost::uint8_t*) vecptr(inputCopy), inputCopy.size()); + + ByteArray digest; + digest.resize(256/8); + done(&context, (boost::uint8_t*) vecptr(digest)); + + return digest; +} + +ByteArray SHA256::getHash(const ByteArray& input) { + return getHashInternal(input); +} + +ByteArray SHA256::getHash(const SafeByteArray& input) { + return getHashInternal(input); +} + +} diff --git a/Swiften/StringCodecs/SHA256.h b/Swiften/StringCodecs/SHA256.h new file mode 100644 index 0000000..28a0e05 --- /dev/null +++ b/Swiften/StringCodecs/SHA256.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <boost/cstdint.hpp> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/SafeByteArray.h> + +namespace Swift { + class SHA256 { + public: + SHA256(); + + SHA256& update(const std::vector<unsigned char>& data); + std::vector<unsigned char> getHash() const; + + /** + * Equivalent of: + * SHA256().update(data),getHash(), but slightly more efficient and + * convenient. + */ + static ByteArray getHash(const ByteArray& data); + static ByteArray getHash(const SafeByteArray& data); + + ByteArray operator()(const SafeByteArray& data) { + return getHash(data); + } + + ByteArray operator()(const ByteArray& data) { + return getHash(data); + } + + private: + struct State { + boost::uint64_t length; + boost::uint32_t state[8], curlen; + unsigned char buf[64]; + }; + + static int init(State *md); + static int process(State * md, const unsigned char *in, unsigned int inlen); + static int compress(State *md, unsigned char *buf); + static int done(State * md, unsigned char *out); + + template<typename Container> static ByteArray getHashInternal(const Container& input); + + private: + State state; + }; +} diff --git a/Swiften/StringCodecs/UnitTest/Base64Test.cpp b/Swiften/StringCodecs/UnitTest/Base64Test.cpp index b263050..f6a424b 100644 --- a/Swiften/StringCodecs/UnitTest/Base64Test.cpp +++ b/Swiften/StringCodecs/UnitTest/Base64Test.cpp @@ -4,12 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/StringCodecs/Base64.h" +#include <Swiften/StringCodecs/Base64.h> using namespace Swift; @@ -24,12 +25,12 @@ class Base64Test : public CppUnit::TestFixture { public: void testEncode() { - std::string result(Base64::encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890")); + std::string result(Base64::encode(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"))); CPPUNIT_ASSERT_EQUAL(std::string("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA="), result); } void testEncode_NonAscii() { - std::string result(Base64::encode(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"))); + std::string result(Base64::encode(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"))); CPPUNIT_ASSERT_EQUAL(std::string("QgayPKawpkPSDYmwT/WM94uAlu0="), result); } @@ -40,7 +41,7 @@ class Base64Test : public CppUnit::TestFixture { void testDecode() { ByteArray result(Base64::decode("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejEyMzQ1Njc4OTA=")); - CPPUNIT_ASSERT_EQUAL(ByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"), result); } void testDecode_NoData() { diff --git a/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp b/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp deleted file mode 100644 index 44bd5b7..0000000 --- a/Swiften/StringCodecs/UnitTest/HMACSHA1Test.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#include "Swiften/Base/ByteArray.h" - -#include <cppunit/extensions/HelperMacros.h> -#include <cppunit/extensions/TestFactoryRegistry.h> - -#include "Swiften/Base/ByteArray.h" -#include "Swiften/StringCodecs/HMACSHA1.h" - -using namespace Swift; - -class HMACSHA1Test : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(HMACSHA1Test); - CPPUNIT_TEST(testGetResult); - CPPUNIT_TEST_SUITE_END(); - - public: - void testGetResult() { - ByteArray result(HMACSHA1::getResult("foo", "foobar")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\xa4\xee\xba\x8e\x63\x3d\x77\x88\x69\xf5\x68\xd0\x5a\x1b\x3d\xc7\x2b\xfd\x4\xdd"), result); - } -}; - -CPPUNIT_TEST_SUITE_REGISTRATION(HMACSHA1Test); diff --git a/Swiften/StringCodecs/UnitTest/HMACTest.cpp b/Swiften/StringCodecs/UnitTest/HMACTest.cpp new file mode 100644 index 0000000..50b1330 --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/HMACTest.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/StringCodecs/HMAC_SHA1.h> +#include <Swiften/StringCodecs/HMAC_SHA256.h> + +using namespace Swift; + +class HMACTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(HMACTest); + CPPUNIT_TEST(testGetResult); + CPPUNIT_TEST(testGetResult_KeyLongerThanBlockSize); + CPPUNIT_TEST(testGetResult_RFC4231_1); + CPPUNIT_TEST(testGetResult_RFC4231_7); + CPPUNIT_TEST_SUITE_END(); + + public: + void testGetResult() { + ByteArray result(HMAC_SHA1()(createSafeByteArray("foo"), createByteArray("foobar"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xa4\xee\xba\x8e\x63\x3d\x77\x88\x69\xf5\x68\xd0\x5a\x1b\x3d\xc7\x2b\xfd\x4\xdd"), result); + } + + void testGetResult_KeyLongerThanBlockSize() { + ByteArray result(HMAC_SHA1()(createSafeByteArray("---------|---------|---------|---------|---------|----------|---------|"), createByteArray("foobar"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xd6""n""\x8f""P|1""\xd3"",""\x6"" ""\xb9\xe3""gg""\x8e\xcf"" ]+""\xa"), result); + } + + void testGetResult_RFC4231_1() { + ByteArray result(HMAC_SHA256()(createSafeByteArray("\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 20), createByteArray("Hi There"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xb0\x34\x4c\x61\xd8\xdb\x38\x53\x5c\xa8\xaf\xce\xaf\x0b\xf1\x2b\x88\x1d\xc2\x00\xc9\x83\x3d\xa7\x26\xe9\x37\x6c\x2e\x32\xcf\xf7", 32), result); + } + + void testGetResult_RFC4231_7() { + ByteArray result(HMAC_SHA256()(createSafeByteArray("\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", 131), createByteArray("This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm."))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x9b\x09\xff\xa7\x1b\x94\x2f\xcb\x27\x63\x5f\xbc\xd5\xb0\xe9\x44\xbf\xdc\x63\x64\x4f\x07\x13\x93\x8a\x7f\x51\x53\x5c\x3a\x35\xe2", 32), result); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(HMACTest); diff --git a/Swiften/StringCodecs/UnitTest/HexifyTest.cpp b/Swiften/StringCodecs/UnitTest/HexifyTest.cpp index 0f267bf..38233f9 100644 --- a/Swiften/StringCodecs/UnitTest/HexifyTest.cpp +++ b/Swiften/StringCodecs/UnitTest/HexifyTest.cpp @@ -7,9 +7,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/StringCodecs/Hexify.h" +#include <Swiften/StringCodecs/Hexify.h> #include <string> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -17,16 +17,22 @@ class HexifyTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(HexifyTest); CPPUNIT_TEST(testHexify); CPPUNIT_TEST(testHexify_Byte); + CPPUNIT_TEST(testUnhexify); CPPUNIT_TEST_SUITE_END(); public: void testHexify() { - CPPUNIT_ASSERT_EQUAL(std::string("4206b23ca6b0a643d20d89b04ff58cf78b8096ed"), Hexify::hexify(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"))); + CPPUNIT_ASSERT_EQUAL(std::string("4206b23ca6b0a643d20d89b04ff58cf78b8096ed"), Hexify::hexify(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"))); } void testHexify_Byte() { CPPUNIT_ASSERT_EQUAL(std::string("b2"), Hexify::hexify(0xb2)); } + + void testUnhexify() { + CPPUNIT_ASSERT_EQUAL(std::string("ffaf02"), Hexify::hexify(Hexify::unhexify("ffaf02"))); + CPPUNIT_ASSERT(createByteArray("\x01\x23\xf2", 3) == Hexify::unhexify("0123f2")); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(HexifyTest); diff --git a/Swiften/StringCodecs/UnitTest/MD5Test.cpp b/Swiften/StringCodecs/UnitTest/MD5Test.cpp index b76af48..c62c46a 100644 --- a/Swiften/StringCodecs/UnitTest/MD5Test.cpp +++ b/Swiften/StringCodecs/UnitTest/MD5Test.cpp @@ -4,13 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/StringCodecs/MD5.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/StringCodecs/MD5.h> +#include <Swiften/Base/ByteArray.h> using namespace Swift; @@ -18,19 +19,30 @@ class MD5Test : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(MD5Test); CPPUNIT_TEST(testGetHash_Empty); CPPUNIT_TEST(testGetHash_Alphabet); + CPPUNIT_TEST(testIncrementalTest); CPPUNIT_TEST_SUITE_END(); public: void testGetHash_Empty() { - ByteArray result(MD5::getHash("")); + ByteArray result(MD5::getHash(createByteArray(""))); - CPPUNIT_ASSERT_EQUAL(ByteArray("\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e", 16), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e", 16), result); } void testGetHash_Alphabet() { - ByteArray result(MD5::getHash("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")); + ByteArray result(MD5::getHash(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"))); - CPPUNIT_ASSERT_EQUAL(ByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result); + } + + void testIncrementalTest() { + MD5 testling; + testling.update(createByteArray("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + testling.update(createByteArray("abcdefghijklmnopqrstuvwxyz0123456789")); + + ByteArray result = testling.getHash(); + + CPPUNIT_ASSERT_EQUAL(createByteArray("\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f", 16), result); } }; diff --git a/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp b/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp index 092fe31..608ca62 100644 --- a/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp +++ b/Swiften/StringCodecs/UnitTest/PBKDF2Test.cpp @@ -4,13 +4,15 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/StringCodecs/PBKDF2.h" +#include <Swiften/Base/ByteArray.h> +#include <Swiften/StringCodecs/PBKDF2.h> +#include <Swiften/StringCodecs/HMAC_SHA1.h> using namespace Swift; @@ -23,21 +25,21 @@ class PBKDF2Test : public CppUnit::TestFixture { public: void testGetResult_I1() { - ByteArray result(PBKDF2::encode("password", "salt", 1)); + ByteArray result(PBKDF2::encode<HMAC_SHA1 >(createSafeByteArray("password"), createByteArray("salt"), 1)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6"), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x0c\x60\xc8\x0f\x96\x1f\x0e\x71\xf3\xa9\xb5\x24\xaf\x60\x12\x06\x2f\xe0\x37\xa6"), result); } void testGetResult_I2() { - ByteArray result(PBKDF2::encode("password", "salt", 2)); + ByteArray result(PBKDF2::encode<HMAC_SHA1 >(createSafeByteArray("password"), createByteArray("salt"), 2)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\xea\x6c\x1\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57"), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xea\x6c\x1\x4d\xc7\x2d\x6f\x8c\xcd\x1e\xd9\x2a\xce\x1d\x41\xf0\xd8\xde\x89\x57"), result); } void testGetResult_I4096() { - ByteArray result(PBKDF2::encode("password", "salt", 4096)); + ByteArray result(PBKDF2::encode<HMAC_SHA1 >(createSafeByteArray("password"), createByteArray("salt"), 4096)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x4b\x00\x79\x1\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x4b\x00\x79\x1\xb7\x65\x48\x9a\xbe\xad\x49\xd9\x26\xf7\x21\xd0\x65\xa4\x29\xc1", 20), result); } }; diff --git a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp index 9434235..bdccb1c 100644 --- a/Swiften/StringCodecs/UnitTest/SHA1Test.cpp +++ b/Swiften/StringCodecs/UnitTest/SHA1Test.cpp @@ -4,41 +4,89 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> -#include "Swiften/StringCodecs/SHA1.h" +#include <Swiften/StringCodecs/SHA1.h> using namespace Swift; class SHA1Test : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(SHA1Test); CPPUNIT_TEST(testGetHash); - CPPUNIT_TEST(testGetHash_Twice); + CPPUNIT_TEST(testGetHash_TwoUpdates); + CPPUNIT_TEST(testGetHash_TwoGetHash); CPPUNIT_TEST(testGetHash_NoData); + CPPUNIT_TEST(testGetHash_InterleavedUpdate); + CPPUNIT_TEST(testGetHashStatic); + CPPUNIT_TEST(testGetHashStatic_Twice); + CPPUNIT_TEST(testGetHashStatic_NoData); CPPUNIT_TEST_SUITE_END(); public: void testGetHash() { - ByteArray result(SHA1::getHash("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); + SHA1 sha; + sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + void testGetHash_TwoUpdates() { + SHA1 sha; + sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); + sha.update(createByteArray("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + void testGetHash_TwoGetHash() { + SHA1 sha; + sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + sha.getHash(); + + CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + void testGetHash_InterleavedUpdate() { + SHA1 sha; + + sha.update(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<")); + sha.getHash(); + sha.update(createByteArray("http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); + + CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), sha.getHash()); + } + + + void testGetHash_NoData() { + SHA1 sha; + sha.update(std::vector<unsigned char>()); + + CPPUNIT_ASSERT_EQUAL(createByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), sha.getHash()); } + void testGetHashStatic() { + ByteArray result(SHA1::getHash(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); + } - void testGetHash_Twice() { - ByteArray input("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<"); + + void testGetHashStatic_Twice() { + ByteArray input(createByteArray("client/pc//Exodus 0.9.1<http://jabber.org/protocol/caps<http://jabber.org/protocol/disco#info<http://jabber.org/protocol/disco#items<http://jabber.org/protocol/muc<")); SHA1::getHash(input); ByteArray result(SHA1::getHash(input)); - CPPUNIT_ASSERT_EQUAL(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed"), result); } - void testGetHash_NoData() { + void testGetHashStatic_NoData() { ByteArray result(SHA1::getHash(ByteArray())); - CPPUNIT_ASSERT_EQUAL(ByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), result); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xda\x39\xa3\xee\x5e\x6b\x4b\x0d\x32\x55\xbf\xef\x95\x60\x18\x90\xaf\xd8\x07\x09"), result); } }; diff --git a/Swiften/StringCodecs/UnitTest/SHA256Test.cpp b/Swiften/StringCodecs/UnitTest/SHA256Test.cpp new file mode 100644 index 0000000..5bcdd11 --- /dev/null +++ b/Swiften/StringCodecs/UnitTest/SHA256Test.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swiften/Base/ByteArray.h> +#include <QA/Checker/IO.h> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/StringCodecs/SHA256.h> + +using namespace Swift; + +class SHA256Test : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(SHA256Test); + CPPUNIT_TEST(testGetHashStatic_Empty); + CPPUNIT_TEST(testGetHashStatic_Small); + CPPUNIT_TEST(testGetHashStatic_Large); + CPPUNIT_TEST_SUITE_END(); + + public: + void testGetHashStatic_Empty() { + ByteArray result(SHA256::getHash(createByteArray(""))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xe3\xb0\xc4" "B" "\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99" "o" "\xb9" "$'" "\xae" "A" "\xe4" "d" "\x9b\x93" "L" "\xa4\x95\x99\x1b" "xR" "\xb8" "U", 32), result); + } + + void testGetHashStatic_Small() { + ByteArray result(SHA256::getHash(createByteArray("abc"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\xba\x78\x16\xbf\x8f\x01\xcf\xea\x41\x41\x40\xde\x5d\xae\x22\x23\xb0\x03\x61\xa3\x96\x17\x7a\x9c\xb4\x10\xff\x61\xf2\x00\x15\xad", 32), result); + } + + void testGetHashStatic_Large() { + ByteArray result(SHA256::getHash(createByteArray("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"))); + CPPUNIT_ASSERT_EQUAL(createByteArray("\x24\x8d\x6a\x61\xd2\x06\x38\xb8\xe5\xc0\x26\x93\x0c\x3e\x60\x39\xa3\x3c\xe4\x59\x64\xff\x21\x67\xf6\xec\xed\xd4\x19\xdb\x06\xc1", 32), result); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SHA256Test); diff --git a/Swiften/TLS/BlindCertificateTrustChecker.h b/Swiften/TLS/BlindCertificateTrustChecker.h index d9db14c..3177322 100644 --- a/Swiften/TLS/BlindCertificateTrustChecker.h +++ b/Swiften/TLS/BlindCertificateTrustChecker.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/TLS/CertificateTrustChecker.h" +#include <Swiften/TLS/CertificateTrustChecker.h> namespace Swift { /** diff --git a/Swiften/TLS/Certificate.cpp b/Swiften/TLS/Certificate.cpp index ecd7d5e..a796463 100644 --- a/Swiften/TLS/Certificate.cpp +++ b/Swiften/TLS/Certificate.cpp @@ -22,7 +22,7 @@ Certificate::~Certificate() { std::string Certificate::getSHA1Fingerprint() const { ByteArray hash = SHA1::getHash(toDER()); std::ostringstream s; - for (size_t i = 0; i < hash.getSize(); ++i) { + for (size_t i = 0; i < hash.size(); ++i) { if (i > 0) { s << ":"; } diff --git a/Swiften/TLS/Certificate.h b/Swiften/TLS/Certificate.h index dc93a2d..ec59a39 100644 --- a/Swiften/TLS/Certificate.h +++ b/Swiften/TLS/Certificate.h @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> namespace Swift { class Certificate { diff --git a/Swiften/TLS/CertificateFactory.cpp b/Swiften/TLS/CertificateFactory.cpp index b2edaf4..df01090 100644 --- a/Swiften/TLS/CertificateFactory.cpp +++ b/Swiften/TLS/CertificateFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/CertificateFactory.h" +#include <Swiften/TLS/CertificateFactory.h> namespace Swift { diff --git a/Swiften/TLS/CertificateFactory.h b/Swiften/TLS/CertificateFactory.h index 90eca58..3e94082 100644 --- a/Swiften/TLS/CertificateFactory.h +++ b/Swiften/TLS/CertificateFactory.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/TLS/Certificate.h" +#include <Swiften/TLS/Certificate.h> namespace Swift { class CertificateFactory { diff --git a/Swiften/TLS/CertificateTrustChecker.cpp b/Swiften/TLS/CertificateTrustChecker.cpp index f4f921d..42e24a1 100644 --- a/Swiften/TLS/CertificateTrustChecker.cpp +++ b/Swiften/TLS/CertificateTrustChecker.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/CertificateTrustChecker.h" +#include <Swiften/TLS/CertificateTrustChecker.h> namespace Swift { diff --git a/Swiften/TLS/CertificateTrustChecker.h b/Swiften/TLS/CertificateTrustChecker.h index aec03e3..06c0c32 100644 --- a/Swiften/TLS/CertificateTrustChecker.h +++ b/Swiften/TLS/CertificateTrustChecker.h @@ -9,7 +9,7 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/TLS/Certificate.h" +#include <Swiften/TLS/Certificate.h> namespace Swift { /** diff --git a/Swiften/TLS/CertificateVerificationError.h b/Swiften/TLS/CertificateVerificationError.h index 554fd3b..2815fdb 100644 --- a/Swiften/TLS/CertificateVerificationError.h +++ b/Swiften/TLS/CertificateVerificationError.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/Base/Error.h" +#include <Swiften/Base/Error.h> namespace Swift { class CertificateVerificationError : public Error { diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp index 0b2df5b..06ce360 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.cpp @@ -23,11 +23,11 @@ OpenSSLCertificate::OpenSSLCertificate(boost::shared_ptr<X509> cert) : cert(cert OpenSSLCertificate::OpenSSLCertificate(const ByteArray& der) { #if OPENSSL_VERSION_NUMBER <= 0x009070cfL - unsigned char* p = const_cast<unsigned char*>(der.getData()); + unsigned char* p = const_cast<unsigned char*>(vecptr(der)); #else - const unsigned char* p = der.getData(); + const unsigned char* p = vecptr(der); #endif - cert = boost::shared_ptr<X509>(d2i_X509(NULL, &p, der.getSize()), X509_free); + cert = boost::shared_ptr<X509>(d2i_X509(NULL, &p, der.size()), X509_free); if (!cert) { SWIFT_LOG(warning) << "Error creating certificate from DER data" << std::endl; } @@ -41,7 +41,7 @@ ByteArray OpenSSLCertificate::toDER() const { ByteArray result; result.resize(i2d_X509(cert.get(), NULL)); - unsigned char* p = reinterpret_cast<unsigned char*>(result.getData()); + unsigned char* p = vecptr(result); i2d_X509(cert.get(), &p); return result; } @@ -57,15 +57,15 @@ void OpenSSLCertificate::parse() { // Subject name ByteArray subjectNameData; subjectNameData.resize(256); - X509_NAME_oneline(X509_get_subject_name(cert.get()), reinterpret_cast<char*>(subjectNameData.getData()), subjectNameData.getSize()); - this->subjectName = std::string(reinterpret_cast<const char*>(subjectNameData.getData())); + X509_NAME_oneline(X509_get_subject_name(cert.get()), reinterpret_cast<char*>(vecptr(subjectNameData)), subjectNameData.size()); + this->subjectName = byteArrayToString(subjectNameData); // Common name int cnLoc = X509_NAME_get_index_by_NID(subjectName, NID_commonName, -1); while (cnLoc != -1) { X509_NAME_ENTRY* cnEntry = X509_NAME_get_entry(subjectName, cnLoc); ASN1_STRING* cnData = X509_NAME_ENTRY_get_data(cnEntry); - commonNames.push_back(ByteArray(cnData->data, cnData->length).toString()); + commonNames.push_back(byteArrayToString(createByteArray(reinterpret_cast<const char*>(cnData->data), cnData->length))); cnLoc = X509_NAME_get_index_by_NID(subjectName, NID_commonName, cnLoc); } } @@ -87,7 +87,7 @@ void OpenSSLCertificate::parse() { continue; } ASN1_UTF8STRING* xmppAddrValue = otherName->value->value.utf8string; - addXMPPAddress(ByteArray(ASN1_STRING_data(xmppAddrValue), ASN1_STRING_length(xmppAddrValue)).toString()); + addXMPPAddress(byteArrayToString(createByteArray(reinterpret_cast<const char*>(ASN1_STRING_data(xmppAddrValue)), ASN1_STRING_length(xmppAddrValue)))); } else if (OBJ_cmp(otherName->type_id, dnsSRVObject.get()) == 0) { // SRVName @@ -95,12 +95,12 @@ void OpenSSLCertificate::parse() { continue; } ASN1_IA5STRING* srvNameValue = otherName->value->value.ia5string; - addSRVName(ByteArray(ASN1_STRING_data(srvNameValue), ASN1_STRING_length(srvNameValue)).toString()); + addSRVName(byteArrayToString(createByteArray(reinterpret_cast<const char*>(ASN1_STRING_data(srvNameValue)), ASN1_STRING_length(srvNameValue)))); } } else if (generalName->type == GEN_DNS) { // DNSName - addDNSName(ByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)).toString()); + addDNSName(byteArrayToString(createByteArray(ASN1_STRING_data(generalName->d.dNSName), ASN1_STRING_length(generalName->d.dNSName)))); } } } diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h index b900170..897b432 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificate.h +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificate.h @@ -10,7 +10,7 @@ #include <openssl/ssl.h> #include <string> -#include "Swiften/TLS/Certificate.h" +#include <Swiften/TLS/Certificate.h> namespace Swift { class OpenSSLCertificate : public Certificate { diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h index cd4982e..52f134c 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/TLS/CertificateFactory.h" -#include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h" +#include <Swiften/TLS/CertificateFactory.h> +#include <Swiften/TLS/OpenSSL/OpenSSLCertificate.h> namespace Swift { class OpenSSLCertificateFactory : public CertificateFactory { diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp index 378b6aa..220e7f9 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.cpp @@ -3,7 +3,7 @@ * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/Platform.h" +#include <Swiften/Base/Platform.h> #ifdef SWIFTEN_PLATFORM_WINDOWS #include <windows.h> @@ -13,14 +13,15 @@ #include <vector> #include <openssl/err.h> #include <openssl/pkcs12.h> +#include <boost/smart_ptr/make_shared.hpp> #if defined(SWIFTEN_PLATFORM_MACOSX) && OPENSSL_VERSION_NUMBER < 0x00908000 #include <Security/Security.h> #endif -#include "Swiften/TLS/OpenSSL/OpenSSLContext.h" -#include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h" -#include "Swiften/TLS/PKCS12Certificate.h" +#include <Swiften/TLS/OpenSSL/OpenSSLContext.h> +#include <Swiften/TLS/OpenSSL/OpenSSLCertificate.h> +#include <Swiften/TLS/PKCS12Certificate.h> #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -48,8 +49,7 @@ OpenSSLContext::OpenSSLContext() : state_(Start), context_(0), handle_(0), readB if (!certContext) { break; } - ByteArray certData(certContext->pbCertEncoded, certContext->cbCertEncoded); - OpenSSLCertificate cert(certData); + OpenSSLCertificate cert(createByteArray(certContext->pbCertEncoded, certContext->cbCertEncoded)); if (store && cert.getInternalX509()) { X509_STORE_add_cert(store, cert.getInternalX509().get()); } @@ -138,15 +138,15 @@ void OpenSSLContext::doConnect() { void OpenSSLContext::sendPendingDataToNetwork() { int size = BIO_pending(writeBIO_); if (size > 0) { - ByteArray data; + SafeByteArray data; data.resize(size); - BIO_read(writeBIO_, data.getData(), size); + BIO_read(writeBIO_, vecptr(data), size); onDataForNetwork(data); } } -void OpenSSLContext::handleDataFromNetwork(const ByteArray& data) { - BIO_write(readBIO_, data.getData(), data.getSize()); +void OpenSSLContext::handleDataFromNetwork(const SafeByteArray& data) { + BIO_write(readBIO_, vecptr(data), data.size()); switch (state_) { case Connecting: doConnect(); @@ -159,8 +159,8 @@ void OpenSSLContext::handleDataFromNetwork(const ByteArray& data) { } } -void OpenSSLContext::handleDataFromApplication(const ByteArray& data) { - if (SSL_write(handle_, data.getData(), data.getSize()) >= 0) { +void OpenSSLContext::handleDataFromApplication(const SafeByteArray& data) { + if (SSL_write(handle_, vecptr(data), data.size()) >= 0) { sendPendingDataToNetwork(); } else { @@ -170,14 +170,14 @@ void OpenSSLContext::handleDataFromApplication(const ByteArray& data) { } void OpenSSLContext::sendPendingDataToApplication() { - ByteArray data; + SafeByteArray data; data.resize(SSL_READ_BUFFERSIZE); - int ret = SSL_read(handle_, data.getData(), data.getSize()); + int ret = SSL_read(handle_, vecptr(data), data.size()); while (ret > 0) { data.resize(ret); onDataForApplication(data); data.resize(SSL_READ_BUFFERSIZE); - ret = SSL_read(handle_, data.getData(), data.getSize()); + ret = SSL_read(handle_, vecptr(data), data.size()); } if (ret < 0 && SSL_get_error(handle_, ret) != SSL_ERROR_WANT_READ) { state_ = Error; @@ -192,7 +192,7 @@ bool OpenSSLContext::setClientCertificate(const PKCS12Certificate& certificate) // Create a PKCS12 structure BIO* bio = BIO_new(BIO_s_mem()); - BIO_write(bio, certificate.getData().getData(), certificate.getData().getSize()); + BIO_write(bio, vecptr(certificate.getData()), certificate.getData().size()); boost::shared_ptr<PKCS12> pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free); BIO_free(bio); if (!pkcs12) { @@ -203,7 +203,7 @@ bool OpenSSLContext::setClientCertificate(const PKCS12Certificate& certificate) X509 *certPtr = 0; EVP_PKEY* privateKeyPtr = 0; STACK_OF(X509)* caCertsPtr = 0; - int result = PKCS12_parse(pkcs12.get(), certificate.getPassword().c_str(), &privateKeyPtr, &certPtr, &caCertsPtr); + int result = PKCS12_parse(pkcs12.get(), reinterpret_cast<const char*>(vecptr(certificate.getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr); if (result != 1) { return false; } @@ -227,7 +227,7 @@ bool OpenSSLContext::setClientCertificate(const PKCS12Certificate& certificate) Certificate::ref OpenSSLContext::getPeerCertificate() const { boost::shared_ptr<X509> x509Cert(SSL_get_peer_certificate(handle_), X509_free); if (x509Cert) { - return Certificate::ref(new OpenSSLCertificate(x509Cert)); + return boost::make_shared<OpenSSLCertificate>(x509Cert); } else { return Certificate::ref(); @@ -237,7 +237,7 @@ Certificate::ref OpenSSLContext::getPeerCertificate() const { boost::shared_ptr<CertificateVerificationError> OpenSSLContext::getPeerCertificateVerificationError() const { int verifyResult = SSL_get_verify_result(handle_); if (verifyResult != X509_V_OK) { - return boost::shared_ptr<CertificateVerificationError>(new CertificateVerificationError(getVerificationErrorTypeForResult(verifyResult))); + return boost::make_shared<CertificateVerificationError>(getVerificationErrorTypeForResult(verifyResult)); } else { return boost::shared_ptr<CertificateVerificationError>(); @@ -247,7 +247,7 @@ boost::shared_ptr<CertificateVerificationError> OpenSSLContext::getPeerCertifica ByteArray OpenSSLContext::getFinishMessage() const { ByteArray data; data.resize(MAX_FINISHED_SIZE); - size_t size = SSL_get_finished(handle_, data.getData(), data.getSize()); + size_t size = SSL_get_finished(handle_, vecptr(data), data.size()); data.resize(size); return data; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLContext.h b/Swiften/TLS/OpenSSL/OpenSSLContext.h index 40e5483..04693a3 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContext.h +++ b/Swiften/TLS/OpenSSL/OpenSSLContext.h @@ -7,11 +7,11 @@ #pragma once #include <openssl/ssl.h> -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/noncopyable.hpp> -#include "Swiften/TLS/TLSContext.h" -#include "Swiften/Base/ByteArray.h" +#include <Swiften/TLS/TLSContext.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class PKCS12Certificate; @@ -24,8 +24,8 @@ namespace Swift { void connect(); bool setClientCertificate(const PKCS12Certificate& cert); - void handleDataFromNetwork(const ByteArray&); - void handleDataFromApplication(const ByteArray&); + void handleDataFromNetwork(const SafeByteArray&); + void handleDataFromApplication(const SafeByteArray&); Certificate::ref getPeerCertificate() const; boost::shared_ptr<CertificateVerificationError> getPeerCertificateVerificationError() const; diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp index f975df7..516482d 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp +++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.cpp @@ -4,8 +4,8 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/OpenSSL/OpenSSLContextFactory.h" -#include "Swiften/TLS/OpenSSL/OpenSSLContext.h" +#include <Swiften/TLS/OpenSSL/OpenSSLContextFactory.h> +#include <Swiften/TLS/OpenSSL/OpenSSLContext.h> namespace Swift { diff --git a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h index cf982c0..4e39cd6 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h +++ b/Swiften/TLS/OpenSSL/OpenSSLContextFactory.h @@ -6,7 +6,7 @@ #pragma once -#include "Swiften/TLS/TLSContextFactory.h" +#include <Swiften/TLS/TLSContextFactory.h> namespace Swift { class OpenSSLContextFactory : public TLSContextFactory { diff --git a/Swiften/TLS/PKCS12Certificate.h b/Swiften/TLS/PKCS12Certificate.h index 1c8c38f..c0e01d0 100644 --- a/Swiften/TLS/PKCS12Certificate.h +++ b/Swiften/TLS/PKCS12Certificate.h @@ -4,22 +4,21 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_PKCS12Certificate_H -#define SWIFTEN_PKCS12Certificate_H +#pragma once -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/SafeByteArray.h> namespace Swift { class PKCS12Certificate { public: PKCS12Certificate() {} - PKCS12Certificate(const std::string& filename, const std::string& password) : password_(password) { - data_.readFromFile(filename); + PKCS12Certificate(const std::string& filename, const SafeByteArray& password) : password_(password) { + readByteArrayFromFile(data_, filename); } bool isNull() const { - return data_.isEmpty(); + return data_.empty(); } const ByteArray& getData() const { @@ -30,14 +29,12 @@ namespace Swift { data_ = data; } - const std::string& getPassword() const { + const SafeByteArray& getPassword() const { return password_; } private: ByteArray data_; - std::string password_; + SafeByteArray password_; }; } - -#endif diff --git a/Swiften/TLS/PlatformTLSFactories.cpp b/Swiften/TLS/PlatformTLSFactories.cpp index e642758..dec8788 100644 --- a/Swiften/TLS/PlatformTLSFactories.cpp +++ b/Swiften/TLS/PlatformTLSFactories.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/PlatformTLSFactories.h" +#include <Swiften/TLS/PlatformTLSFactories.h> #include <cstring> #include <cassert> #ifdef HAVE_OPENSSL -#include "Swiften/TLS/OpenSSL/OpenSSLContextFactory.h" -#include "Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h" +#include <Swiften/TLS/OpenSSL/OpenSSLContextFactory.h> +#include <Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h> #endif namespace Swift { diff --git a/Swiften/TLS/ServerIdentityVerifier.cpp b/Swiften/TLS/ServerIdentityVerifier.cpp index d7b0580..a908ad0 100644 --- a/Swiften/TLS/ServerIdentityVerifier.cpp +++ b/Swiften/TLS/ServerIdentityVerifier.cpp @@ -4,12 +4,12 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/ServerIdentityVerifier.h" +#include <Swiften/TLS/ServerIdentityVerifier.h> #include <boost/algorithm/string.hpp> -#include "Swiften/Base/foreach.h" -#include "Swiften/IDN/IDNA.h" +#include <Swiften/Base/foreach.h> +#include <Swiften/IDN/IDNA.h> namespace Swift { @@ -63,7 +63,7 @@ bool ServerIdentityVerifier::certificateVerifies(Certificate::ref certificate) { return false; } -bool ServerIdentityVerifier::matchesDomain(const std::string& s) { +bool ServerIdentityVerifier::matchesDomain(const std::string& s) const { if (boost::starts_with(s, "*.")) { std::string matchString(s.substr(2, s.npos)); std::string matchDomain = encodedDomain; @@ -78,7 +78,7 @@ bool ServerIdentityVerifier::matchesDomain(const std::string& s) { } } -bool ServerIdentityVerifier::matchesAddress(const std::string& s) { +bool ServerIdentityVerifier::matchesAddress(const std::string& s) const { return s == domain; } diff --git a/Swiften/TLS/ServerIdentityVerifier.h b/Swiften/TLS/ServerIdentityVerifier.h index 05bb5f0..b09abd9 100644 --- a/Swiften/TLS/ServerIdentityVerifier.h +++ b/Swiften/TLS/ServerIdentityVerifier.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/TLS/Certificate.h" +#include <Swiften/JID/JID.h> +#include <Swiften/TLS/Certificate.h> namespace Swift { class ServerIdentityVerifier { @@ -20,8 +20,8 @@ namespace Swift { bool certificateVerifies(Certificate::ref); private: - bool matchesDomain(const std::string&); - bool matchesAddress(const std::string&); + bool matchesDomain(const std::string&) const ; + bool matchesAddress(const std::string&) const; private: std::string domain; diff --git a/Swiften/TLS/SimpleCertificate.h b/Swiften/TLS/SimpleCertificate.h index a81a23e..4cf0cc2 100644 --- a/Swiften/TLS/SimpleCertificate.h +++ b/Swiften/TLS/SimpleCertificate.h @@ -7,7 +7,7 @@ #pragma once #include <string> -#include "Swiften/TLS/Certificate.h" +#include <Swiften/TLS/Certificate.h> namespace Swift { class SimpleCertificate : public Certificate { diff --git a/Swiften/TLS/TLSContext.cpp b/Swiften/TLS/TLSContext.cpp index 008bfc0..026ae70 100644 --- a/Swiften/TLS/TLSContext.cpp +++ b/Swiften/TLS/TLSContext.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/TLSContext.h" +#include <Swiften/TLS/TLSContext.h> namespace Swift { diff --git a/Swiften/TLS/TLSContext.h b/Swiften/TLS/TLSContext.h index 1279eeb..1538863 100644 --- a/Swiften/TLS/TLSContext.h +++ b/Swiften/TLS/TLSContext.h @@ -6,12 +6,12 @@ #pragma once -#include "Swiften/Base/boost_bsignals.h" +#include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> -#include "Swiften/Base/ByteArray.h" -#include "Swiften/TLS/Certificate.h" -#include "Swiften/TLS/CertificateVerificationError.h" +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/TLS/Certificate.h> +#include <Swiften/TLS/CertificateVerificationError.h> namespace Swift { class PKCS12Certificate; @@ -24,8 +24,8 @@ namespace Swift { virtual bool setClientCertificate(const PKCS12Certificate& cert) = 0; - virtual void handleDataFromNetwork(const ByteArray&) = 0; - virtual void handleDataFromApplication(const ByteArray&) = 0; + virtual void handleDataFromNetwork(const SafeByteArray&) = 0; + virtual void handleDataFromApplication(const SafeByteArray&) = 0; virtual Certificate::ref getPeerCertificate() const = 0; virtual CertificateVerificationError::ref getPeerCertificateVerificationError() const = 0; @@ -33,8 +33,8 @@ namespace Swift { virtual ByteArray getFinishMessage() const = 0; public: - boost::signal<void (const ByteArray&)> onDataForNetwork; - boost::signal<void (const ByteArray&)> onDataForApplication; + boost::signal<void (const SafeByteArray&)> onDataForNetwork; + boost::signal<void (const SafeByteArray&)> onDataForApplication; boost::signal<void ()> onError; boost::signal<void ()> onConnected; }; diff --git a/Swiften/TLS/TLSContextFactory.cpp b/Swiften/TLS/TLSContextFactory.cpp index 47b529f..eb02f0c 100644 --- a/Swiften/TLS/TLSContextFactory.cpp +++ b/Swiften/TLS/TLSContextFactory.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/TLS/TLSContextFactory.h" +#include <Swiften/TLS/TLSContextFactory.h> namespace Swift { diff --git a/Swiften/TLS/UnitTest/CertificateTest.cpp b/Swiften/TLS/UnitTest/CertificateTest.cpp index 216aaae..5df5639 100644 --- a/Swiften/TLS/UnitTest/CertificateTest.cpp +++ b/Swiften/TLS/UnitTest/CertificateTest.cpp @@ -23,7 +23,7 @@ class CertificateTest : public CppUnit::TestFixture { public: void testGetSHA1Fingerprint() { SimpleCertificate::ref testling = boost::make_shared<SimpleCertificate>(); - testling->setDER(ByteArray("abcdefg")); + testling->setDER(createByteArray("abcdefg")); CPPUNIT_ASSERT_EQUAL(std::string("2f:b5:e1:34:19:fc:89:24:68:65:e7:a3:24:f4:76:ec:62:4e:87:40"), testling->getSHA1Fingerprint()); } diff --git a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp index 5234445..bd68c84 100644 --- a/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp +++ b/Swiften/TLS/UnitTest/ServerIdentityVerifierTest.cpp @@ -4,14 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include <vector> -#include "Swiften/TLS/ServerIdentityVerifier.h" -#include "Swiften/TLS/SimpleCertificate.h" +#include <Swiften/TLS/ServerIdentityVerifier.h> +#include <Swiften/TLS/SimpleCertificate.h> using namespace Swift; diff --git a/Swiften/VCards/GetVCardRequest.h b/Swiften/VCards/GetVCardRequest.h index 93e4871..dc65773 100644 --- a/Swiften/VCards/GetVCardRequest.h +++ b/Swiften/VCards/GetVCardRequest.h @@ -6,8 +6,8 @@ #pragma once -#include "Swiften/Queries/GenericRequest.h" -#include "Swiften/Elements/VCard.h" +#include <Swiften/Queries/GenericRequest.h> +#include <Swiften/Elements/VCard.h> namespace Swift { diff --git a/Swiften/VCards/SConscript b/Swiften/VCards/SConscript index e980ba3..c20c17d 100644 --- a/Swiften/VCards/SConscript +++ b/Swiften/VCards/SConscript @@ -3,6 +3,5 @@ Import("swiften_env") objects = swiften_env.SwiftenObject([ "VCardManager.cpp", "VCardStorage.cpp", - "VCardFileStorage.cpp", ]) swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/VCards/UnitTest/VCardManagerTest.cpp b/Swiften/VCards/UnitTest/VCardManagerTest.cpp index fa46306..eecec7b 100644 --- a/Swiften/VCards/UnitTest/VCardManagerTest.cpp +++ b/Swiften/VCards/UnitTest/VCardManagerTest.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/Base/ByteArray.h" +#include <Swiften/Base/ByteArray.h> #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -12,10 +12,10 @@ #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/VCards/VCardManager.h" -#include "Swiften/VCards/VCardMemoryStorage.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Client/DummyStanzaChannel.h" +#include <Swiften/VCards/VCardManager.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Client/DummyStanzaChannel.h> using namespace Swift; @@ -48,7 +48,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testGet_NewVCardRequestsVCard() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz")); CPPUNIT_ASSERT(!result); @@ -57,7 +57,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testGet_ExistingVCard() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); VCard::ref vcard(new VCard()); vcard->setFullName("Foo Bar"); vcardStorage->setVCard(JID("foo@bar.com/baz"), vcard); @@ -69,7 +69,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_RequestsVCard() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(stanzaChannel->sentStanzas.size())); @@ -77,7 +77,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_ReceiveEmitsNotification() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); stanzaChannel->onIQReceived(createVCardResult()); @@ -90,7 +90,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_Error() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); stanzaChannel->onIQReceived(IQ::createError(JID("baz@fum.com/foo"), stanzaChannel->sentStanzas[0]->getTo(), stanzaChannel->sentStanzas[0]->getID())); @@ -101,7 +101,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_VCardAlreadyRequested() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); VCard::ref result = testling->getVCardAndRequestWhenNeeded(JID("foo@bar.com/baz")); @@ -110,7 +110,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequest_AfterPreviousRequest() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); testling->requestVCard(JID("foo@bar.com/baz")); stanzaChannel->onIQReceived(createVCardResult()); testling->requestVCard(JID("foo@bar.com/baz")); @@ -120,7 +120,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testRequestOwnVCard() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); testling->requestVCard(ownJID); stanzaChannel->onIQReceived(createOwnVCardResult()); @@ -136,7 +136,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testCreateSetVCardRequest() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); VCard::ref vcard = boost::make_shared<VCard>(); vcard->setFullName("New Name"); SetVCardRequest::ref request = testling->createSetVCardRequest(vcard); @@ -150,7 +150,7 @@ class VCardManagerTest : public CppUnit::TestFixture { } void testCreateSetVCardRequest_Error() { - std::auto_ptr<VCardManager> testling = createManager(); + boost::shared_ptr<VCardManager> testling = createManager(); VCard::ref vcard = boost::make_shared<VCard>(); vcard->setFullName("New Name"); SetVCardRequest::ref request = testling->createSetVCardRequest(vcard); @@ -162,8 +162,8 @@ class VCardManagerTest : public CppUnit::TestFixture { } private: - std::auto_ptr<VCardManager> createManager() { - std::auto_ptr<VCardManager> manager(new VCardManager(ownJID, iqRouter, vcardStorage)); + boost::shared_ptr<VCardManager> createManager() { + boost::shared_ptr<VCardManager> manager(new VCardManager(ownJID, iqRouter, vcardStorage)); manager->onVCardChanged.connect(boost::bind(&VCardManagerTest::handleVCardChanged, this, _1, _2)); manager->onOwnVCardChanged.connect(boost::bind(&VCardManagerTest::handleOwnVCardChanged, this, _1)); return manager; diff --git a/Swiften/VCards/VCardManager.cpp b/Swiften/VCards/VCardManager.cpp index b9602ab..52447a1 100644 --- a/Swiften/VCards/VCardManager.cpp +++ b/Swiften/VCards/VCardManager.cpp @@ -4,13 +4,13 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/VCards/VCardManager.h" +#include <Swiften/VCards/VCardManager.h> #include <boost/bind.hpp> -#include "Swiften/JID/JID.h" -#include "Swiften/VCards/VCardStorage.h" -#include "Swiften/VCards/GetVCardRequest.h" +#include <Swiften/JID/JID.h> +#include <Swiften/VCards/VCardStorage.h> +#include <Swiften/VCards/GetVCardRequest.h> namespace Swift { diff --git a/Swiften/VCards/VCardManager.h b/Swiften/VCards/VCardManager.h index 1dd16ae..29fe32c 100644 --- a/Swiften/VCards/VCardManager.h +++ b/Swiften/VCards/VCardManager.h @@ -8,9 +8,9 @@ #include <set> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/VCard.h" -#include "Swiften/Elements/ErrorPayload.h" +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/VCard.h> +#include <Swiften/Elements/ErrorPayload.h> #include <Swiften/VCards/SetVCardRequest.h> #include <Swiften/Base/boost_bsignals.h> diff --git a/Swiften/VCards/VCardMemoryStorage.h b/Swiften/VCards/VCardMemoryStorage.h index b2e99c6..ade9c89 100644 --- a/Swiften/VCards/VCardMemoryStorage.h +++ b/Swiften/VCards/VCardMemoryStorage.h @@ -9,8 +9,8 @@ #include <boost/shared_ptr.hpp> #include <map> -#include "Swiften/JID/JID.h" -#include "Swiften/VCards/VCardStorage.h" +#include <Swiften/JID/JID.h> +#include <Swiften/VCards/VCardStorage.h> namespace Swift { class VCardMemoryStorage : public VCardStorage { diff --git a/Swiften/VCards/VCardStorage.cpp b/Swiften/VCards/VCardStorage.cpp index b14ee60..900f1e5 100644 --- a/Swiften/VCards/VCardStorage.cpp +++ b/Swiften/VCards/VCardStorage.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiften/VCards/VCardStorage.h" +#include <Swiften/VCards/VCardStorage.h> #include <Swiften/StringCodecs/Hexify.h> #include <Swiften/StringCodecs/SHA1.h> @@ -16,7 +16,7 @@ VCardStorage::~VCardStorage() { std::string VCardStorage::getPhotoHash(const JID& jid) const { VCard::ref vCard = getVCard(jid); - if (vCard && !vCard->getPhoto().isEmpty()) { + if (vCard && !vCard->getPhoto().empty()) { return Hexify::hexify(SHA1::getHash(vCard->getPhoto())); } else { diff --git a/Swiftob/Commands.cpp b/Swiftob/Commands.cpp index e39d23e..cf24196 100644 --- a/Swiftob/Commands.cpp +++ b/Swiftob/Commands.cpp @@ -4,8 +4,9 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiftob/Commands.h" +#include <Swiftob/Commands.h> +#include <Swiften/Base/foreach.h> #include <iostream> #include <boost/bind.hpp> diff --git a/Swiftob/Commands.h b/Swiftob/Commands.h index e11078d..8423252 100644 --- a/Swiftob/Commands.h +++ b/Swiftob/Commands.h @@ -12,8 +12,8 @@ #include <Swiften/Base/boost_bsignals.h> #include <Swiften/Elements/Message.h> -#include "Swiftob/Users.h" -#include "Swiftob/MUCs.h" +#include <Swiftob/Users.h> +#include <Swiftob/MUCs.h> namespace Swift { class Client; diff --git a/Swiftob/LuaCommands.cpp b/Swiftob/LuaCommands.cpp index 7be818e..9f99d82 100644 --- a/Swiftob/LuaCommands.cpp +++ b/Swiftob/LuaCommands.cpp @@ -4,16 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiftob/LuaCommands.h" +#include <Swiftob/LuaCommands.h> #include <boost/bind.hpp> #include <vector> #include <algorithm> +#include <iostream> +#include <Swiften/Base/foreach.h> #include <Swiften/Client/Client.h> #include <Swiften/Network/TimerFactory.h> -#include "Swiftob/Commands.h" +#include <Swiftob/Commands.h> #define LUA_COMMANDS "__Lua_Commands" #define STORAGE "__Storage" diff --git a/Swiftob/LuaCommands.h b/Swiftob/LuaCommands.h index dc8e36e..fc743ca 100644 --- a/Swiftob/LuaCommands.h +++ b/Swiftob/LuaCommands.h @@ -9,21 +9,18 @@ #include <string> #include <vector> -extern "C" { #include <lua.h> #include <lauxlib.h> #include <lualib.h> -} - #include <boost/filesystem/fstream.hpp> #include <boost/noncopyable.hpp> -#include "Swiften/Network/NetworkFactories.h" +#include <Swiften/Network/NetworkFactories.h> #include <Swiften/Elements/SoftwareVersion.h> #include <Swiften/Queries/Requests/GetSoftwareVersionRequest.h> #include <Swiften/Network/Timer.h> -#include "Swiftob/Commands.h" -#include "Swiftob/Storage.h" +#include <Swiftob/Commands.h> +#include <Swiftob/Storage.h> using namespace Swift; /** diff --git a/Swiftob/MUCs.cpp b/Swiftob/MUCs.cpp index 55bf313..695cbd9 100644 --- a/Swiftob/MUCs.cpp +++ b/Swiftob/MUCs.cpp @@ -4,14 +4,18 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiftob/MUCs.h" +#include <Swiftob/MUCs.h> +#include <boost/bind.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> + +#include <Swiften/Base/foreach.h> #include <Swiften/Client/Client.h> #include <Swiften/MUC/MUC.h> #include <Swiften/MUC/MUCManager.h> #include <Swiften/Base/String.h> -#include "Swiftob/Storage.h" +#include <Swiftob/Storage.h> #define MUC_LIST_SETTING "muc_list" diff --git a/Swiftob/SConscript b/Swiftob/SConscript index 3928ff0..bb056bb 100644 --- a/Swiftob/SConscript +++ b/Swiftob/SConscript @@ -3,18 +3,11 @@ Import("env") if env["SCONS_STAGE"] == "build": myenv = env.Clone() - myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) - myenv.MergeFlags(myenv["LIBIDN_FLAGS"]) - myenv.MergeFlags(myenv["BOOST_FLAGS"]) - myenv.MergeFlags(myenv["ZLIB_FLAGS"]) - myenv.MergeFlags(myenv["OPENSSL_FLAGS"]) - myenv.MergeFlags(myenv.get("SQLITE_FLAGS", {})) - myenv.MergeFlags(myenv.get("LIBXML_FLAGS", "")) - myenv.MergeFlags(myenv.get("EXPAT_FLAGS", "")) - myenv.MergeFlags(myenv["PLATFORM_FLAGS"]) myenv.MergeFlags(myenv.get("LUA_FLAGS", {})) + myenv.MergeFlags(myenv["SWIFTEN_FLAGS"]) + myenv.MergeFlags(myenv["SWIFTEN_DEP_FLAGS"]) sources = [ - "linit.c", # This is horrible! + "linit.cpp", "Swiftob.cpp", "Users.cpp", "Commands.cpp", diff --git a/Swiftob/Storage.cpp b/Swiftob/Storage.cpp index 0cf16d7..47d0619 100644 --- a/Swiftob/Storage.cpp +++ b/Swiftob/Storage.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiftob/Storage.h" +#include <Swiftob/Storage.h> #include <Swiften/Base/String.h> #include <Swiften/Base/ByteArray.h> @@ -23,8 +23,8 @@ Storage::Storage(const boost::filesystem::path& path) : settingsPath_(path) { void Storage::load() { if (boost::filesystem::exists(settingsPath_)) { Swift::ByteArray data; - data.readFromFile(settingsPath_.string()); - foreach (std::string line, Swift::String::split(data.toString(), '\n')) { + Swift::readByteArrayFromFile(data, settingsPath_.string()); + foreach (std::string line, Swift::String::split(Swift::byteArrayToString(data), '\n')) { std::pair<std::string, std::string> pair = Swift::String::getSplittedAtFirst(line, '\t'); settings_[pair.first] = pair.second; } diff --git a/Swiftob/Swiftob.cpp b/Swiftob/Swiftob.cpp index 6c6dad0..331e55e 100644 --- a/Swiftob/Swiftob.cpp +++ b/Swiftob/Swiftob.cpp @@ -4,7 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiftob/Swiftob.h" +#include <Swiftob/Swiftob.h> #include <string> #include <iostream> @@ -14,8 +14,8 @@ #include <Swiften/Base/String.h> #include <Swiften/Presence/PresenceSender.h> -#include "Swiftob/Users.h" -#include "Swiftob/Storage.h" +#include <Swiftob/Users.h> +#include <Swiftob/Storage.h> po::options_description Swiftob::getOptionsDescription() { @@ -108,6 +108,7 @@ Swiftob::~Swiftob() { delete commands_; delete storage_; delete users_; + delete mucs_; delete client_; } diff --git a/Swiftob/Swiftob.h b/Swiftob/Swiftob.h index 45061d0..ad4e9b8 100644 --- a/Swiftob/Swiftob.h +++ b/Swiftob/Swiftob.h @@ -18,8 +18,8 @@ #include <Swiften/Client/Client.h> #include <Swiften/Network/BoostNetworkFactories.h> -#include "Swiftob/Commands.h" -#include "Swiftob/LuaCommands.h" +#include <Swiftob/Commands.h> +#include <Swiftob/LuaCommands.h> namespace po = boost::program_options; diff --git a/Swiftob/Users.cpp b/Swiftob/Users.cpp index 55ba4eb..09173cc 100644 --- a/Swiftob/Users.cpp +++ b/Swiftob/Users.cpp @@ -4,13 +4,14 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swiftob/Users.h" +#include <Swiftob/Users.h> #include <iostream> +#include <Swiften/Base/foreach.h> #include <Swiften/Client/Client.h> -#include "Swiftob/MUCs.h" +#include <Swiftob/MUCs.h> Users::Users(Client* client, MUCs* mucs) { client_ = client; diff --git a/Swiftob/linit.c b/Swiftob/linit.cpp index 13c5b09..13c5b09 100644 --- a/Swiftob/linit.c +++ b/Swiftob/linit.cpp diff --git a/Swiftob/main.cpp b/Swiftob/main.cpp index 9908b45..a4e0925 100644 --- a/Swiftob/main.cpp +++ b/Swiftob/main.cpp @@ -17,7 +17,7 @@ int main(int argc, char* argv[]) { boost::program_options::variables_map vm; try { boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); - } catch (boost::program_options::unknown_option option) { + } catch (const boost::program_options::unknown_option& option) { #if BOOST_VERSION >= 104200 std::cout << "Ignoring unknown option " << option.get_option_name() << " but continuing." << std::endl; #else |