diff options
| -rw-r--r-- | Swift/QtUI/QtWebKitChatView.cpp | 53 | ||||
| -rw-r--r-- | Swift/QtUI/QtWebKitChatView.h | 4 | ||||
| -rw-r--r-- | Swiften/FileTransfer/ByteArrayWriteBytestream.h | 5 | ||||
| -rw-r--r-- | Swiften/FileTransfer/FileTransferError.h | 3 | ||||
| -rw-r--r-- | Swiften/FileTransfer/FileWriteBytestream.cpp | 17 | ||||
| -rw-r--r-- | Swiften/FileTransfer/FileWriteBytestream.h | 2 | ||||
| -rw-r--r-- | Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp | 3 | ||||
| -rw-r--r-- | Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp | 40 | ||||
| -rw-r--r-- | Swiften/FileTransfer/SOCKS5BytestreamServerSession.h | 9 | ||||
| -rw-r--r-- | Swiften/FileTransfer/WriteBytestream.h | 12 | ||||
| -rw-r--r-- | Swiften/QA/SConscript | 2 | ||||
| -rw-r--r-- | Swiften/QA/StorageTest/FileReadBytestreamTest.cpp | 13 | ||||
| -rw-r--r-- | Swiften/QA/StorageTest/FileWriteBytestreamTest.cpp | 58 | ||||
| -rw-r--r-- | Swiften/QA/StorageTest/SConscript | 3 | 
14 files changed, 171 insertions, 53 deletions
| diff --git a/Swift/QtUI/QtWebKitChatView.cpp b/Swift/QtUI/QtWebKitChatView.cpp index 260da8a..b543e34 100644 --- a/Swift/QtUI/QtWebKitChatView.cpp +++ b/Swift/QtUI/QtWebKitChatView.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -11,6 +11,7 @@  #include <QEventLoop>  #include <QFile>  #include <QFileDialog> +#include <QFileInfo>  #include <QInputDialog>  #include <QKeyEvent>  #include <QMessageBox> @@ -747,6 +748,50 @@ void QtWebKitChatView::setWhiteboardSessionStatus(const std::string& id, const C  	setWhiteboardSessionStatus(P2QSTRING(id), state);  } +static bool isFilePathWritable(const QString& path) { +	QFileInfo fileInfo = QFileInfo(path); +	if (fileInfo.exists()) { +		return fileInfo.isWritable(); +	} +	else { +		bool writable = false; +		QFile writeTestFile(path); +		if (writeTestFile.open(QIODevice::ReadWrite)) { +			writeTestFile.write("test"); +			if (writeTestFile.error() == QFileDevice::NoError) { +				writable = true; +			} +		} +		writeTestFile.close(); +		writeTestFile.remove(); +		return writable; +	} +} + +void QtWebKitChatView::setFileTransferWarning(QString id, QString warningText) { +	QWebElement ftElement = findElementWithID(document_, "div", id); +	if (ftElement.isNull()) { +		SWIFT_LOG(debug) << "Tried to access FT UI via invalid id! id = " << Q2PSTRING(id) << std::endl; +		return; +	} + +	removeFileTransferWarning(id); +	ftElement.appendInside(QString("<div class='ft_warning' style='color: red;'><br/>%1</div>").arg(QtUtilities::htmlEscape(warningText))); +} + +void QtWebKitChatView::removeFileTransferWarning(QString id) { +	QWebElement ftElement = findElementWithID(document_, "div", id); +	if (ftElement.isNull()) { +		SWIFT_LOG(debug) << "Tried to access FT UI via invalid id! id = " << Q2PSTRING(id) << std::endl; +		return; +	} + +	QWebElement warningElement = ftElement.findFirst(".ft_warning"); +	if (!warningElement.isNull()) { +		warningElement.removeFromDocument(); +	} +} +  void QtWebKitChatView::handleHTMLButtonClicked(QString id, QString encodedArgument1, QString encodedArgument2, QString encodedArgument3, QString encodedArgument4, QString encodedArgument5) {  	QString arg1 = decodeButtonArgument(encodedArgument1);  	QString arg2 = decodeButtonArgument(encodedArgument2); @@ -777,9 +822,13 @@ void QtWebKitChatView::handleHTMLButtonClicked(QString id, QString encodedArgume  		QString filename = arg2;  		QString path = QFileDialog::getSaveFileName(this, tr("Save File"), filename); -		if (!path.isEmpty()) { +		if (!path.isEmpty() && isFilePathWritable(path)) {  			filePaths_[ft_id] = path;  			window_->onFileTransferAccept(Q2PSTRING(ft_id), Q2PSTRING(path)); +			removeFileTransferWarning(ft_id); +		} +		else { +			setFileTransferWarning(ft_id, tr("The chosen save location is not writable! Click the 'Accept' button to select a different save location."));  		}  	}  	else if (id.startsWith(ButtonFileTransferOpenFile)) { diff --git a/Swift/QtUI/QtWebKitChatView.h b/Swift/QtUI/QtWebKitChatView.h index 99375f7..173a05b 100644 --- a/Swift/QtUI/QtWebKitChatView.h +++ b/Swift/QtUI/QtWebKitChatView.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -95,6 +95,8 @@ namespace Swift {  			void addToJSEnvironment(const QString&, QObject*);  			void setFileTransferProgress(QString id, const int percentageDone);  			void setFileTransferStatus(QString id, const ChatWindow::FileTransferState state, const QString& msg); +			void setFileTransferWarning(QString id, QString warningText); +			void removeFileTransferWarning(QString id);  			void setWhiteboardSessionStatus(QString id, const ChatWindow::WhiteboardSessionState state);  			void setMUCInvitationJoined(QString id);  			void askDesktopToOpenFile(const QString& filename); diff --git a/Swiften/FileTransfer/ByteArrayWriteBytestream.h b/Swiften/FileTransfer/ByteArrayWriteBytestream.h index 938b1d4..08c4d4b 100644 --- a/Swiften/FileTransfer/ByteArrayWriteBytestream.h +++ b/Swiften/FileTransfer/ByteArrayWriteBytestream.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -15,9 +15,10 @@ namespace Swift {  			ByteArrayWriteBytestream() {  			} -			virtual void write(const std::vector<unsigned char>& bytes) { +			virtual bool write(const std::vector<unsigned char>& bytes) {  				data.insert(data.end(), bytes.begin(), bytes.end());  				onWrite(bytes); +				return true;  			}  			const std::vector<unsigned char>& getData() const { diff --git a/Swiften/FileTransfer/FileTransferError.h b/Swiften/FileTransfer/FileTransferError.h index 67e32f2..eff8ca9 100644 --- a/Swiften/FileTransfer/FileTransferError.h +++ b/Swiften/FileTransfer/FileTransferError.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -15,6 +15,7 @@ namespace Swift {  				UnknownError,  				PeerError,  				ReadError, +				WriteError,  				ClosedError  			}; diff --git a/Swiften/FileTransfer/FileWriteBytestream.cpp b/Swiften/FileTransfer/FileWriteBytestream.cpp index bbf3d51..c39d63a 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.cpp +++ b/Swiften/FileTransfer/FileWriteBytestream.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -24,16 +24,21 @@ FileWriteBytestream::~FileWriteBytestream() {  	}  } -void FileWriteBytestream::write(const std::vector<unsigned char>& data) { +bool FileWriteBytestream::write(const std::vector<unsigned char>& data) {  	if (data.empty()) { -		return; +		return true;  	}  	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[0]), boost::numeric_cast<std::streamsize>(data.size())); -	onWrite(data); +	if (stream->good()) { +		stream->write(reinterpret_cast<const char*>(&data[0]), boost::numeric_cast<std::streamsize>(data.size())); +		if (stream->good()) { +			onWrite(data); +			return true; +		} +	} +	return false;  }  void FileWriteBytestream::close() { diff --git a/Swiften/FileTransfer/FileWriteBytestream.h b/Swiften/FileTransfer/FileWriteBytestream.h index b2d3347..02e1b46 100644 --- a/Swiften/FileTransfer/FileWriteBytestream.h +++ b/Swiften/FileTransfer/FileWriteBytestream.h @@ -18,7 +18,7 @@ namespace Swift {  			FileWriteBytestream(const boost::filesystem::path& file);  			virtual ~FileWriteBytestream(); -			virtual void write(const std::vector<unsigned char>&); +			virtual bool write(const std::vector<unsigned char>&);  			void close();  		private: diff --git a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp index a38501b..4fc0246 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamClientSession.cpp @@ -5,7 +5,7 @@   */  /* - * Copyright (c) 2013-2015 Isode Limited. + * Copyright (c) 2013-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -166,7 +166,6 @@ void SOCKS5BytestreamClientSession::startReceiving(boost::shared_ptr<WriteBytest  		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; diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp index 7838dd1..0e1eb6b 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010-2013 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -8,16 +8,15 @@  #include <boost/bind.hpp>  #include <boost/numeric/conversion/cast.hpp> -#include <iostream> -#include <Swiften/Base/ByteArray.h> -#include <Swiften/Base/SafeByteArray.h>  #include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/ByteArray.h>  #include <Swiften/Base/Concat.h>  #include <Swiften/Base/Log.h> -#include <Swiften/Network/HostAddressPort.h> -#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/Base/SafeByteArray.h>  #include <Swiften/FileTransfer/BytestreamException.h> +#include <Swiften/FileTransfer/SOCKS5BytestreamRegistry.h> +#include <Swiften/Network/HostAddressPort.h>  namespace Swift { @@ -34,8 +33,8 @@ SOCKS5BytestreamServerSession::SOCKS5BytestreamServerSession(  SOCKS5BytestreamServerSession::~SOCKS5BytestreamServerSession() {  	if (state != Finished && state != Initial) { -		std::cerr << "Warning: SOCKS5BytestreamServerSession unfinished" << std::endl; -		finish(false); +		SWIFT_LOG(warning) << "SOCKS5BytestreamServerSession unfinished" << std::endl; +		finish();  	}  } @@ -47,7 +46,7 @@ void SOCKS5BytestreamServerSession::start() {  }  void SOCKS5BytestreamServerSession::stop() { -	finish(false); +	finish();  }  void SOCKS5BytestreamServerSession::startSending(boost::shared_ptr<ReadBytestream> stream) { @@ -81,8 +80,9 @@ void SOCKS5BytestreamServerSession::handleDataRead(boost::shared_ptr<SafeByteArr  		append(unprocessedData, *data);  		process();  	} else { -		writeBytestream->write(createByteArray(vecptr(*data), data->size())); -		// onBytesReceived(data->size()); +		if (!writeBytestream->write(createByteArray(vecptr(*data), data->size()))) { +			finish(boost::optional<FileTransferError>(FileTransferError::WriteError)); +		}  	}  } @@ -94,7 +94,7 @@ void SOCKS5BytestreamServerSession::handleDataAvailable() {  void SOCKS5BytestreamServerSession::handleDisconnected(const boost::optional<Connection::Error>& error) {  	SWIFT_LOG(debug) << (error ? (error == Connection::ReadError ? "Read Error" : "Write Error") : "No Error") << std::endl; -	finish(error ? true : false); +	finish(error ? boost::optional<FileTransferError>(FileTransferError::PeerError) : boost::optional<FileTransferError>());  }  void SOCKS5BytestreamServerSession::process() { @@ -143,7 +143,7 @@ void SOCKS5BytestreamServerSession::process() {  				if (!hasBytestream) {  					SWIFT_LOG(debug) << "Readstream or Wrtiestream with ID " << streamID << " not found!" << std::endl;  					connection->write(result); -					finish(true); +					finish(boost::optional<FileTransferError>(FileTransferError::PeerError));  				}  				else {  					SWIFT_LOG(debug) << "Found stream. Sent OK." << std::endl; @@ -169,16 +169,16 @@ void SOCKS5BytestreamServerSession::sendData() {  			}  		}  		catch (const BytestreamException&) { -			finish(true); +			finish(boost::optional<FileTransferError>(FileTransferError::PeerError));  		}  	}  	else { -		finish(false); +		finish();  	}  } -void SOCKS5BytestreamServerSession::finish(bool error) { -	SWIFT_LOG(debug) << error << " " << state << std::endl; +void SOCKS5BytestreamServerSession::finish(const boost::optional<FileTransferError>& error) { +	SWIFT_LOG(debug) << "state: " << state << std::endl;  	if (state == Finished) {  		return;  	} @@ -189,11 +189,7 @@ void SOCKS5BytestreamServerSession::finish(bool error) {  	dataAvailableConnection.disconnect();  	readBytestream.reset();  	state = Finished; -	if (error) { -		onFinished(boost::optional<FileTransferError>(FileTransferError::PeerError)); -	} else { -		onFinished(boost::optional<FileTransferError>()); -	} +	onFinished(error);  }  } diff --git a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h index d8eea34..ed5272f 100644 --- a/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h +++ b/Swiften/FileTransfer/SOCKS5BytestreamServerSession.h @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -10,10 +10,10 @@  #include <Swiften/Base/API.h>  #include <Swiften/Base/boost_bsignals.h> -#include <Swiften/Network/Connection.h> +#include <Swiften/FileTransfer/FileTransferError.h>  #include <Swiften/FileTransfer/ReadBytestream.h>  #include <Swiften/FileTransfer/WriteBytestream.h> -#include <Swiften/FileTransfer/FileTransferError.h> +#include <Swiften/Network/Connection.h>  namespace Swift {  	class SOCKS5BytestreamRegistry; @@ -50,14 +50,13 @@ namespace Swift {  			boost::signal<void (boost::optional<FileTransferError>)> onFinished;  			boost::signal<void (unsigned long long)> onBytesSent; -			// boost::signal<void (unsigned long long)> onBytesReceived;  			const std::string& getStreamID() const {  				return streamID;  			}  		private: -			void finish(bool error); +			void finish(const boost::optional<FileTransferError>& error = boost::optional<FileTransferError>());  			void process();  			void handleDataRead(boost::shared_ptr<SafeByteArray>);  			void handleDisconnected(const boost::optional<Connection::Error>&); diff --git a/Swiften/FileTransfer/WriteBytestream.h b/Swiften/FileTransfer/WriteBytestream.h index 3299620..76237c4 100644 --- a/Swiften/FileTransfer/WriteBytestream.h +++ b/Swiften/FileTransfer/WriteBytestream.h @@ -1,14 +1,15 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */  #pragma once -#include <boost/shared_ptr.hpp>  #include <vector> +#include <boost/shared_ptr.hpp> +  #include <Swiften/Base/API.h>  #include <Swiften/Base/boost_bsignals.h> @@ -19,7 +20,12 @@ namespace Swift {  			virtual ~WriteBytestream(); -			virtual void write(const std::vector<unsigned char>&) = 0; +			/** +			 * Write data from vector argument to bytestream. +			 *  +			 * On success true is returned and \ref onWrite is called. On failure false is returned. +			 */ +			virtual bool write(const std::vector<unsigned char>&) = 0;  			boost::signal<void (const std::vector<unsigned char>&)> onWrite;  	}; diff --git a/Swiften/QA/SConscript b/Swiften/QA/SConscript index 2135ef4..2c588e5 100644 --- a/Swiften/QA/SConscript +++ b/Swiften/QA/SConscript @@ -5,7 +5,7 @@ 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 c36420a..d70d9c9 100644 --- a/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp +++ b/Swiften/QA/StorageTest/FileReadBytestreamTest.cpp @@ -1,5 +1,5 @@  /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2016 Isode Limited.   * All rights reserved.   * See the COPYING file for more information.   */ @@ -9,7 +9,8 @@  #include <Swiften/Base/ByteArray.h>  #include <Swiften/FileTransfer/FileReadBytestream.h> -#include "SwifTools/Application/PlatformApplicationPathProvider.h" + +#include <SwifTools/Application/PlatformApplicationPathProvider.h>  using namespace Swift; @@ -33,18 +34,18 @@ class FileReadBytestreamTest : public CppUnit::TestFixture {  		void testRead() {  			boost::shared_ptr<FileReadBytestream> testling(createTestling()); -			std::vector<unsigned char> result = testling->read(10); +			boost::shared_ptr< std::vector<unsigned char> > result = testling->read(10); -			CPPUNIT_ASSERT(ByteArray::create("/*\n * Copy") == result); +			CPPUNIT_ASSERT(createByteArray("/*\n * Copy") == *result.get());  		}  		void testRead_Twice() {  			boost::shared_ptr<FileReadBytestream> testling(createTestling());  			testling->read(10); -			ByteArray result(testling->read(10)); +			boost::shared_ptr< std::vector<unsigned char> > result = testling->read(10); -			CPPUNIT_ASSERT_EQUAL(std::string("right (c) "), result.toString()); +			CPPUNIT_ASSERT_EQUAL(std::string("right (c) "), byteArrayToString(*result));  		}  		void testIsFinished_NotFinished() { diff --git a/Swiften/QA/StorageTest/FileWriteBytestreamTest.cpp b/Swiften/QA/StorageTest/FileWriteBytestreamTest.cpp new file mode 100644 index 0000000..3686cf9 --- /dev/null +++ b/Swiften/QA/StorageTest/FileWriteBytestreamTest.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <boost/bind.hpp> +#include <boost/filesystem.hpp> + +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/FileTransfer/FileWriteBytestream.h> + +using namespace Swift; + +class FileWriteBytestreamTest : public CppUnit::TestFixture { +		CPPUNIT_TEST_SUITE(FileWriteBytestreamTest); +		CPPUNIT_TEST(testSuccessfulWrite); +		CPPUNIT_TEST(testFailingWrite); +		CPPUNIT_TEST_SUITE_END(); + +	public: +		void setUp() { +			onWriteWasCalled = false; +		} + +		void testSuccessfulWrite() { +			boost::filesystem::path filename = boost::filesystem::unique_path("write_file_bytestream_test_%%%%%%%%%%%%%%%%.bin"); +			boost::shared_ptr<WriteBytestream> writeBytestream = boost::make_shared<FileWriteBytestream>(filename.string()); +			writeBytestream->onWrite.connect(boost::bind(&FileWriteBytestreamTest::handleOnWrite, this, _1)); + +			CPPUNIT_ASSERT_EQUAL(true, writeBytestream->write(createByteArray("Some data."))); +			CPPUNIT_ASSERT_EQUAL(true, onWriteWasCalled); + +			boost::filesystem::remove(filename); +		} + +		void testFailingWrite() { +			boost::shared_ptr<WriteBytestream> writeBytestream = boost::make_shared<FileWriteBytestream>(""); +			writeBytestream->onWrite.connect(boost::bind(&FileWriteBytestreamTest::handleOnWrite, this, _1)); + +			CPPUNIT_ASSERT_EQUAL(false, writeBytestream->write(createByteArray("Some data."))); +			CPPUNIT_ASSERT_EQUAL(false, onWriteWasCalled); +		} + + +		void handleOnWrite(const std::vector<unsigned char>& /*data*/) { +			onWriteWasCalled = true; +		} + +	private: +		bool onWriteWasCalled; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(FileWriteBytestreamTest); diff --git a/Swiften/QA/StorageTest/SConscript b/Swiften/QA/StorageTest/SConscript index 6d65b30..fff2a2b 100644 --- a/Swiften/QA/StorageTest/SConscript +++ b/Swiften/QA/StorageTest/SConscript @@ -15,7 +15,8 @@ if env["TEST"] :  	myenv.MergeFlags(myenv["PLATFORM_FLAGS"])  	tester = myenv.Program("StorageTest", [ -			"VCardFileStorageTest.cpp", +			#"VCardFileStorageTest.cpp",  			"FileReadBytestreamTest.cpp", +			"FileWriteBytestreamTest.cpp",  		])  	myenv.Test(tester, "system", is_checker = True) | 
 Swift
 Swift