diff options
Diffstat (limited to 'Swiften')
41 files changed, 872 insertions, 499 deletions
diff --git a/Swiften/Elements/HashElement.h b/Swiften/Elements/HashElement.h new file mode 100644 index 0000000..44d2f96 --- /dev/null +++ b/Swiften/Elements/HashElement.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/ByteArray.h> + +namespace Swift { + /* + * @brief This class represents a XEP-0300 <hash/> element. + */ + class HashElement { + public: + HashElement(const std::string& algorithm, const ByteArray& hash) : algorithm_(algorithm), hash_(hash) { + } + + void setHashValue(const std::string& algorithm, const ByteArray& hash) { + algorithm_ = algorithm; + hash_ = hash; + } + + const std::string& getAlgorithm() const { + return algorithm_; + } + + const ByteArray& getHashValue() const { + return hash_; + } + + bool operator==(const HashElement& rhs) const { + return (algorithm_ == rhs.algorithm_) && (hash_ == rhs.hash_); + } + + + private: + std::string algorithm_; + ByteArray hash_; + }; +} diff --git a/Swiften/Elements/JingleFileTransferDescription.h b/Swiften/Elements/JingleFileTransferDescription.h index 620f8f5..9308abf 100644 --- a/Swiften/Elements/JingleFileTransferDescription.h +++ b/Swiften/Elements/JingleFileTransferDescription.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Isode Limited. + * Copyright (c) 2011-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,32 +10,22 @@ #include <vector> #include <Swiften/Elements/JingleDescription.h> -#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/JingleFileTransferFileInfo.h> namespace Swift { class JingleFileTransferDescription : public JingleDescription { public: typedef boost::shared_ptr<JingleFileTransferDescription> ref; - void addOffer(const StreamInitiationFileInfo& offer) { - offers.push_back(offer); + void setFileInfo(const JingleFileTransferFileInfo& fileInfo) { + fileInfo_ = fileInfo; } - - 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; + const JingleFileTransferFileInfo& getFileInfo() { + return fileInfo_; } private: - std::vector<StreamInitiationFileInfo> offers; - std::vector<StreamInitiationFileInfo> reqeusts; + JingleFileTransferFileInfo fileInfo_; }; } diff --git a/Swiften/Elements/JingleFileTransferFileInfo.h b/Swiften/Elements/JingleFileTransferFileInfo.h new file mode 100644 index 0000000..8fec59e --- /dev/null +++ b/Swiften/Elements/JingleFileTransferFileInfo.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <string> +#include <vector> +#include <map> + +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> + +#include <Swiften/Elements/HashElement.h> +#include <Swiften/Elements/Payload.h> + +namespace Swift { + + /** + * @brief This class represents the file info used in XEP-0234. + */ + class JingleFileTransferFileInfo : public Payload { + typedef boost::shared_ptr<JingleFileTransferFileInfo> ref; + + public: + JingleFileTransferFileInfo(const std::string& name = "", const std::string& description = "", unsigned long long size = 0, const boost::posix_time::ptime &date = boost::posix_time::ptime()) : + name_(name), description_(description), size_(size), date_(date), supportsRangeRequests_(false), rangeOffset_(0) { + } + + public: + typedef std::map<std::string, ByteArray> HashElementMap; + + public: + void setName(const std::string& name) { + name_ = name;; + } + + const std::string& getName() const { + return name_; + } + + void setDescription(const std::string& description) { + description_ = description; + } + + const std::string& getDescription() const { + return description_; + } + + void setMediaType(const std::string& mediaType) { + mediaType_ = mediaType; + } + + const std::string& getMediaType() const { + return mediaType_; + } + + void setSize(const boost::uintmax_t size) { + size_ = size; + } + + boost::uintmax_t getSize() const { + return size_; + } + + void setDate(const boost::posix_time::ptime& date) { + date_ = date; + } + + const boost::posix_time::ptime& getDate() const { + return date_; + } + + void setSupportsRangeRequests(const bool supportsIt) { + supportsRangeRequests_ = supportsIt; + } + + bool getSupportsRangeRequests() const { + return supportsRangeRequests_; + } + + void setRangeOffset(const boost::uintmax_t offset) { + supportsRangeRequests_ = true; + rangeOffset_ = offset; + } + + boost::uintmax_t getRangeOffset() const { + return rangeOffset_; + } + + void addHash(const HashElement& hash) { + hashes_[hash.getAlgorithm()] = hash.getHashValue(); + } + + const std::map<std::string, ByteArray>& getHashes() const { + return hashes_; + } + + boost::optional<ByteArray> getHash(const std::string& algorithm) const { + boost::optional<ByteArray> ret; + if (hashes_.find(algorithm) != hashes_.end()) { + ret = boost::optional<ByteArray>(hashes_.find(algorithm)->second); + } + return ret; + } + + private: + std::string name_; + std::string description_; + std::string mediaType_; + boost::uintmax_t size_; + boost::posix_time::ptime date_; + bool supportsRangeRequests_; + boost::uintmax_t rangeOffset_; + HashElementMap hashes_; + }; +} diff --git a/Swiften/Elements/JingleFileTransferHash.h b/Swiften/Elements/JingleFileTransferHash.h index 5603531..d34e35d 100644 --- a/Swiften/Elements/JingleFileTransferHash.h +++ b/Swiften/Elements/JingleFileTransferHash.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #pragma once #include <boost/shared_ptr.hpp> @@ -11,25 +17,24 @@ #include <string> #include <Swiften/Elements/JingleDescription.h> +#include <Swiften/Elements/JingleFileTransferFileInfo.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; + void setFileInfo(const JingleFileTransferFileInfo& fileInfo) { + fileInfo_ = fileInfo; } - const HashesMap& getHashes() const { - return hashes; + JingleFileTransferFileInfo& getFileInfo() { + return fileInfo_; } private: - HashesMap hashes; + JingleFileTransferFileInfo fileInfo_; }; } diff --git a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp index 74492b1..1a77685 100644 --- a/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp +++ b/Swiften/FileTransfer/DefaultFileTransferTransporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -242,8 +242,10 @@ boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBSen boost::shared_ptr<TransportSession> DefaultFileTransferTransporter::createIBBReceiveSession( const std::string& sessionID, unsigned long long size, boost::shared_ptr<WriteBytestream> stream) { - closeLocalSession(); - closeRemoteSession(); + if (s5bServerManager->getServer()) { + closeLocalSession(); + closeRemoteSession(); + } boost::shared_ptr<IBBReceiveSession> ibbSession = boost::make_shared<IBBReceiveSession>( sessionID, initiator, responder, size, stream, router); return boost::make_shared<IBBReceiveTransportSession>(ibbSession); diff --git a/Swiften/FileTransfer/FileTransferManagerImpl.cpp b/Swiften/FileTransfer/FileTransferManagerImpl.cpp index f248b8a..fe8bfd6 100644 --- a/Swiften/FileTransfer/FileTransferManagerImpl.cpp +++ b/Swiften/FileTransfer/FileTransferManagerImpl.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -21,7 +21,7 @@ #include <Swiften/Base/Path.h> #include "Swiften/Disco/EntityCapsProvider.h" #include <Swiften/JID/JID.h> -#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/JingleFileTransferFileInfo.h> #include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> #include <Swiften/FileTransfer/OutgoingFileTransferManager.h> #include <Swiften/FileTransfer/IncomingFileTransferManager.h> @@ -146,7 +146,7 @@ OutgoingFileTransfer::ref FileTransferManagerImpl::createOutgoingFileTransfer( const boost::posix_time::ptime& lastModified, boost::shared_ptr<ReadBytestream> bytestream, const FileTransferOptions& config) { - StreamInitiationFileInfo fileInfo; + JingleFileTransferFileInfo fileInfo; fileInfo.setDate(lastModified); fileInfo.setSize(sizeInBytes); fileInfo.setName(filename); diff --git a/Swiften/FileTransfer/FileTransferOptions.h b/Swiften/FileTransfer/FileTransferOptions.h index 3a0abcb..3d00d2b 100644 --- a/Swiften/FileTransfer/FileTransferOptions.h +++ b/Swiften/FileTransfer/FileTransferOptions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -12,7 +12,7 @@ namespace Swift { class SWIFTEN_API FileTransferOptions { public: - FileTransferOptions() : allowInBand(false) { + FileTransferOptions() : allowInBand(true) { } SWIFTEN_DEFAULT_COPY_CONSTRUCTOR(FileTransferOptions) ~FileTransferOptions(); diff --git a/Swiften/FileTransfer/FileTransferTransporter.h b/Swiften/FileTransfer/FileTransferTransporter.h index d149722..2116f0d 100644 --- a/Swiften/FileTransfer/FileTransferTransporter.h +++ b/Swiften/FileTransfer/FileTransferTransporter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -20,6 +20,11 @@ namespace Swift { class ReadBytestream; class WriteBytestream; + /** + * @brief The FileTransferTransporter class is an abstract factory definition + * to generate SOCKS5 bytestream transports or IBB bytestreams for use in file + * transfers. + */ class SWIFTEN_API FileTransferTransporter { public: virtual ~FileTransferTransporter(); diff --git a/Swiften/FileTransfer/IncomingFileTransfer.h b/Swiften/FileTransfer/IncomingFileTransfer.h index e0cb4ad..93ecf1a 100644 --- a/Swiften/FileTransfer/IncomingFileTransfer.h +++ b/Swiften/FileTransfer/IncomingFileTransfer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -16,6 +16,10 @@ namespace Swift { class WriteBytestream; class JID; + /** + * @brief The IncomingFileTransfer abstract class is the general interface in Swiften + * for incoming file transfers. + */ class IncomingFileTransfer : public FileTransfer { public: typedef boost::shared_ptr<IncomingFileTransfer> ref; diff --git a/Swiften/FileTransfer/IncomingFileTransferManager.cpp b/Swiften/FileTransfer/IncomingFileTransferManager.cpp index 05d6259..239c4a8 100644 --- a/Swiften/FileTransfer/IncomingFileTransferManager.cpp +++ b/Swiften/FileTransfer/IncomingFileTransferManager.cpp @@ -44,13 +44,13 @@ bool IncomingFileTransferManager::handleIncomingJingleSession( if (JingleContentPayload::ref content = Jingle::getContentWithDescription<JingleFileTransferDescription>(contents)) { if (content->getTransport<JingleS5BTransportPayload>()) { JingleFileTransferDescription::ref description = content->getDescription<JingleFileTransferDescription>(); - if (description && description->getOffers().size() == 1) { + if (description) { IncomingJingleFileTransfer::ref transfer = boost::make_shared<IncomingJingleFileTransfer>( recipient, session, content, transporterFactory, timerFactory, crypto); onIncomingFileTransfer(transfer); } else { - SWIFT_LOG(warning) << "Received a file-transfer request with no description or more than one file."; + SWIFT_LOG(warning) << "Received a file-transfer request with no file description."; session->sendTerminate(JinglePayload::Reason::FailedApplication); } } diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp index 66b2e53..720eefd 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.cpp @@ -1,15 +1,18 @@ /* - * Copyright (c) 2011-2013 Isode Limited. + * Copyright (c) 2011-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> +#include <set> + #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <Swiften/Base/Log.h> +#include <Swiften/StringCodecs/Base64.h> #include <Swiften/Base/foreach.h> #include <Swiften/Jingle/JingleSession.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> @@ -43,11 +46,9 @@ IncomingJingleFileTransfer::IncomingJingleFileTransfer( hashCalculator(NULL) { description = initialContent->getDescription<JingleFileTransferDescription>(); assert(description); - assert(description->getOffers().size() == 1); - StreamInitiationFileInfo fileInfo = description->getOffers().front(); + JingleFileTransferFileInfo fileInfo = description->getFileInfo(); setFileInfo(fileInfo.getName(), fileInfo.getSize()); - hash = fileInfo.getHash(); - hashAlgorithm = fileInfo.getAlgo(); + hashes = fileInfo.getHashes(); waitOnHashTimer = timerFactory->createTimer(5000); waitOnHashTimerTickedConnection = waitOnHashTimer->onTick.connect( @@ -68,20 +69,33 @@ void IncomingJingleFileTransfer::accept( this->options = options; assert(!hashCalculator); + hashCalculator = new IncrementalBytestreamHashCalculator( - hashAlgorithm == "md5" || hash.empty(), hashAlgorithm == "sha-1" || hash.empty(), crypto); + hashes.find("md5") != hashes.end(), hashes.find("sha-1") != hashes.end(), crypto); writeStreamDataReceivedConnection = stream->onWrite.connect( boost::bind(&IncomingJingleFileTransfer::handleWriteStreamDataReceived, this, _1)); if (JingleS5BTransportPayload::ref s5bTransport = initialContent->getTransport<JingleS5BTransportPayload>()) { - SWIFT_LOG(debug) << "Got S5B transport payload!" << std::endl; + SWIFT_LOG(debug) << "Got S5B transport as initial payload." << std::endl; setTransporter(transporterFactory->createResponderTransporter( getInitiator(), getResponder(), s5bTransport->getSessionID())); transporter->addRemoteCandidates(s5bTransport->getCandidates()); setState(GeneratingInitialLocalCandidates); transporter->startGeneratingLocalCandidates(); } + else if (JingleIBBTransportPayload::ref ibbTransport = initialContent->getTransport<JingleIBBTransportPayload>()) { + SWIFT_LOG(debug) << "Got IBB transport as initial payload." << std::endl; + setTransporter(transporterFactory->createResponderTransporter( + getInitiator(), getResponder(), ibbTransport->getSessionID())); + + startTransferring(transporter->createIBBReceiveSession( + ibbTransport->getSessionID(), + description->getFileInfo().getSize(), + stream)); + + session->sendAccept(getContentID(), initialContent->getDescriptions()[0], ibbTransport); + } else { // Can't happen, because the transfer would have been rejected automatically assert(false); @@ -121,13 +135,11 @@ void IncomingJingleFileTransfer::handleSessionInfoReceived(JinglePayload::ref ji if (transferHash) { SWIFT_LOG(debug) << "Received hash information." << std::endl; waitOnHashTimer->stop(); - if (transferHash->getHashes().find("sha-1") != transferHash->getHashes().end()) { - hashAlgorithm = "sha-1"; - hash = transferHash->getHashes().find("sha-1")->second; + if (transferHash->getFileInfo().getHashes().find("sha-1") != transferHash->getFileInfo().getHashes().end()) { + hashes["sha-1"] = transferHash->getFileInfo().getHash("sha-1").get(); } - else if (transferHash->getHashes().find("md5") != transferHash->getHashes().end()) { - hashAlgorithm = "md5"; - hash = transferHash->getHashes().find("md5")->second; + else if (transferHash->getFileInfo().getHashes().find("md5") != transferHash->getFileInfo().getHashes().end()) { + hashes["md5"] = transferHash->getFileInfo().getHash("md5").get(); } if (state == WaitingForHash) { checkHashAndTerminate(); @@ -172,7 +184,12 @@ void IncomingJingleFileTransfer::checkHashAndTerminate() { void IncomingJingleFileTransfer::checkIfAllDataReceived() { if (receivedBytes == getFileSizeInBytes()) { SWIFT_LOG(debug) << "All data received." << std::endl; - if (hash.empty()) { + bool hashInfoAvailable = true; + foreach(const JingleFileTransferFileInfo::HashElementMap::value_type& hashElement, hashes) { + hashInfoAvailable &= !hashElement.second.empty(); + } + + if (!hashInfoAvailable) { SWIFT_LOG(debug) << "No hash information yet. Waiting a while on hash info." << std::endl; setState(WaitingForHash); waitOnHashTimer->start(); @@ -207,7 +224,7 @@ void IncomingJingleFileTransfer::handleTransportReplaceReceived( startTransferring(transporter->createIBBReceiveSession( ibbTransport->getSessionID(), - description->getOffers()[0].getSize(), + description->getFileInfo().getSize(), stream)); session->sendTransportAccept(content, ibbTransport); } @@ -222,17 +239,17 @@ JingleContentID IncomingJingleFileTransfer::getContentID() const { } bool IncomingJingleFileTransfer::verifyData() { - if (hashAlgorithm.empty() || hash.empty()) { + if (hashes.empty()) { SWIFT_LOG(debug) << "no verification possible, skipping" << std::endl; return true; } - if (hashAlgorithm == "sha-1") { - SWIFT_LOG(debug) << "Verify SHA-1 hash: " << (hash == hashCalculator->getSHA1String()) << std::endl; - return hash == hashCalculator->getSHA1String(); + if (hashes.find("sha-1") != hashes.end()) { + SWIFT_LOG(debug) << "Verify SHA-1 hash: " << (hashes["sha-1"] == hashCalculator->getSHA1Hash()) << std::endl; + return hashes["sha-1"] == hashCalculator->getSHA1Hash(); } - else if (hashAlgorithm == "md5") { - SWIFT_LOG(debug) << "Verify MD5 hash: " << (hash == hashCalculator->getMD5String()) << std::endl; - return hash == hashCalculator->getMD5String(); + else if (hashes.find("md5") != hashes.end()) { + SWIFT_LOG(debug) << "Verify MD5 hash: " << (hashes["md5"] == hashCalculator->getMD5Hash()) << std::endl; + return hashes["md5"] == hashCalculator->getMD5Hash(); } else { SWIFT_LOG(debug) << "Unknown hash, skipping" << std::endl; diff --git a/Swiften/FileTransfer/IncomingJingleFileTransfer.h b/Swiften/FileTransfer/IncomingJingleFileTransfer.h index 727d278..7fc22f4 100644 --- a/Swiften/FileTransfer/IncomingJingleFileTransfer.h +++ b/Swiften/FileTransfer/IncomingJingleFileTransfer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -17,6 +17,7 @@ #include <Swiften/FileTransfer/JingleFileTransfer.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> #include <Swiften/FileTransfer/FileTransferOptions.h> +#include <Swiften/Base/ByteArray.h> namespace Swift { class JID; @@ -29,7 +30,15 @@ namespace Swift { class CryptoProvider; class IncrementalBytestreamHashCalculator; class JingleFileTransferDescription; + class HashElement; + /** + * @brief The IncomingJingleFileTransfer class contains the business logic for managing incoming + * Jingle file transfers. + * + * Calling IncomingJingleFileTransfer::accept will start to negotiate possible transfer + * methods and after a working method has been decided among peers the trasnfer is started. + */ class SWIFTEN_API IncomingJingleFileTransfer : public IncomingFileTransfer, public JingleFileTransfer { public: typedef boost::shared_ptr<IncomingJingleFileTransfer> ref; @@ -43,7 +52,7 @@ namespace Swift { CryptoProvider*); ~IncomingJingleFileTransfer(); - virtual void accept(boost::shared_ptr<WriteBytestream>, const FileTransferOptions&) SWIFTEN_OVERRIDE; + virtual void accept(boost::shared_ptr<WriteBytestream>, const FileTransferOptions& = FileTransferOptions()) SWIFTEN_OVERRIDE; virtual void cancel() SWIFTEN_OVERRIDE; private: @@ -108,8 +117,7 @@ namespace Swift { boost::uintmax_t receivedBytes; IncrementalBytestreamHashCalculator* hashCalculator; boost::shared_ptr<Timer> waitOnHashTimer; - std::string hashAlgorithm; - std::string hash; + std::map<std::string, ByteArray> hashes; FileTransferOptions options; boost::bsignals::scoped_connection writeStreamDataReceivedConnection; diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp index e982fd0..7eb9560 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -46,20 +46,30 @@ void IncrementalBytestreamHashCalculator::feedData(const SafeByteArray& data) { } }*/ -std::string IncrementalBytestreamHashCalculator::getSHA1String() { +ByteArray IncrementalBytestreamHashCalculator::getSHA1Hash() { assert(sha1Hasher); if (!sha1Hash) { - sha1Hash = Hexify::hexify(sha1Hasher->getHash()); + sha1Hash = sha1Hasher->getHash(); } return *sha1Hash; } -std::string IncrementalBytestreamHashCalculator::getMD5String() { +ByteArray IncrementalBytestreamHashCalculator::getMD5Hash() { assert(md5Hasher); if (!md5Hash) { - md5Hash = Hexify::hexify(md5Hasher->getHash()); + md5Hash = md5Hasher->getHash(); } return *md5Hash; } +std::string IncrementalBytestreamHashCalculator::getSHA1String() { + assert(sha1Hasher); + return Hexify::hexify(getSHA1Hash());; +} + +std::string IncrementalBytestreamHashCalculator::getMD5String() { + assert(md5Hasher); + return Hexify::hexify(getMD5Hash());; +} + } diff --git a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h index bb6b441..bc4ebf9 100644 --- a/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h +++ b/Swiften/FileTransfer/IncrementalBytestreamHashCalculator.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -30,14 +30,17 @@ namespace Swift { void feedData(const ByteArray& data); //void feedData(const SafeByteArray& data); + ByteArray getSHA1Hash(); + ByteArray getMD5Hash(); + std::string getSHA1String(); std::string getMD5String(); private: Hash* md5Hasher; Hash* sha1Hasher; - boost::optional<std::string> md5Hash; - boost::optional<std::string> sha1Hash; + boost::optional<ByteArray> md5Hash; + boost::optional<ByteArray> sha1Hash; }; } diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp index 5ed4656..5d0555f 100644 --- a/Swiften/FileTransfer/OutgoingFileTransferManager.cpp +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -43,7 +43,7 @@ boost::shared_ptr<OutgoingFileTransfer> OutgoingFileTransferManager::createOutgo const JID& from, const JID& recipient, boost::shared_ptr<ReadBytestream> readBytestream, - const StreamInitiationFileInfo& fileInfo, + const JingleFileTransferFileInfo& fileInfo, const FileTransferOptions& config) { JingleSessionImpl::ref jingleSession = boost::make_shared<JingleSessionImpl>( from, recipient, idGenerator->generateID(), iqRouter); diff --git a/Swiften/FileTransfer/OutgoingFileTransferManager.h b/Swiften/FileTransfer/OutgoingFileTransferManager.h index 8dd4bbc..fd7380b 100644 --- a/Swiften/FileTransfer/OutgoingFileTransferManager.h +++ b/Swiften/FileTransfer/OutgoingFileTransferManager.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -22,7 +22,7 @@ namespace Swift { class JID; class IDGenerator; class ReadBytestream; - class StreamInitiationFileInfo; + class JingleFileTransferFileInfo; class CryptoProvider; class FileTransferOptions; @@ -39,7 +39,7 @@ namespace Swift { const JID& from, const JID& to, boost::shared_ptr<ReadBytestream>, - const StreamInitiationFileInfo&, + const JingleFileTransferFileInfo&, const FileTransferOptions&); private: diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp index 93214eb..369af8f 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2013 Isode Limited. + * Copyright (C) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -49,7 +49,7 @@ OutgoingJingleFileTransfer::OutgoingJingleFileTransfer( boost::shared_ptr<ReadBytestream> stream, FileTransferTransporterFactory* transporterFactory, IDGenerator* idGenerator, - const StreamInitiationFileInfo& fileInfo, + const JingleFileTransferFileInfo& fileInfo, const FileTransferOptions& options, CryptoProvider* crypto) : JingleFileTransfer(session, toJID, transporterFactory), @@ -149,8 +149,8 @@ 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()); + hashElement->getFileInfo().addHash(HashElement("sha-1", hashCalculator->getSHA1Hash())); + hashElement->getFileInfo().addHash(HashElement("md5", hashCalculator->getMD5Hash())); session->sendInfo(hashElement); } @@ -162,7 +162,9 @@ void OutgoingJingleFileTransfer::handleLocalTransportCandidatesGenerated( fillCandidateMap(localCandidates, candidates); JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); - description->addOffer(fileInfo); + fileInfo.addHash(HashElement("sha-1", ByteArray())); + fileInfo.addHash(HashElement("md5", ByteArray())); + description->setFileInfo(fileInfo); JingleS5BTransportPayload::ref transport = boost::make_shared<JingleS5BTransportPayload>(); transport->setSessionID(s5bSessionID); diff --git a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h index c21c50b..f022b9f 100644 --- a/Swiften/FileTransfer/OutgoingJingleFileTransfer.h +++ b/Swiften/FileTransfer/OutgoingJingleFileTransfer.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -18,7 +18,7 @@ #include <Swiften/Base/API.h> #include <Swiften/Base/Override.h> #include <Swiften/Jingle/JingleContentID.h> -#include <Swiften/Elements/StreamInitiationFileInfo.h> +#include <Swiften/Elements/JingleFileTransferFileInfo.h> #include <Swiften/FileTransfer/OutgoingFileTransfer.h> #include <Swiften/FileTransfer/JingleFileTransfer.h> #include <Swiften/FileTransfer/FileTransferOptions.h> @@ -40,7 +40,7 @@ namespace Swift { boost::shared_ptr<ReadBytestream>, FileTransferTransporterFactory*, IDGenerator*, - const StreamInitiationFileInfo&, + const JingleFileTransferFileInfo&, const FileTransferOptions&, CryptoProvider*); virtual ~OutgoingJingleFileTransfer(); @@ -99,7 +99,7 @@ namespace Swift { private: IDGenerator* idGenerator; boost::shared_ptr<ReadBytestream> stream; - StreamInitiationFileInfo fileInfo; + JingleFileTransferFileInfo fileInfo; FileTransferOptions options; JingleContentID contentID; IncrementalBytestreamHashCalculator* hashCalculator; diff --git a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp index a296b33..207f590 100644 --- a/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp +++ b/Swiften/FileTransfer/UnitTest/IncomingJingleFileTransferTest.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -22,14 +22,20 @@ #include <Swiften/Elements/IBB.h> #include <Swiften/Elements/JingleIBBTransportPayload.h> #include <Swiften/Elements/JingleS5BTransportPayload.h> +#include <Swiften/Elements/JingleFileTransferDescription.h> +#include <Swiften/FileTransfer/DefaultFileTransferTransporterFactory.h> #include <Swiften/FileTransfer/ByteArrayWriteBytestream.h> #include <Swiften/FileTransfer/IncomingJingleFileTransfer.h> #include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/Network/PlatformNetworkEnvironment.h> #include <Swiften/FileTransfer/SOCKS5BytestreamProxiesManager.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamServerManager.h> #include <Swiften/Jingle/FakeJingleSession.h> +#include <Swiften/Network/NATTraverser.h> #include <Swiften/Network/DummyTimerFactory.h> #include <Swiften/EventLoop/DummyEventLoop.h> #include <Swiften/Network/DummyConnectionFactory.h> +#include <Swiften/Network/DummyConnectionServerFactory.h> #include <Swiften/Network/PlatformNATTraversalWorker.h> #include <Swiften/Queries/IQRouter.h> #include <Swiften/Crypto/CryptoProvider.h> @@ -42,53 +48,61 @@ using namespace boost; class IncomingJingleFileTransferTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(IncomingJingleFileTransferTest); - //CPPUNIT_TEST(test_AcceptOnyIBBSendsSessionAccept); - //CPPUNIT_TEST(test_OnlyIBBTransferReceiveWorks); + 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 boost::shared_ptr<IncomingJingleFileTransfer>(new IncomingJingleFileTransfer(ourJID, shared_ptr<JingleSession>(session), jingleContentPayload, fakeRJTCSF.get(), fakeLJTCF.get(), iqRouter, bytestreamRegistry, bytestreamProxy, timerFactory, crypto.get())); - // } + shared_ptr<IncomingJingleFileTransfer> createTestling() { + JID ourJID("our@jid.org/full"); + return boost::make_shared<IncomingJingleFileTransfer>(ourJID, shared_ptr<JingleSession>(session), jingleContentPayload, ftTransporterFactory, timerFactory, crypto.get()); + } - // 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; - // } + 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() { crypto = boost::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()); eventLoop = new DummyEventLoop(); session = boost::make_shared<FakeJingleSession>("foo@bar.com/baz", "mysession"); - // jingleContentPayload = make_shared<JingleContentPayload>(); + 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 SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); + stanzaChannel = new DummyStanzaChannel(); + connectionFactory = new DummyConnectionFactory(eventLoop); + serverConnectionFactory = new DummyConnectionServerFactory(eventLoop); + iqRouter = new IQRouter(stanzaChannel); + bytestreamRegistry = new SOCKS5BytestreamRegistry(); + networkEnvironment = new PlatformNetworkEnvironment(); + natTraverser = new PlatformNATTraversalWorker(eventLoop); + bytestreamServerManager = new SOCKS5BytestreamServerManager(bytestreamRegistry, serverConnectionFactory, networkEnvironment, natTraverser); + idGenerator = new SimpleIDGenerator(); + timerFactory = new DummyTimerFactory(); + bytestreamProxy = new SOCKS5BytestreamProxiesManager(connectionFactory, timerFactory); + ftTransporterFactory = new DefaultFileTransferTransporterFactory(bytestreamRegistry, bytestreamServerManager, bytestreamProxy, idGenerator, connectionFactory, timerFactory, crypto.get(), iqRouter); } void tearDown() { - // delete bytestreamProxy; - // delete connectionFactory; - // delete timerFactory; - // delete bytestreamRegistry; - // delete iqRouter; - // delete stanzaChannel; + delete ftTransporterFactory; + delete bytestreamServerManager; + delete bytestreamProxy; + delete connectionFactory; + delete timerFactory; + delete bytestreamRegistry; + delete iqRouter; + delete stanzaChannel; delete eventLoop; + Log::setLogLevel(Log::error); } // Tests whether IncomingJingleFileTransfer would accept a IBB only file transfer. -#if 0 void test_AcceptOnyIBBSendsSessionAccept() { //1. create your test incoming file transfer shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); - desc->addOffer(StreamInitiationFileInfo("foo.txt", "", 10)); + desc->setFileInfo(JingleFileTransferFileInfo("foo.txt", "", 10)); jingleContentPayload->addDescription(desc); JingleIBBTransportPayload::ref tpRef = make_shared<JingleIBBTransportPayload>(); tpRef->setSessionID("mysession"); @@ -107,7 +121,7 @@ public: void test_OnlyIBBTransferReceiveWorks() { //1. create your test incoming file transfer shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); - desc->addOffer(StreamInitiationFileInfo("file.txt", "", 10)); + desc->setFileInfo(JingleFileTransferFileInfo("file.txt", "", 10)); jingleContentPayload->addDescription(desc); JingleIBBTransportPayload::ref tpRef = make_shared<JingleIBBTransportPayload>(); tpRef->setSessionID("mysession"); @@ -139,6 +153,8 @@ public: shared_ptr<ByteArrayWriteBytestream> byteStream = make_shared<ByteArrayWriteBytestream>(); fileTransfer->accept(byteStream); + // candidates are gathered + // check whether accept has been called FakeJingleSession::AcceptCall acceptCall = getCall<FakeJingleSession::AcceptCall>(0); CPPUNIT_ASSERT_EQUAL(payLoad->getSessionID(), acceptCall.payload->getSessionID()); @@ -149,7 +165,7 @@ public: CPPUNIT_ASSERT(s5bPayload->hasCandidateError()); // indicate transport replace (Romeo) - session->onTransportReplaceReceived(getContentID(), addJingleIBBPayload()); + session->handleTransportReplaceReceived(getContentID(), addJingleIBBPayload()); FakeJingleSession::AcceptTransportCall acceptTransportCall = getCall<FakeJingleSession::AcceptTransportCall>(2); @@ -158,16 +174,16 @@ public: stanzaChannel->onIQReceived(createIBBRequest(IBB::createIBBData("mysession", 0, createByteArray("abc")), "foo@bar.com/baz", "id-a")); CPPUNIT_ASSERT(createByteArray("abc") == byteStream->getData()); } - +#if 0 void test_S5BTransferReceiveTest() { addFileTransferDescription(); JingleS5BTransportPayload::ref payLoad = addJingleS5BPayload(); } - +#endif private: void addFileTransferDescription() { shared_ptr<JingleFileTransferDescription> desc = make_shared<JingleFileTransferDescription>(); - desc->addOffer(StreamInitiationFileInfo("file.txt", "", 10)); + desc->setFileInfo(JingleFileTransferFileInfo("file.txt", "", 10)); jingleContentPayload->addDescription(desc); } @@ -196,23 +212,26 @@ private: CPPUNIT_ASSERT(cmd); return *cmd; } -#endif private: EventLoop* eventLoop; boost::shared_ptr<CryptoProvider> crypto; boost::shared_ptr<FakeJingleSession> session; -#if 0 shared_ptr<JingleContentPayload> jingleContentPayload; - shared_ptr<FakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF; - shared_ptr<FakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF; +// shared_ptr<FakeRemoteJingleTransportCandidateSelectorFactory> fakeRJTCSF; +// shared_ptr<FakeLocalJingleTransportCandidateGeneratorFactory> fakeLJTCF; + FileTransferTransporterFactory* ftTransporterFactory; + SOCKS5BytestreamServerManager* bytestreamServerManager; DummyStanzaChannel* stanzaChannel; IQRouter* iqRouter; SOCKS5BytestreamRegistry* bytestreamRegistry; DummyConnectionFactory* connectionFactory; + DummyConnectionServerFactory* serverConnectionFactory; SOCKS5BytestreamProxiesManager* bytestreamProxy; DummyTimerFactory* timerFactory; -#endif + NetworkEnvironment* networkEnvironment; + NATTraverser* natTraverser; + IDGenerator* idGenerator; }; CPPUNIT_TEST_SUITE_REGISTRATION(IncomingJingleFileTransferTest); diff --git a/Swiften/Jingle/FakeJingleSession.cpp b/Swiften/Jingle/FakeJingleSession.cpp index 1df106a..3b94da7 100644 --- a/Swiften/Jingle/FakeJingleSession.cpp +++ b/Swiften/Jingle/FakeJingleSession.cpp @@ -4,7 +4,14 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include <Swiften/Jingle/FakeJingleSession.h> +#include <Swiften/Jingle/JingleSessionListener.h> #include <boost/smart_ptr/make_shared.hpp> @@ -50,4 +57,8 @@ void FakeJingleSession::sendTransportReplace(const JingleContentID& id, JingleTr calledCommands.push_back(ReplaceTransportCall(id, payload)); } +void FakeJingleSession::handleTransportReplaceReceived(const JingleContentID& contentID, JingleTransportPayload::ref transport) { + notifyListeners(&JingleSessionListener::handleTransportReplaceReceived, contentID, transport); +} + } diff --git a/Swiften/Jingle/FakeJingleSession.h b/Swiften/Jingle/FakeJingleSession.h index 24e85d8..19028ad 100644 --- a/Swiften/Jingle/FakeJingleSession.h +++ b/Swiften/Jingle/FakeJingleSession.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2013 Isode Limited. + * Copyright (c) 2013-2014 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -96,6 +96,8 @@ namespace Swift { virtual void sendTransportReject(const JingleContentID&, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; virtual void sendTransportReplace(const JingleContentID&, JingleTransportPayload::ref) SWIFTEN_OVERRIDE; + void handleTransportReplaceReceived(const JingleContentID&, JingleTransportPayload::ref); + public: std::vector<Command> calledCommands; SimpleIDGenerator idGenerator; diff --git a/Swiften/Network/DummyConnectionServer.h b/Swiften/Network/DummyConnectionServer.h new file mode 100644 index 0000000..0cbce0e --- /dev/null +++ b/Swiften/Network/DummyConnectionServer.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010-2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/enable_shared_from_this.hpp> + +#include <Swiften/Base/API.h> +#include <Swiften/Network/ConnectionServer.h> +#include <Swiften/Network/HostAddressPort.h> +#include <Swiften/EventLoop/EventLoop.h> +#include <Swiften/EventLoop/EventOwner.h> + +namespace Swift { + class SWIFTEN_API DummyConnectionServer : public ConnectionServer, public EventOwner, public boost::enable_shared_from_this<DummyConnectionServer> { + public: + DummyConnectionServer(EventLoop* eventLoop, int port) : eventLoop(eventLoop), localAddressPort(HostAddress(), port) {} + DummyConnectionServer(EventLoop* eventLoop, const Swift::HostAddress& hostAddress, int port) : eventLoop(eventLoop), localAddressPort(hostAddress, port) {} + virtual ~DummyConnectionServer() {} + + virtual HostAddressPort getAddressPort() const { + return localAddressPort; + } + + virtual boost::optional<Error> tryStart() { + return boost::optional<Error>(); + } + + virtual void start() { + + } + + virtual void stop() { + + } + + public: + EventLoop* eventLoop; + HostAddressPort localAddressPort; + }; +} diff --git a/Swiften/Network/DummyConnectionServerFactory.h b/Swiften/Network/DummyConnectionServerFactory.h new file mode 100644 index 0000000..6369452 --- /dev/null +++ b/Swiften/Network/DummyConnectionServerFactory.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <boost/smart_ptr/make_shared.hpp> + +#include <Swiften/Network/ConnectionServerFactory.h> +#include <Swiften/Network/DummyConnectionServer.h> + +namespace Swift { + +class EventLoop; + +class DummyConnectionServerFactory : public ConnectionServerFactory { +public: + DummyConnectionServerFactory(EventLoop* eventLoop) : eventLoop(eventLoop) {} + virtual ~DummyConnectionServerFactory() {} + + virtual boost::shared_ptr<ConnectionServer> createConnectionServer(int port) { + return boost::make_shared<DummyConnectionServer>(eventLoop, port); + } + + virtual boost::shared_ptr<ConnectionServer> createConnectionServer(const Swift::HostAddress& hostAddress, int port) { + return boost::make_shared<DummyConnectionServer>(eventLoop, hostAddress, port); + } + +private: + EventLoop* eventLoop; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp index fe61c72..812e968 100644 --- a/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp +++ b/Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.cpp @@ -78,6 +78,7 @@ #include <Swiften/Parser/PayloadParsers/StatusShowParser.h> #include <Swiften/Parser/PayloadParsers/StorageParser.h> #include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> +#include <Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.h> #include <Swiften/Parser/PayloadParsers/StreamInitiationParser.h> #include <Swiften/Parser/PayloadParsers/SubjectParser.h> #include <Swiften/Parser/PayloadParsers/UserLocationParser.h> @@ -140,6 +141,7 @@ FullPayloadParserFactoryCollection::FullPayloadParserFactoryCollection() { factories_.push_back(boost::make_shared<GenericPayloadParserFactory<JingleS5BTransportMethodPayloadParser> >("transport", "urn:xmpp:jingle:transports:s5b:1")); factories_.push_back(boost::make_shared<JingleFileTransferDescriptionParserFactory>(this)); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<StreamInitiationFileInfoParser> >("file", "http://jabber.org/protocol/si/profile/file-transfer")); + factories_.push_back(boost::make_shared<GenericPayloadParserFactory<JingleFileTransferFileInfoParser> >("file", "urn:xmpp:jingle:apps:file-transfer:4")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<JingleFileTransferReceivedParser> >("received", "urn:xmpp:jingle:apps:file-transfer:3")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<JingleFileTransferHashParser> >("checksum")); factories_.push_back(boost::make_shared<GenericPayloadParserFactory<S5BProxyRequestParser> >("query", "http://jabber.org/protocol/bytestreams")); diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp index b394115..fb1836f 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.cpp @@ -4,72 +4,59 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ -#include "JingleFileTransferDescriptionParser.h" +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h> + +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> #include <Swiften/Parser/PayloadParserFactoryCollection.h> #include <Swiften/Parser/PayloadParserFactory.h> -#include <Swiften/Base/Log.h> +#include <Swiften/Base/DateTime.h> +#include <Swiften/StringCodecs/Base64.h> namespace Swift { -JingleFileTransferDescriptionParser::JingleFileTransferDescriptionParser(PayloadParserFactoryCollection* factories) : factories(factories), level(0), - currentElement(UnknownElement) { - +JingleFileTransferDescriptionParser::JingleFileTransferDescriptionParser(PayloadParserFactoryCollection* factories) : factories(factories), level(0) { } 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) { + if (level >= 1 && 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 >= 1 && currentPayloadParser) { + 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); - } - } + if (level == 0) { + boost::shared_ptr<JingleFileTransferFileInfo> info = boost::dynamic_pointer_cast<JingleFileTransferFileInfo>(currentPayloadParser->getPayload()); + if (info) { + getPayloadInternal()->setFileInfo(*info); } } } void JingleFileTransferDescriptionParser::handleCharacterData(const std::string& data) { - if (level >= 2 && currentPayloadParser) { + if (level >= 1 && currentPayloadParser) { currentPayloadParser->handleCharacterData(data); } } - + } diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h index 7ea22b4..a1215c1 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParser.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #pragma once #include <Swiften/Elements/JingleFileTransferDescription.h> @@ -20,18 +26,11 @@ class JingleFileTransferDescriptionParser : public GenericPayloadParser<JingleFi 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); + 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 index b997c1d..7bd4b8a 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferDescriptionParserFactory.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #pragma once #include <Swiften/Parser/GenericPayloadParserFactory.h> @@ -19,7 +25,7 @@ namespace Swift { } 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"; + return element == "description" && ns == "urn:xmpp:jingle:apps:file-transfer:4"; } virtual PayloadParser* createPayloadParser() { diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.cpp new file mode 100644 index 0000000..2a62f23 --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.h> + +#include <boost/optional.hpp> +#include <boost/lexical_cast.hpp> + +#include <Swiften/Base/DateTime.h> +#include <Swiften/StringCodecs/Base64.h> + +namespace Swift { + +JingleFileTransferFileInfoParser::JingleFileTransferFileInfoParser() : level(0) { +} + +template<typename T> boost::optional<T> safeLexicalCast(const std::string& str) { + boost::optional<T> ret; + try { + ret = boost::lexical_cast<T>(str); + } catch (boost::bad_lexical_cast &) { + + } + return ret; +} + +void JingleFileTransferFileInfoParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { + charData.clear(); + if (element == "hash") { + hashAlg = attributes.getAttributeValue("algo").get_value_or(""); + } + else if (element == "range") { + rangeOffset = safeLexicalCast<boost::uintmax_t>(attributes.getAttributeValue("offset").get_value_or("")); + } + + ++level; +} + +void JingleFileTransferFileInfoParser::handleEndElement(const std::string& element, const std::string&) { + --level; + if (level == 1) { + if (element == "date") { + getPayloadInternal()->setDate(stringToDateTime(charData)); + } + else if (element == "desc") { + getPayloadInternal()->setDescription(charData); + } + else if (element == "media-type") { + getPayloadInternal()->setMediaType(charData); + } + else if (element == "name") { + getPayloadInternal()->setName(charData); + } + else if (element == "size") { + boost::optional<boost::uintmax_t> size = safeLexicalCast<boost::uintmax_t>(charData); + if (size) { + getPayloadInternal()->setSize(size.get()); + } + } + else if (element == "range") { + getPayloadInternal()->setSupportsRangeRequests(true); + if (rangeOffset) { + getPayloadInternal()->setRangeOffset(rangeOffset.get_value_or(0)); + } + } + else if (element == "hash") { + getPayloadInternal()->addHash(HashElement(hashAlg, Base64::decode(charData))); + } + } +} + +void JingleFileTransferFileInfoParser::handleCharacterData(const std::string& data) { + charData += data; +} + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.h new file mode 100644 index 0000000..eb6245c --- /dev/null +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferFileInfoParser.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Elements/JingleFileTransferFileInfo.h> +#include <Swiften/Parser/GenericPayloadParser.h> + +namespace Swift { + +class JingleFileTransferFileInfoParser : public GenericPayloadParser<JingleFileTransferFileInfo> { + public: + JingleFileTransferFileInfoParser(); + + 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; + std::string charData; + std::string hashAlg; + boost::optional<boost::uintmax_t> rangeOffset; +}; + +} diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp index 87f8317..6a1a031 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.cpp @@ -4,39 +4,54 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file 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/PayloadParsers/JingleFileTransferFileInfoParser.h> #include <Swiften/Parser/GenericPayloadParserFactory.h> #include <Swiften/Parser/PayloadParserFactory.h> namespace Swift { -JingleFileTransferHashParser::JingleFileTransferHashParser() { +JingleFileTransferHashParser::JingleFileTransferHashParser() : level(0) { } -void JingleFileTransferHashParser::handleStartElement(const std::string& element, const std::string&, const AttributeMap& attributes) { - if (element == "hash") { - algo = attributes.getAttribute("algo"); +void JingleFileTransferHashParser::handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { + if (level == 1 && element == "file") { + currentPayloadParser = boost::make_shared<JingleFileTransferFileInfoParser>(); } + + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleStartElement(element, ns, attributes); + } + ++level; } -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::handleEndElement(const std::string& element, const std::string& ns) { + --level; + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleEndElement(element, ns); + } + + if (level == 1) { + boost::shared_ptr<JingleFileTransferFileInfo> info = boost::dynamic_pointer_cast<JingleFileTransferFileInfo>(currentPayloadParser->getPayload()); + if (info) { + getPayloadInternal()->setFileInfo(*info); + } } } void JingleFileTransferHashParser::handleCharacterData(const std::string& data) { - if (!algo.empty()) { - std::string new_data(data); - boost::trim(new_data); - hash += new_data; + if (level >= 1 && currentPayloadParser) { + currentPayloadParser->handleCharacterData(data); } } diff --git a/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h index 35e4a05..5a7c6c5 100644 --- a/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h +++ b/Swiften/Parser/PayloadParsers/JingleFileTransferHashParser.h @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #pragma once #include <Swiften/Elements/JingleFileTransferHash.h> @@ -20,8 +26,8 @@ public: virtual void handleCharacterData(const std::string& data); private: - std::string algo; - std::string hash; + int level; + boost::shared_ptr<PayloadParser> currentPayloadParser; }; } diff --git a/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp index cc69348..b3888d6 100644 --- a/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp +++ b/Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.cpp @@ -4,7 +4,13 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ -#include "StreamInitiationFileInfoParser.h" +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Parser/PayloadParsers/StreamInitiationFileInfoParser.h> #include <boost/optional.hpp> #include <boost/lexical_cast.hpp> diff --git a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp index 8c8601a..a6be599 100644 --- a/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp +++ b/Swiften/Parser/PayloadParsers/UnitTest/JingleParserTest.cpp @@ -16,7 +16,7 @@ #include <Swiften/Elements/JingleFileTransferReceived.h> #include <Swiften/Elements/JingleFileTransferHash.h> #include <Swiften/Base/DateTime.h> - +#include <Swiften/StringCodecs/Base64.h> #include <Swiften/Base/Log.h> using namespace Swift; @@ -36,8 +36,6 @@ class JingleParserTest : public CppUnit::TestFixture { 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); @@ -223,40 +221,39 @@ class JingleParserTest : public CppUnit::TestFixture { 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" + " 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:4'>\n" + "<file>\n" + "<date>1969-07-21T02:56:15Z</date>\n" + "<desc>This is a test. If this were a real file...</desc>\n" + "<media-type>text/plain</media-type>\n" + "<name>test.txt</name>\n" + "<range/>\n" + "<size>1022</size>\n" + "<hash xmlns='urn:xmpp:hashes:1' algo='sha-1'>VS2nSZMIUsaa5dIUHTdmsQ==</hash>\n" + "</file>\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>(); @@ -270,16 +267,15 @@ class JingleParserTest : public CppUnit::TestFixture { 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()); + CPPUNIT_ASSERT(description); + JingleFileTransferFileInfo fileInfo = description->getFileInfo(); + CPPUNIT_ASSERT_EQUAL(std::string("test.txt"), fileInfo.getName()); + CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), fileInfo.getHashes().begin()->first); + CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(fileInfo.getHashes().begin()->second)); + CPPUNIT_ASSERT(1022 == fileInfo.getSize()); + CPPUNIT_ASSERT_EQUAL(std::string("This is a test. If this were a real file..."), fileInfo.getDescription()); + CPPUNIT_ASSERT_EQUAL(true, fileInfo.getSupportsRangeRequests()); + CPPUNIT_ASSERT(stringToDateTime("1969-07-21T02:56:15Z") == fileInfo.getDate()); } // http://xmpp.org/extensions/xep-0234.html#example-3 @@ -287,22 +283,21 @@ class JingleParserTest : public CppUnit::TestFixture { 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" + " 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:4'>\n" + "<file>\n" + "<date>1969-07-21T02:56:15Z</date>\n" + "<desc>This is a test. If this were a real file...</desc>\n" + "<media-type>text/plain</media-type>\n" + "<name>test.txt</name>\n" + "<range/>\n" + "<size>1022</size>\n" + "<hash xmlns='urn:xmpp:hashes:1' algo='sha-1'>VS2nSZMIUsaa5dIUHTdmsQ==</hash>\n" + "</file>\n" + "</description>\n" " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" " mode='tcp'\n" " sid='vj3hs98y'>\n" @@ -340,16 +335,16 @@ class JingleParserTest : public CppUnit::TestFixture { JingleFileTransferDescription::ref description = contents[0]->getDescription<JingleFileTransferDescription>(); + CPPUNIT_ASSERT(description); - 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()); + JingleFileTransferFileInfo fileInfo = description->getFileInfo(); + CPPUNIT_ASSERT_EQUAL(std::string("test.txt"), fileInfo.getName()); + CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), fileInfo.getHashes().begin()->first); + CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(fileInfo.getHashes().begin()->second)); + CPPUNIT_ASSERT(1022 == fileInfo.getSize()); + CPPUNIT_ASSERT_EQUAL(std::string("This is a test. If this were a real file..."), fileInfo.getDescription()); + CPPUNIT_ASSERT_EQUAL(true, fileInfo.getSupportsRangeRequests()); + CPPUNIT_ASSERT(stringToDateTime("1969-07-21T02:56:15Z") == fileInfo.getDate()); } // http://xmpp.org/extensions/xep-0234.html#example-5 @@ -393,11 +388,9 @@ class JingleParserTest : public CppUnit::TestFixture { " action='session-info'\n" " initiator='romeo@montague.lit/orchard'\n" " sid='a73sjjvkla37jfea'>\n" - " <checksum xmlns='urn:xmpp:jingle:apps:file-transfer:3'>\n" + " <checksum xmlns='urn:xmpp:jingle:apps:file-transfer:4'>\n" " <file>\n" - " <hashes xmlns='urn:xmpp:hashes:0'>\n" - " <hash algo='sha-1'>552da749930852c69ae5d2141d3766b1</hash>\n" - " </hashes>\n" + " <hash xmlns='urn:xmpp:hashes:0' algo='sha-1'>VS2nSZMIUsaa5dIUHTdmsQ==</hash>\n" " </file>\n" " </checksum>\n" "</jingle>\n" @@ -410,12 +403,12 @@ class JingleParserTest : public CppUnit::TestFixture { JingleFileTransferHash::ref hash = jingle->getPayload<JingleFileTransferHash>(); CPPUNIT_ASSERT(hash); - CPPUNIT_ASSERT_EQUAL(std::string("552da749930852c69ae5d2141d3766b1"), hash->getHashes().find("sha-1")->second); - + CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(hash->getFileInfo().getHash("sha-1").get())); } // http://xmpp.org/extensions/xep-0234.html#example-10 void testParse_Xep0234_Example10() { + Log::setLogLevel(Log::debug); PayloadsParserTester parser; CPPUNIT_ASSERT(parser.parse( "<jingle xmlns='urn:xmpp:jingle:1'\n" @@ -423,13 +416,11 @@ class JingleParserTest : public CppUnit::TestFixture { " 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 xmlns='urn:xmpp:jingle:apps:file-transfer:4'>\n" + " <file>\n" + " <hash xmlns='urn:xmpp:hashes:1' algo='sha-1'>VS2nSZMIUsaa5dIUHTdmsQ==</hash>\n" + " <range offset='270336'/>\n" + " </file>\n" " </description>\n" " <transport xmlns='urn:xmpp:jingle:transports:s5b:1'\n" " mode='tcp'\n" @@ -466,101 +457,13 @@ class JingleParserTest : public CppUnit::TestFixture { 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(static_cast<unsigned long long>(270336), file.getRangeOffset()); + JingleFileTransferFileInfo file = content->getDescription<JingleFileTransferDescription>()->getFileInfo(); + CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), file.getHashes().begin()->first); + CPPUNIT_ASSERT_EQUAL(std::string("VS2nSZMIUsaa5dIUHTdmsQ=="), Base64::encode(file.getHashes().begin()->second)); + CPPUNIT_ASSERT_EQUAL(static_cast<boost::uintmax_t>(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; diff --git a/Swiften/Parser/SConscript b/Swiften/Parser/SConscript index 94ea6d3..4bdf66f 100644 --- a/Swiften/Parser/SConscript +++ b/Swiften/Parser/SConscript @@ -38,6 +38,7 @@ sources = [ "PayloadParsers/JingleFileTransferDescriptionParser.cpp", "PayloadParsers/JingleFileTransferReceivedParser.cpp", "PayloadParsers/JingleFileTransferHashParser.cpp", + "PayloadParsers/JingleFileTransferFileInfoParser.cpp", "PayloadParsers/StreamInitiationFileInfoParser.cpp", "PayloadParsers/CommandParser.cpp", "PayloadParsers/InBandRegistrationPayloadParser.cpp", diff --git a/Swiften/SConscript b/Swiften/SConscript index 877b084..147f7a6 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -235,6 +235,7 @@ if env["SCONS_STAGE"] == "build" : "Serializer/PayloadSerializers/MAMResultSerializer.cpp", "Serializer/PayloadSerializers/MAMQuerySerializer.cpp", "Serializer/PayloadSerializers/IsodeIQDelegationSerializer.cpp", + "Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp", "Serializer/PresenceSerializer.cpp", "Serializer/StanzaSerializer.cpp", "Serializer/StreamErrorSerializer.cpp", diff --git a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp index 4a4d678..a9a1ae3 100644 --- a/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp +++ b/Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.cpp @@ -32,6 +32,7 @@ #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferReceivedSerializer.h> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleIBBTransportPayloadSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JinglePayloadSerializer.h> #include <Swiften/Serializer/PayloadSerializers/JingleS5BTransportPayloadSerializer.h> @@ -127,6 +128,7 @@ FullPayloadSerializerCollection::FullPayloadSerializerCollection() { serializers_.push_back(new IdleSerializer()); serializers_.push_back(new StreamInitiationFileInfoSerializer()); + serializers_.push_back(new JingleFileTransferFileInfoSerializer()); serializers_.push_back(new JingleContentPayloadSerializer()); serializers_.push_back(new JingleFileTransferDescriptionSerializer()); serializers_.push_back(new JingleFileTransferHashSerializer()); diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp index 16337ff..bbe1510 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.cpp @@ -4,17 +4,27 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferDescriptionSerializer.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/StringCodecs/Base64.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> +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.h> namespace Swift { @@ -22,24 +32,11 @@ 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); - } + XMLElement description("description", "urn:xmpp:jingle:apps:file-transfer:4"); + + JingleFileTransferFileInfoSerializer fileInfoSerializer; + boost::shared_ptr<XMLRawTextNode> fileInfoXML = boost::make_shared<XMLRawTextNode>(fileInfoSerializer.serialize(boost::make_shared<JingleFileTransferFileInfo>(payload->getFileInfo()))); + description.addNode(fileInfoXML); return description.serialize(); } diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp new file mode 100644 index 0000000..1a675d0 --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.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> +#include <Swiften/StringCodecs/Base64.h> + +namespace Swift { + +JingleFileTransferFileInfoSerializer::JingleFileTransferFileInfoSerializer() { +} + +std::string JingleFileTransferFileInfoSerializer::serializePayload(boost::shared_ptr<JingleFileTransferFileInfo> fileInfo) const { + + XMLElement fileElement("file", ""); + + if (fileInfo->getDate() != stringToDateTime("")) { + fileElement.addNode(boost::make_shared<XMLElement>("date", "", dateTimeToString(fileInfo->getDate()))); + } + + if (!fileInfo->getDescription().empty()) { + fileElement.addNode(boost::make_shared<XMLElement>("desc", "", fileInfo->getDescription())); + } + + if (!fileInfo->getMediaType().empty()) { + fileElement.addNode(boost::make_shared<XMLElement>("media-type", "", fileInfo->getMediaType())); + } + + if (!fileInfo->getName().empty()) { + fileElement.addNode(boost::make_shared<XMLElement>("name", "", fileInfo->getName())); + } + + 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); + } + + if (fileInfo->getSize() > 0) { + fileElement.addNode(boost::make_shared<XMLElement>("size", "", boost::lexical_cast<std::string>(fileInfo->getSize()))); + } + + foreach (JingleFileTransferFileInfo::HashElementMap::value_type hashElement, fileInfo->getHashes()) { + boost::shared_ptr<XMLElement> hash = boost::make_shared<XMLElement>("hash", "urn:xmpp:hashes:1", Base64::encode(hashElement.second)); + hash->setAttribute("algo", hashElement.first); + fileElement.addNode(hash); + } + + return fileElement.serialize(); +} + +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.h b/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.h new file mode 100644 index 0000000..0c9f2de --- /dev/null +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2014 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <Swiften/Base/API.h> +#include <Swiften/Serializer/GenericPayloadSerializer.h> +#include <Swiften/Elements/JingleFileTransferFileInfo.h> + +#include <Swiften/Serializer/XML/XMLElement.h> + +namespace Swift { + class PayloadSerializerCollection; + + class SWIFTEN_API JingleFileTransferFileInfoSerializer : public GenericPayloadSerializer<JingleFileTransferFileInfo> { + public: + JingleFileTransferFileInfoSerializer(); + + virtual std::string serializePayload(boost::shared_ptr<JingleFileTransferFileInfo>) const; + }; +} diff --git a/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp b/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp index 2bd3afa..f416ddc 100644 --- a/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp +++ b/Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include <Swiften/Serializer/PayloadSerializers/JingleFileTransferHashSerializer.h> #include <string> @@ -16,7 +22,7 @@ #include <Swiften/Serializer/XML/XMLNode.h> #include <Swiften/Serializer/XML/XMLElement.h> #include <Swiften/Serializer/XML/XMLRawTextNode.h> - +#include <Swiften/Serializer/PayloadSerializers/JingleFileTransferFileInfoSerializer.h> namespace Swift { @@ -27,17 +33,14 @@ std::string JingleFileTransferHashSerializer::serializePayload(boost::shared_ptr // 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"); + // code for version urn:xmpp:jingle:apps:file-transfer:4 + XMLElement checksum("checksum", "urn:xmpp:jingle:apps:file-transfer:4"); + + JingleFileTransferFileInfoSerializer fileSerializer; + + boost::shared_ptr<XMLRawTextNode> file = boost::make_shared<XMLRawTextNode>(fileSerializer.serialize(boost::make_shared<JingleFileTransferFileInfo>(payload->getFileInfo()))); + 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/UnitTest/JingleSerializersTest.cpp b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp index e3ec8fc..722c039 100644 --- a/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp +++ b/Swiften/Serializer/PayloadSerializers/UnitTest/JingleSerializersTest.cpp @@ -4,6 +4,12 @@ * See Documentation/Licenses/BSD-simplified.txt for more information. */ +/* + * Copyright (c) 2015 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + #include <boost/shared_ptr.hpp> #include <boost/smart_ptr/make_shared.hpp> @@ -15,13 +21,14 @@ #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/JingleFileTransferFileInfo.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> +#include <Swiften/StringCodecs/Base64.h> using namespace Swift; @@ -38,7 +45,6 @@ class JingleSerializersTest : public CppUnit::TestFixture { 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); @@ -179,30 +185,27 @@ class JingleSerializersTest : public CppUnit::TestFixture { // 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>"; + std::string expected = "<description xmlns=\"urn:xmpp:jingle:apps:file-transfer:4\">" + "<file>" + "<date>1969-07-21T02:56:15Z</date>" + "<desc>This is a test. If this were a real file...</desc>" + "<name>test.txt</name>" + "<range/>" + "<size>1022</size>" + "<hash algo=\"sha-1\" xmlns=\"urn:xmpp:hashes:1\">VS2nSZMIUsaa5dIUHTdmsQ==</hash>" + "</file>" + "</description>"; JingleFileTransferDescription::ref desc = boost::make_shared<JingleFileTransferDescription>(); - StreamInitiationFileInfo fileInfo; + JingleFileTransferFileInfo fileInfo; fileInfo.setDate(stringToDateTime("1969-07-21T02:56:15Z")); - fileInfo.setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo.addHash(HashElement("sha-1", Base64::decode("VS2nSZMIUsaa5dIUHTdmsQ=="))); 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); + desc->setFileInfo(fileInfo); CPPUNIT_ASSERT_EQUAL(expected, boost::make_shared<JingleFileTransferDescriptionSerializer>()->serialize(desc)); } @@ -215,18 +218,15 @@ class JingleSerializersTest : public CppUnit::TestFixture { " 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 xmlns=\"urn:xmpp:jingle:apps:file-transfer:4\">" + "<file>" + "<date>1969-07-21T02:56:15Z</date>" + "<desc>This is a test. If this were a real file...</desc>" + "<name>test.txt</name>" + "<range/>" + "<size>1022</size>" + "<hash algo=\"sha-1\" xmlns=\"urn:xmpp:hashes:1\">VS2nSZMIUsaa5dIUHTdmsQ==</hash>" + "</file>" "</description>" /*"<transport xmlns=\"urn:xmpp:jingle:transports:s5b:1\"" " mode=\"tcp\"" @@ -263,15 +263,15 @@ class JingleSerializersTest : public CppUnit::TestFixture { content->setName("a-file-offer"); JingleFileTransferDescription::ref description = boost::make_shared<JingleFileTransferDescription>(); - StreamInitiationFileInfo fileInfo; + JingleFileTransferFileInfo fileInfo; fileInfo.setName("test.txt"); fileInfo.setSize(1022); - fileInfo.setHash("552da749930852c69ae5d2141d3766b1"); + fileInfo.addHash(HashElement("sha-1", Base64::decode("VS2nSZMIUsaa5dIUHTdmsQ=="))); 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); + description->setFileInfo(fileInfo); content->addDescription(description); payload->addPayload(content); @@ -316,11 +316,9 @@ class JingleSerializersTest : public CppUnit::TestFixture { " initiator=\"romeo@montague.lit/orchard\"" " sid=\"a73sjjvkla37jfea\"" " xmlns=\"urn:xmpp:jingle:1\">" - "<checksum xmlns=\"urn:xmpp:jingle:apps:file-transfer:3\">" + "<checksum xmlns=\"urn:xmpp:jingle:apps:file-transfer:4\">" "<file>" - "<hashes xmlns=\"urn:xmpp:hashes:0\">" - "<hash algo=\"sha-1\">552da749930852c69ae5d2141d3766b1</hash>" - "</hashes>" + "<hash algo=\"sha-1\" xmlns=\"urn:xmpp:hashes:1\">VS2nSZMIUsaa5dIUHTdmsQ==</hash>" "</file>" "</checksum>" "</jingle>"; @@ -331,82 +329,12 @@ class JingleSerializersTest : public CppUnit::TestFixture { payload->setSessionID("a73sjjvkla37jfea"); JingleFileTransferHash::ref hash = boost::make_shared<JingleFileTransferHash>(); - hash->setHash("sha-1", "552da749930852c69ae5d2141d3766b1"); + hash->getFileInfo().addHash(HashElement("sha-1", Base64::decode("VS2nSZMIUsaa5dIUHTdmsQ=="))); 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() { |