From a74debb40c3df12738c722548c556a97e5976036 Mon Sep 17 00:00:00 2001
From: aunsane <aunsane@gmail.com>
Date: Sat, 21 Apr 2018 20:45:34 +0300
Subject: CloudFile: - fix #1278 - decrease volume of response data with fields
 filtering - fix uploading for gdrive and onedrive in some cases - simplifying
 upload code - version bump

---
 plugins/CloudFile/src/Services/dropbox_api.h       |   1 +
 plugins/CloudFile/src/Services/dropbox_service.cpp | 148 +++++++++------------
 plugins/CloudFile/src/Services/dropbox_service.h   |   4 +-
 plugins/CloudFile/src/Services/google_api.h        |  37 +++++-
 plugins/CloudFile/src/Services/google_service.cpp  | 107 ++++++++-------
 plugins/CloudFile/src/Services/google_service.h    |   6 +-
 plugins/CloudFile/src/Services/microsoft_api.h     |  20 ++-
 .../CloudFile/src/Services/microsoft_service.cpp   |  95 ++++++-------
 plugins/CloudFile/src/Services/microsoft_service.h |   6 +-
 plugins/CloudFile/src/Services/yandex_api.h        |   4 +
 plugins/CloudFile/src/Services/yandex_service.cpp  |  94 ++++++-------
 plugins/CloudFile/src/Services/yandex_service.h    |   4 +-
 plugins/CloudFile/src/cloud_file.cpp               |  27 +++-
 plugins/CloudFile/src/cloud_file.h                 |   6 +-
 plugins/CloudFile/src/file_transfer.h              |  51 +++----
 plugins/CloudFile/src/http_request.h               |  12 ++
 plugins/CloudFile/src/services.cpp                 |  25 ++--
 plugins/CloudFile/src/transfers.cpp                |   2 +-
 plugins/CloudFile/src/utils.cpp                    |   6 +-
 plugins/CloudFile/src/version.h                    |   2 +-
 plugins/Db_autobackups/src/backup.cpp              |   1 +
 plugins/ExternalAPI/m_cloudfile.h                  |  26 +---
 plugins/SendScreenshotPlus/src/CSendCloudFile.cpp  |  12 +-
 23 files changed, 346 insertions(+), 350 deletions(-)

(limited to 'plugins')

diff --git a/plugins/CloudFile/src/Services/dropbox_api.h b/plugins/CloudFile/src/Services/dropbox_api.h
index a4ebe5910d..e7e77600c0 100644
--- a/plugins/CloudFile/src/Services/dropbox_api.h
+++ b/plugins/CloudFile/src/Services/dropbox_api.h
@@ -1,6 +1,7 @@
 #ifndef _DROPBOXSERVICE_API_H_
 #define _DROPBOXSERVICE_API_H_
 
+// https://www.dropbox.com/developers/documentation/http/documentation
 namespace DropboxAPI
 {
 #define DROPBOX_API_VER "/2"
diff --git a/plugins/CloudFile/src/Services/dropbox_service.cpp b/plugins/CloudFile/src/Services/dropbox_service.cpp
index 528cb8e386..41b72b9de3 100644
--- a/plugins/CloudFile/src/Services/dropbox_service.cpp
+++ b/plugins/CloudFile/src/Services/dropbox_service.cpp
@@ -168,13 +168,17 @@ void CDropboxService::CreateFolder(const std::string &path)
 	DropboxAPI::CreateFolderRequest request(token, path.c_str());
 	NLHR_PTR response(request.Send(m_hConnection));
 
-	HandleHttpError(response);
+	if (HTTP_CODE_SUCCESS(response->resultCode)) {
+		GetJsonResponse(response);
+		return;
+	}
 
-	// forder exists on server 
-	if (response->resultCode == HTTP_CODE_FORBIDDEN)
+	// forder exists on server
+	if (response->resultCode == HTTP_CODE_CONFLICT) {
 		return;
+	}
 
-	GetJsonResponse(response);
+	HttpResponseToError(response);
 }
 
 auto CDropboxService::CreateSharedLink(const std::string &path)
@@ -183,16 +187,14 @@ auto CDropboxService::CreateSharedLink(const std::string &path)
 	DropboxAPI::CreateSharedLinkRequest shareRequest(token, path.c_str());
 	NLHR_PTR response(shareRequest.Send(m_hConnection));
 
-	if (response == nullptr)
-		throw Exception(HttpStatusToError());
-
-	if (!HTTP_CODE_SUCCESS(response->resultCode) &&
-		response->resultCode != HTTP_CODE_CONFLICT) {
-		if (response->dataLength)
-			throw Exception(response->pData);
-		throw Exception(HttpStatusToError(response->resultCode));
+	if (response && HTTP_CODE_SUCCESS(response->resultCode)) {
+		JSONNode root = GetJsonResponse(response);
+		return root["url"].as_string();
 	}
 
+	if (!response || response->resultCode != HTTP_CODE_CONFLICT)
+		HttpResponseToError(response);
+
 	JSONNode root = JSONNode::parse(response->pData);
 	if (root.isnull())
 		throw Exception(HttpStatusToError());
@@ -217,93 +219,73 @@ auto CDropboxService::CreateSharedLink(const std::string &path)
 	return link.as_string();
 }
 
-UINT CDropboxService::Upload(FileTransferParam *ftp)
+void CDropboxService::Upload(FileTransferParam *ftp)
 {
-	if (!IsLoggedIn())
-		Login();
-
-	try {
-		if (ftp->IsFolder()) {
-			T2Utf folderName(ftp->GetFolderName());
-
-			auto path = PreparePath(folderName);
-			CreateFolder(path);
-
-			auto link = CreateSharedLink(path);
-			ftp->AddSharedLink(link.c_str());
-		}
-
-		ftp->FirstFile();
-		do
-		{
-			T2Utf fileName(ftp->GetCurrentRelativeFilePath());
-			uint64_t fileSize = ftp->GetCurrentFileSize();
-
-			size_t chunkSize = ftp->GetCurrentFileChunkSize();
-			mir_ptr<char>chunk((char*)mir_calloc(chunkSize));
-
-			std::string path;
-			auto serverFolder = ftp->GetServerFolder();
-			if (serverFolder) {
-				char serverPath[MAX_PATH] = { 0 };
-				mir_snprintf(serverPath, "%s\\%s", T2Utf(serverFolder), fileName);
-				path = PreparePath(serverPath);
-			}
-			else
-				path = PreparePath(fileName);
+	std::string serverFolder = T2Utf(ftp->GetServerDirectory());
+	if (!serverFolder.empty()) {
+		auto path = PreparePath(serverFolder);
+		auto link = CreateSharedLink(path);
+		ftp->AddSharedLink(link.c_str());
+	}
 
-			if (chunkSize == fileSize) {
-				ftp->CheckCurrentFile();
-				size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+	ftp->FirstFile();
+	do
+	{
+		std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+		uint64_t fileSize = ftp->GetCurrentFileSize();
 
-				path = UploadFile(chunk, size, path);
+		size_t chunkSize = ftp->GetCurrentFileChunkSize();
+		mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
 
-				ftp->Progress(size);
-			}
-			else {
-				ftp->CheckCurrentFile();
-				size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+		std::string path;
+		if (!serverFolder.empty())
+			path = "/" + serverFolder + "/" + fileName;
+		else
+			path = PreparePath(fileName);
 
-				auto sessionId = CreateUploadSession(chunk, size);
+		if (chunkSize == fileSize) {
+			ftp->CheckCurrentFile();
+			size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
 
-				ftp->Progress(size);
+			path = UploadFile(chunk, size, path);
 
-				size_t offset = size;
-				double chunkCount = ceil(double(fileSize) / chunkSize) - 2;
-				for (size_t i = 0; i < chunkCount; i++) {
-					ftp->CheckCurrentFile();
+			ftp->Progress(size);
+		}
+		else {
+			ftp->CheckCurrentFile();
+			size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
 
-					size = ftp->ReadCurrentFile(chunk, chunkSize);
-					UploadFileChunk(sessionId, chunk, size, offset);
+			auto sessionId = CreateUploadSession(chunk, size);
 
-					offset += size;
-					ftp->Progress(size);
-				}
+			ftp->Progress(size);
 
+			size_t offset = size;
+			double chunkCount = ceil(double(fileSize) / chunkSize) - 2;
+			for (size_t i = 0; i < chunkCount; i++) {
 				ftp->CheckCurrentFile();
-				size = offset < fileSize
-					? ftp->ReadCurrentFile(chunk, fileSize - offset)
-					: 0;
 
-				path = CommitUploadSession(sessionId, chunk, size, offset, path);
+				size = ftp->ReadCurrentFile(chunk, chunkSize);
+				UploadFileChunk(sessionId, chunk, size, offset);
 
+				offset += size;
 				ftp->Progress(size);
 			}
 
-			if (!ftp->IsFolder()) {
-				auto link = CreateSharedLink(path);
-				ftp->AddSharedLink(link.c_str());
-			}
-		} while (ftp->NextFile());
-	}
-	catch (Exception &ex) {
-		debugLogA("%s: %s", GetModuleName(), ex.what());
-		ftp->SetStatus(ACKRESULT_FAILED);
-		return ACKRESULT_FAILED;
-	}
+			ftp->CheckCurrentFile();
+			size = offset < fileSize
+				? ftp->ReadCurrentFile(chunk, fileSize - offset)
+				: 0;
+
+			path = CommitUploadSession(sessionId, chunk, size, offset, path);
+
+			ftp->Progress(size);
+		}
 
-	ftp->SetStatus(ACKRESULT_SUCCESS);
-	return ACKRESULT_SUCCESS;
+		if (!ftp->IsCurrentFileInSubDirectory()) {
+			auto link = CreateSharedLink(path);
+			ftp->AddSharedLink(link.c_str());
+		}
+	} while (ftp->NextFile());
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -318,4 +300,4 @@ struct CMPluginDropbox : public PLUGIN<CMPluginDropbox>
 		RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)CDropboxService::Init, (pfnUninitProto)CDropboxService::UnInit);
 	}
 }
-	g_pluginDropbox;
+g_pluginDropbox;
diff --git a/plugins/CloudFile/src/Services/dropbox_service.h b/plugins/CloudFile/src/Services/dropbox_service.h
index 5289dc321c..793a27d52b 100644
--- a/plugins/CloudFile/src/Services/dropbox_service.h
+++ b/plugins/CloudFile/src/Services/dropbox_service.h
@@ -16,6 +16,8 @@ private:
 	void CreateFolder(const std::string &path);
 	auto CreateSharedLink(const std::string &path);
 
+	void Upload(FileTransferParam *ftp) override;
+
 public:
 	CDropboxService(const char *protoName, const wchar_t *userName);
 
@@ -29,8 +31,6 @@ public:
 	bool IsLoggedIn() override;
 	void Login(HWND owner = nullptr) override;
 	void Logout() override;
-
-	UINT Upload(FileTransferParam *ftp) override;
 };
 
 #endif //_CLOUDSERVICE_DROPBOX_H_
\ No newline at end of file
diff --git a/plugins/CloudFile/src/Services/google_api.h b/plugins/CloudFile/src/Services/google_api.h
index 793d0053c3..2020e7db23 100644
--- a/plugins/CloudFile/src/Services/google_api.h
+++ b/plugins/CloudFile/src/Services/google_api.h
@@ -1,6 +1,7 @@
 #ifndef _GDRIVESERVICE_API_H_
 #define _GDRIVESERVICE_API_H_
 
+// https://developers.google.com/drive/v3/reference/
 namespace GDriveAPI
 {
 #define GOOGLE_OAUTH "https://accounts.google.com/o/oauth2/v2"
@@ -62,6 +63,8 @@ namespace GDriveAPI
 		UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size) :
 			HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)
 		{
+			AddUrlParameter("fields=id");
+
 			AddBearerAuthHeader(token);
 			AddHeader("Content-Type", "multipart/related; boundary=upload");
 
@@ -73,7 +76,7 @@ namespace GDriveAPI
 			body.Append("{");
 			body.AppendFormat("\"name\": \"%s\"", name);
 			if (mir_strlen(parentId))
-				body.AppendFormat("\"parents\": [\"%s\"]", parentId);
+				body.AppendFormat(", \"parents\": [\"%s\"]", parentId);
 			body.Append("}");
 			body.AppendChar(0x0A);
 			body.AppendChar(0x0A);
@@ -121,6 +124,8 @@ namespace GDriveAPI
 		UploadFileChunkRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize):
 			HttpRequest(REQUEST_PUT, uploadUri)
 		{
+			AddUrlParameter("fields=id");
+
 			uint64_t rangeMin = offset;
 			uint64_t rangeMax = offset + chunkSize - 1;
 			CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
@@ -130,19 +135,39 @@ namespace GDriveAPI
 		}
 	};
 
+	class GetFolderRequest : public HttpRequest
+	{
+	public:
+		GetFolderRequest(const char *token, const char *parentId, const char *name) :
+			HttpRequest(REQUEST_GET, GDRIVE_API)
+		{
+			AddUrlParameterWithEncode("q", "mimeType = 'application/vnd.google-apps.folder' and trashed = false and '%s' in parents and name = '%s'", mir_strlen(parentId) ? parentId : "root", name);
+			AddUrlParameterWithEncode("fields", "files(id)");
+
+			AddBearerAuthHeader(token);
+		}
+	};
+
 	class CreateFolderRequest : public HttpRequest
 	{
 	public:
-		CreateFolderRequest(const char *token, const char *path) :
-			HttpRequest(REQUEST_PUT, GDRIVE_API)
+		CreateFolderRequest(const char *token, const char *parentId, const char *name) :
+			HttpRequest(REQUEST_POST, GDRIVE_API)
 		{
+			AddUrlParameter("fields=id");
+
 			AddBearerAuthHeader(token);
 			AddHeader("Content-Type", "application/json");
 
+			JSONNode parents(JSON_ARRAY);
+			parents.set_name("parents");
+			parents.push_back(JSONNode("", parentId));
+
 			JSONNode params(JSON_NODE);
 			params
-				<< JSONNode("name", path)
-				<< JSONNode("mimeType", "application/vnd.google-apps.folder");
+				<< JSONNode("name", name)
+				<< JSONNode("mimeType", "application/vnd.google-apps.folder")
+				<< parents;
 
 			json_string data = params.write();
 			SetData(data.c_str(), data.length());
@@ -155,6 +180,8 @@ namespace GDriveAPI
 		GrantPermissionsRequest(const char *token, const char *fileId) :
 			HttpRequest(REQUEST_POST, FORMAT, GDRIVE_API "/%s/permissions", fileId)
 		{
+			AddUrlParameter("fields=id");
+
 			AddBearerAuthHeader(token);
 			AddHeader("Content-Type", "application/json");
 
diff --git a/plugins/CloudFile/src/Services/google_service.cpp b/plugins/CloudFile/src/Services/google_service.cpp
index 05befd78f7..76821deb2d 100644
--- a/plugins/CloudFile/src/Services/google_service.cpp
+++ b/plugins/CloudFile/src/Services/google_service.cpp
@@ -180,6 +180,8 @@ auto CGDriveService::CreateUploadSession(const std::string &parentId, const std:
 	}
 
 	HttpResponseToError(response);
+
+	return std::string();
 }
 
 auto CGDriveService::UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize)
@@ -198,15 +200,25 @@ auto CGDriveService::UploadFileChunk(const std::string &uploadUri, const char *c
 	}
 
 	HttpResponseToError(response);
+
+	return std::string();
 }
 
-auto CGDriveService::CreateFolder(const char *path)
+auto CGDriveService::CreateFolder(const std::string &parentId, const std::string &name)
 {
 	ptrA token(getStringA("TokenSecret"));
-	GDriveAPI::CreateFolderRequest request(token, path);
-	NLHR_PTR response(request.Send(m_hConnection));
+	GDriveAPI::GetFolderRequest getFolderRequest(token, parentId.c_str(), name.c_str());
+	NLHR_PTR response(getFolderRequest.Send(m_hConnection));
 
 	JSONNode root = GetJsonResponse(response);
+	JSONNode files = root["files"].as_array();
+	if (files.size() > 0)
+		return files[(size_t)0]["id"].as_string();
+
+	GDriveAPI::CreateFolderRequest createFolderRequest(token, parentId.c_str(), name.c_str());
+	response = createFolderRequest.Send(m_hConnection);
+
+	root = GetJsonResponse(response);
 	return root["id"].as_string();
 }
 
@@ -225,69 +237,54 @@ auto CGDriveService::CreateSharedLink(const std::string &itemId)
 	}
 
 	HttpResponseToError(response);
+
+	return std::string();
 }
 
-UINT CGDriveService::Upload(FileTransferParam *ftp)
+void CGDriveService::Upload(FileTransferParam *ftp)
 {
-	try {
-		if (!IsLoggedIn())
-			Login();
-
-		if (!IsLoggedIn()) {
-			ftp->SetStatus(ACKRESULT_FAILED);
-			return ACKRESULT_FAILED;
-		}
+	std::string folderId;
+	std::string serverFolder = T2Utf(ftp->GetServerDirectory());
+	if (!serverFolder.empty()) {
+		folderId = CreateFolder(folderId, serverFolder);
+		auto link = CreateSharedLink(folderId);
+		ftp->AddSharedLink(link.c_str());
+	}
 
-		std::string folderId;
-		if (ftp->IsFolder()) {
-			folderId = CreateFolder(T2Utf(ftp->GetFolderName()));
-			auto link = CreateSharedLink(folderId);
-			ftp->AddSharedLink(link.c_str());
-		}
+	ftp->FirstFile();
+	do {
+		std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+		uint64_t fileSize = ftp->GetCurrentFileSize();
 
-		ftp->FirstFile();
-		do {
-			std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath()).get();
-			uint64_t fileSize = ftp->GetCurrentFileSize();
+		size_t chunkSize = ftp->GetCurrentFileChunkSize();
+		mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
 
-			size_t chunkSize = ftp->GetCurrentFileChunkSize();
-			mir_ptr<char>chunk((char*)mir_calloc(chunkSize));
+		std::string fileId;
+		if (chunkSize == fileSize) {
+			ftp->CheckCurrentFile();
+			size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+			fileId = UploadFile(folderId, fileName, chunk, size);
+			ftp->Progress(size);
+		}
+		else {
+			auto uploadUri = CreateUploadSession(folderId, fileName);
 
-			std::string fileId;
-			if (chunkSize == fileSize) {
+			uint64_t offset = 0;
+			double chunkCount = ceil(double(fileSize) / chunkSize);
+			for (size_t i = 0; i < chunkCount; i++) {
 				ftp->CheckCurrentFile();
 				size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
-				fileId = UploadFile(folderId, fileName, chunk, size);
+				fileId = UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
+				offset += size;
 				ftp->Progress(size);
 			}
-			else {
-				auto uploadUri = CreateUploadSession(folderId, fileName);
-
-				uint64_t offset = 0;
-				double chunkCount = ceil(double(fileSize) / chunkSize);
-				for (size_t i = 0; i < chunkCount; i++) {
-					ftp->CheckCurrentFile();
-					size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
-					fileId = UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
-					offset += size;
-					ftp->Progress(size);
-				}
-			}
-
-			if (!ftp->IsFolder()) {
-				auto link = CreateSharedLink(fileId);
-				ftp->AddSharedLink(link.c_str());
-			}
-		} while (ftp->NextFile());
-	}
-	catch (Exception &ex) {
-		debugLogA("%s: %s", GetAccountName(), ex.what());
-		ftp->SetStatus(ACKRESULT_FAILED);
-		return ACKRESULT_FAILED;
-	}
+		}
 
-	ftp->SetStatus(ACKRESULT_SUCCESS);
-	return ACKRESULT_SUCCESS;
+		if (!ftp->IsCurrentFileInSubDirectory()) {
+			auto link = CreateSharedLink(fileId);
+			ftp->AddSharedLink(link.c_str());
+		}
+	} while (ftp->NextFile());
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -302,4 +299,4 @@ struct CMPluginGoogle : public CMPluginBase
 		RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)CGDriveService::Init, (pfnUninitProto)CGDriveService::UnInit);
 	}
 }
-	g_pluginGoogle;
+g_pluginGoogle;
diff --git a/plugins/CloudFile/src/Services/google_service.h b/plugins/CloudFile/src/Services/google_service.h
index 717e6314b0..35d5f528fb 100644
--- a/plugins/CloudFile/src/Services/google_service.h
+++ b/plugins/CloudFile/src/Services/google_service.h
@@ -12,9 +12,11 @@ private:
 	auto UploadFile(const std::string &parentId, const std::string &fileName, const char *data, size_t size);
 	auto CreateUploadSession(const std::string &parentId, const std::string &fileName);
 	auto UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize);
-	auto CreateFolder(const char *path);
+	auto CreateFolder(const std::string &parentId, const std::string &name);
 	auto CreateSharedLink(const std::string &itemId);
 
+	void Upload(FileTransferParam *ftp) override;
+
 public:
 	CGDriveService(const char *protoName, const wchar_t *userName);
 
@@ -28,8 +30,6 @@ public:
 	bool IsLoggedIn() override;
 	void Login(HWND owner = nullptr) override;
 	void Logout() override;
-
-	UINT Upload(FileTransferParam *ftp) override;
 };
 
 #endif //_CLOUDFILE_GDRIVE_H_
\ No newline at end of file
diff --git a/plugins/CloudFile/src/Services/microsoft_api.h b/plugins/CloudFile/src/Services/microsoft_api.h
index 5c8abafeb3..62a2204459 100644
--- a/plugins/CloudFile/src/Services/microsoft_api.h
+++ b/plugins/CloudFile/src/Services/microsoft_api.h
@@ -1,6 +1,7 @@
 #ifndef _ONEDRIVESERVICE_API_H_
 #define _ONEDRIVESERVICE_API_H_
 
+// https://docs.microsoft.com/onedrive/developer/rest-api/
 namespace OneDriveAPI
 {
 #define MICROSOFT_OAUTH "https://login.microsoftonline.com/common/oauth2/v2.0"
@@ -49,6 +50,8 @@ namespace OneDriveAPI
 		UploadFileRequest(const char *token, const char *name, const char *data, size_t size, OnConflict strategy = NONE) :
 			HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/special/approot:/%s:/content", ptrA(mir_urlEncode(name)))
 		{
+			AddUrlParameter("select=id");
+
 			if (strategy == OnConflict::RENAME)
 				AddUrlParameter("@microsoft.graph.conflictBehavior=rename");
 			else if (strategy == OnConflict::REPLACE)
@@ -60,8 +63,10 @@ namespace OneDriveAPI
 		}
 
 		UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size, OnConflict strategy = NONE) :
-			HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/items/{parent-id}:/{filename}:/content", parentId, ptrA(mir_urlEncode(name)))
+			HttpRequest(REQUEST_PUT, FORMAT, ONEDRIVE_API "/items/%s:/%s:/content", parentId, ptrA(mir_urlEncode(name)))
 		{
+			AddUrlParameter("select=id");
+
 			if (strategy == OnConflict::RENAME)
 				AddUrlParameter("@microsoft.graph.conflictBehavior=rename");
 			else if (strategy == OnConflict::REPLACE)
@@ -76,7 +81,7 @@ namespace OneDriveAPI
 	class CreateUploadSessionRequest : public HttpRequest
 	{
 	public:
-		CreateUploadSessionRequest(const char *token, const char *name,  OnConflict strategy = NONE) :
+		CreateUploadSessionRequest(const char *token, const char *name, OnConflict strategy = NONE) :
 			HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/special/approot:/%s:/createUploadSession", ptrA(mir_urlEncode(name)))
 		{
 			AddBearerAuthHeader(token);
@@ -97,7 +102,7 @@ namespace OneDriveAPI
 		}
 
 		CreateUploadSessionRequest(const char *token, const char *parentId, const char *name, OnConflict strategy = NONE) :
-			HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s:/%s:/createUploadSession", parentId, name)
+			HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s:/%s:/createUploadSession", parentId, ptrA(mir_urlEncode(name)))
 		{
 			AddBearerAuthHeader(token);
 			AddHeader("Content-Type", "application/json");
@@ -123,6 +128,8 @@ namespace OneDriveAPI
 		UploadFileChunkRequest(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) :
 			HttpRequest(REQUEST_PUT, uploadUri)
 		{
+			AddUrlParameter("select=id");
+
 			uint64_t rangeMin = offset;
 			uint64_t rangeMax = offset + chunkSize - 1;
 			CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize);
@@ -136,14 +143,15 @@ namespace OneDriveAPI
 	{
 	public:
 		CreateFolderRequest(const char *token, const char *path) :
-			HttpRequest(REQUEST_PUT, ONEDRIVE_API "/special/approot/children")
+			HttpRequest(REQUEST_POST, ONEDRIVE_API "/special/approot/children")
 		{
+			AddUrlParameter("select=id");
+
 			AddBearerAuthHeader(token);
 			AddHeader("Content-Type", "application/json");
 
 			JSONNode folder(JSON_NODE);
 			folder.set_name("folder");
-			folder << JSONNode(JSON_NODE);
 
 			JSONNode params(JSON_NODE);
 			params
@@ -161,6 +169,8 @@ namespace OneDriveAPI
 		CreateSharedLinkRequest(const char *token, const char *itemId) :
 			HttpRequest(REQUEST_POST, FORMAT, ONEDRIVE_API "/items/%s/createLink", itemId)
 		{
+			AddUrlParameter("select=link");
+
 			AddBearerAuthHeader(token);
 			AddHeader("Content-Type", "application/json");
 
diff --git a/plugins/CloudFile/src/Services/microsoft_service.cpp b/plugins/CloudFile/src/Services/microsoft_service.cpp
index 1de8e52ee9..92a50cbc80 100644
--- a/plugins/CloudFile/src/Services/microsoft_service.cpp
+++ b/plugins/CloudFile/src/Services/microsoft_service.cpp
@@ -184,6 +184,8 @@ auto COneDriveService::UploadFileChunk(const std::string &uploadUri, const char
 	}
 
 	HttpResponseToError(response);
+
+	return std::string();
 }
 
 auto COneDriveService::CreateFolder(const std::string &path)
@@ -206,73 +208,54 @@ auto COneDriveService::CreateSharedLink(const std::string &itemId)
 	return root["link"]["webUrl"].as_string();
 }
 
-UINT COneDriveService::Upload(FileTransferParam *ftp)
+void COneDriveService::Upload(FileTransferParam *ftp)
 {
-	try {
-		if (!IsLoggedIn())
-			Login();
+	std::string folderId;
+	std::string serverFolder = T2Utf(ftp->GetServerDirectory());
+	if (!serverFolder.empty()) {
+		auto path = PreparePath(serverFolder);
+		folderId = CreateFolder(path);
+
+		auto link = CreateSharedLink(path);
+		ftp->AddSharedLink(link.c_str());
+	}
 
-		if (!IsLoggedIn()) {
-			ftp->SetStatus(ACKRESULT_FAILED);
-			return ACKRESULT_FAILED;
-		}
+	ftp->FirstFile();
+	do {
+		std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+		uint64_t fileSize = ftp->GetCurrentFileSize();
 
-		std::string folderId;
-		if (ftp->IsFolder()) {
-			T2Utf folderName(ftp->GetFolderName());
+		size_t chunkSize = ftp->GetCurrentFileChunkSize();
+		mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
 
-			auto path = PreparePath(folderName);
-			folderId = CreateFolder(path);
+		std::string fileId;
+		if (chunkSize == fileSize) {
+			ftp->CheckCurrentFile();
+			size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
 
-			auto link = CreateSharedLink(path);
-			ftp->AddSharedLink(link.c_str());
-		}
+			fileId = UploadFile(folderId, fileName, chunk, size);
 
-		ftp->FirstFile();
-		do {
-			std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
-			uint64_t fileSize = ftp->GetCurrentFileSize();
-
-			size_t chunkSize = ftp->GetCurrentFileChunkSize();
-			mir_ptr<char>chunk((char*)mir_calloc(chunkSize));
+			ftp->Progress(size);
+		}
+		else {
+			auto uploadUri = CreateUploadSession(folderId, fileName);
 
-			std::string fileId;
-			if (chunkSize == fileSize) {
+			uint64_t offset = 0;
+			double chunkCount = ceil(double(fileSize) / chunkSize);
+			for (size_t i = 0; i < chunkCount; i++) {
 				ftp->CheckCurrentFile();
 				size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
-
-				fileId = UploadFile(folderId, fileName, chunk, size);
-
+				fileId = UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
+				offset += size;
 				ftp->Progress(size);
 			}
-			else {
-				auto uploadUri = CreateUploadSession(folderId, fileName);
-
-				uint64_t offset = 0;
-				double chunkCount = ceil(double(fileSize) / chunkSize);
-				for (size_t i = 0; i < chunkCount; i++) {
-					ftp->CheckCurrentFile();
-					size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
-					fileId = UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
-					offset += size;
-					ftp->Progress(size);
-				}
-			}
-
-			if (!ftp->IsFolder()) {
-				auto link = CreateSharedLink(fileId);
-				ftp->AddSharedLink(link.c_str());
-			}
-		} while (ftp->NextFile());
-	}
-	catch (Exception &ex) {
-		debugLogA("%s: %s", GetAccountName(), ex.what());
-		ftp->SetStatus(ACKRESULT_FAILED);
-		return ACKRESULT_FAILED;
-	}
+		}
 
-	ftp->SetStatus(ACKRESULT_SUCCESS);
-	return ACKRESULT_SUCCESS;
+		if (!ftp->IsCurrentFileInSubDirectory()) {
+			auto link = CreateSharedLink(fileId);
+			ftp->AddSharedLink(link.c_str());
+		}
+	} while (ftp->NextFile());
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -287,4 +270,4 @@ struct CMPluginOnedrive : public CMPluginBase
 		RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)COneDriveService::Init, (pfnUninitProto)COneDriveService::UnInit);
 	}
 }
-	g_pluginOnedrive;
+g_pluginOnedrive;
diff --git a/plugins/CloudFile/src/Services/microsoft_service.h b/plugins/CloudFile/src/Services/microsoft_service.h
index 8ae162d45e..895e39ed45 100644
--- a/plugins/CloudFile/src/Services/microsoft_service.h
+++ b/plugins/CloudFile/src/Services/microsoft_service.h
@@ -11,9 +11,11 @@ private:
 	auto UploadFile(const std::string &parentId, const std::string &fileName, const char *data, size_t size);
 	auto CreateUploadSession(const std::string &parentId, const std::string &fileName);
 	auto UploadFileChunk(const std::string &uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize);
-	auto CreateFolder(const std::string &path);
+	auto CreateFolder(const std::string &name);
 	auto CreateSharedLink(const std::string &itemId);
 
+	void Upload(FileTransferParam *ftp) override;
+
 public:
 	COneDriveService(const char *protoName, const wchar_t *userName);
 
@@ -27,8 +29,6 @@ public:
 	bool IsLoggedIn() override;
 	void Login(HWND owner = nullptr) override;
 	void Logout() override;
-
-	UINT Upload(FileTransferParam *ftp) override;
 };
 
 #endif //_CLOUDFILE_ONEDRIVE_H_
\ No newline at end of file
diff --git a/plugins/CloudFile/src/Services/yandex_api.h b/plugins/CloudFile/src/Services/yandex_api.h
index 19c76d61f9..91db0290a1 100644
--- a/plugins/CloudFile/src/Services/yandex_api.h
+++ b/plugins/CloudFile/src/Services/yandex_api.h
@@ -1,6 +1,7 @@
 #ifndef _YANDEXSERVICE_API_H_
 #define _YANDEXSERVICE_API_H_
 
+// https://tech.yandex.ru/disk/api/concepts/about-docpage/
 namespace YandexAPI
 {
 #define YANDEX_OAUTH "https://oauth.yandex.ru"
@@ -60,6 +61,7 @@ namespace YandexAPI
 		{
 			AddOAuthHeader(token);
 			AddUrlParameter("path=app:%s", ptrA(mir_urlEncode(path)));
+			AddUrlParameter("fields=href");
 			if (strategy == OnConflict::REPLACE)
 				AddUrlParameter("overwrite=true");
 		}
@@ -98,6 +100,7 @@ namespace YandexAPI
 		{
 			AddOAuthHeader(token);
 			AddUrlParameter("path=app:%s", ptrA(mir_urlEncode(path)));
+			AddUrlParameter("fields=href");
 		}
 	};
 
@@ -120,6 +123,7 @@ namespace YandexAPI
 		{
 			AddOAuthHeader(token);
 			AddUrlParameter("path=app:%s", ptrA(mir_urlEncode(path)));
+			AddUrlParameter("fields=public_url");
 		}
 	};
 };
diff --git a/plugins/CloudFile/src/Services/yandex_service.cpp b/plugins/CloudFile/src/Services/yandex_service.cpp
index 3e5e63440b..cffe82caa2 100644
--- a/plugins/CloudFile/src/Services/yandex_service.cpp
+++ b/plugins/CloudFile/src/Services/yandex_service.cpp
@@ -218,71 +218,57 @@ auto CYandexService::CreateSharedLink(const std::string &path)
 	return root["public_url"].as_string();
 }
 
-UINT CYandexService::Upload(FileTransferParam *ftp)
+void CYandexService::Upload(FileTransferParam *ftp)
 {
-	try {
-		if (!IsLoggedIn())
-			Login();
+	std::string serverFolder = T2Utf(ftp->GetServerDirectory());
+	if (!serverFolder.empty()) {
+		auto path = PreparePath(serverFolder);
+		CreateFolder(path);
 
-		if (!IsLoggedIn()) {
-			ftp->SetStatus(ACKRESULT_FAILED);
-			return ACKRESULT_FAILED;
-		}
-
-		if (ftp->IsFolder()) {
-			T2Utf folderName(ftp->GetFolderName());
-
-			auto path = PreparePath(folderName);
-			CreateFolder(path);
+		auto link = CreateSharedLink(path);
+		ftp->AddSharedLink(link.c_str());
+	}
 
-			auto link = CreateSharedLink(path);
-			ftp->AddSharedLink(link.c_str());
-		}
+	ftp->FirstFile();
+	do
+	{
+		std::string fileName = T2Utf(ftp->GetCurrentRelativeFilePath());
+		uint64_t fileSize = ftp->GetCurrentFileSize();
 
-		ftp->FirstFile();
-		do
-		{
-			T2Utf fileName(ftp->GetCurrentRelativeFilePath());
-			uint64_t fileSize = ftp->GetCurrentFileSize();
+		size_t chunkSize = ftp->GetCurrentFileChunkSize();
+		mir_ptr<char> chunk((char*)mir_calloc(chunkSize));
 
-			auto path = PreparePath(fileName);
-			auto uploadUri = CreateUploadSession(path);
+		std::string path;
+		if (!serverFolder.empty())
+			path = "/" + serverFolder + "/" + fileName;
+		else
+			path = PreparePath(fileName);
 
-			size_t chunkSize = ftp->GetCurrentFileChunkSize();
-			mir_ptr<char>chunk((char*)mir_calloc(chunkSize));
+		auto uploadUri = CreateUploadSession(path);
 
-			if (chunkSize == fileSize) {
+		if (chunkSize == fileSize) {
+			ftp->CheckCurrentFile();
+			size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
+			UploadFile(uploadUri, chunk, size);
+			ftp->Progress(size);
+		}
+		else {
+			uint64_t offset = 0;
+			double chunkCount = ceil(double(fileSize) / chunkSize);
+			for (size_t i = 0; i < chunkCount; i++) {
 				ftp->CheckCurrentFile();
 				size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
-				UploadFile(uploadUri, chunk, size);
+				UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
+				offset += size;
 				ftp->Progress(size);
 			}
-			else {
-				uint64_t offset = 0;
-				double chunkCount = ceil(double(fileSize) / chunkSize);
-				for (size_t i = 0; i < chunkCount; i++) {
-					ftp->CheckCurrentFile();
-					size_t size = ftp->ReadCurrentFile(chunk, chunkSize);
-					UploadFileChunk(uploadUri, chunk, size, offset, fileSize);
-					offset += size;
-					ftp->Progress(size);
-				}
-			}
-
-			if (!ftp->IsFolder()) {
-				auto link = CreateSharedLink(path);
-				ftp->AddSharedLink(link.c_str());
-			}
-		} while (ftp->NextFile());
-	}
-	catch (Exception &ex) {
-		debugLogA("%s: %s", GetAccountName(), ex.what());
-		ftp->SetStatus(ACKRESULT_FAILED);
-		return ACKRESULT_FAILED;
-	}
+		}
 
-	ftp->SetStatus(ACKRESULT_SUCCESS);
-	return ACKRESULT_SUCCESS;
+		if (!ftp->IsCurrentFileInSubDirectory()) {
+			auto link = CreateSharedLink(path);
+			ftp->AddSharedLink(link.c_str());
+		}
+	} while (ftp->NextFile());
 }
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -297,4 +283,4 @@ struct CMPluginYandex : public CMPluginBase
 		RegisterProtocol(PROTOTYPE_PROTOWITHACCS, (pfnInitProto)CYandexService::Init, (pfnUninitProto)CYandexService::UnInit);
 	}
 }
-	g_pluginYandex;
+g_pluginYandex;
diff --git a/plugins/CloudFile/src/Services/yandex_service.h b/plugins/CloudFile/src/Services/yandex_service.h
index fa18e0f2f2..d384ad0a53 100644
--- a/plugins/CloudFile/src/Services/yandex_service.h
+++ b/plugins/CloudFile/src/Services/yandex_service.h
@@ -15,6 +15,8 @@ private:
 	void CreateFolder(const std::string &path);
 	auto CreateSharedLink(const std::string &path);
 
+	void Upload(FileTransferParam *ftp) override;
+
 public:
 	CYandexService(const char *protoName, const wchar_t *userName);
 
@@ -28,8 +30,6 @@ public:
 	bool IsLoggedIn() override;
 	void Login(HWND owner = nullptr) override;
 	void Logout() override;
-
-	UINT Upload(FileTransferParam *ftp) override;
 };
 
 #endif //_CLOUDFILE_YANDEX_H_
\ No newline at end of file
diff --git a/plugins/CloudFile/src/cloud_file.cpp b/plugins/CloudFile/src/cloud_file.cpp
index 86e65b6b34..3217716341 100644
--- a/plugins/CloudFile/src/cloud_file.cpp
+++ b/plugins/CloudFile/src/cloud_file.cpp
@@ -106,7 +106,7 @@ INT_PTR CCloudService::OnAccountManagerInit(WPARAM, LPARAM lParam)
 	return (INT_PTR)page->GetHwnd();
 }
 
-std::string CCloudService::PreparePath(const char *path)
+std::string CCloudService::PreparePath(const std::string &path) const
 {
 	std::string newPath = path;
 	if (newPath[0] != '/')
@@ -146,6 +146,8 @@ char* CCloudService::HttpStatusToError(int status)
 
 void CCloudService::HttpResponseToError(NETLIBHTTPREQUEST *response)
 {
+	if (response == nullptr)
+		throw Exception(HttpStatusToError());
 	if (response->dataLength)
 		throw Exception(response->pData);
 	throw Exception(HttpStatusToError(response->resultCode));
@@ -177,3 +179,26 @@ JSONNode CCloudService::GetJsonResponse(NETLIBHTTPREQUEST *response)
 
 	return root;
 }
+
+UINT CCloudService::Upload(CCloudService *service, FileTransferParam *ftp)
+{
+	try {
+		if (!service->IsLoggedIn())
+			service->Login();
+
+		if (!service->IsLoggedIn()) {
+			ftp->SetStatus(ACKRESULT_FAILED);
+			return ACKRESULT_FAILED;
+		}
+
+		service->Upload(ftp);
+	}
+	catch (Exception &ex) {
+		service->debugLogA("%s: %s", service->GetModuleName(), ex.what());
+		ftp->SetStatus(ACKRESULT_FAILED);
+		return ACKRESULT_FAILED;
+	}
+
+	ftp->SetStatus(ACKRESULT_SUCCESS);
+	return ACKRESULT_SUCCESS;
+}
\ No newline at end of file
diff --git a/plugins/CloudFile/src/cloud_file.h b/plugins/CloudFile/src/cloud_file.h
index bca4aa1703..140102a9a2 100644
--- a/plugins/CloudFile/src/cloud_file.h
+++ b/plugins/CloudFile/src/cloud_file.h
@@ -17,7 +17,7 @@ protected:
 	INT_PTR __cdecl OnAccountManagerInit(WPARAM, LPARAM);
 
 	// utils
-	std::string PreparePath(const char *path);
+	std::string PreparePath(const std::string &path) const;
 
 	virtual char* HttpStatusToError(int status = 0);
 	virtual void HttpResponseToError(NETLIBHTTPREQUEST *response);
@@ -28,6 +28,8 @@ protected:
 
 	JSONNode GetJsonResponse(NETLIBHTTPREQUEST *response);
 
+	virtual void Upload(FileTransferParam *ftp) = 0;
+
 public:
 	std::map<MCONTACT, HWND> InterceptedContacts;
 
@@ -53,7 +55,7 @@ public:
 
 	void OpenUploadDialog(MCONTACT hContact);
 
-	virtual UINT Upload(FileTransferParam *ftp) = 0;
+	static UINT Upload(CCloudService *service, FileTransferParam *ftp);
 };
 
 #endif //_CLOUD_SERVICE_H_
\ No newline at end of file
diff --git a/plugins/CloudFile/src/file_transfer.h b/plugins/CloudFile/src/file_transfer.h
index a19c62a412..9918018ff0 100644
--- a/plugins/CloudFile/src/file_transfer.h
+++ b/plugins/CloudFile/src/file_transfer.h
@@ -12,10 +12,8 @@ private:
 
 	bool isTerminated;
 
-	CMStringW serverFolder;
-
-	const wchar_t* folderName;
-	int relativePathStart;
+	CMStringW m_serverDirectory;
+	int m_relativePathStart;
 	
 	LIST<char> m_links;
 	CMStringW m_description;
@@ -29,8 +27,7 @@ public:
 
 		isTerminated = false;
 
-		folderName = NULL;
-		relativePathStart = 0;
+		m_relativePathStart = 0;
 
 		pfts.flags = PFTS_UNICODE | PFTS_SENDING;
 		pfts.hContact = hContact;
@@ -93,19 +90,6 @@ public:
 		isTerminated = true;
 	}
 
-	void SetServerFolder(const wchar_t *path)
-	{
-		if (path)
-			serverFolder = path;
-	}
-
-	const wchar_t* GetServerFolder() const
-	{
-		if (serverFolder.IsEmpty())
-			return NULL;
-		return serverFolder;
-	}
-
 	void SetDescription(const wchar_t *description)
 	{
 		m_description = description;
@@ -113,21 +97,24 @@ public:
 
 	void SetWorkingDirectory(const wchar_t *path)
 	{
-		relativePathStart = wcsrchr(path, '\\') - path + 1;
-		pfts.szWorkingDir.w = (wchar_t*)mir_calloc(sizeof(wchar_t) * relativePathStart);
-		mir_wstrncpy(pfts.szWorkingDir.w, path, relativePathStart);
+		m_relativePathStart = wcsrchr(path, '\\') - path + 1;
+		pfts.szWorkingDir.w = (wchar_t*)mir_calloc(sizeof(wchar_t) * m_relativePathStart);
+		mir_wstrncpy(pfts.szWorkingDir.w, path, m_relativePathStart);
 		if (PathIsDirectory(path))
-			folderName = wcsrchr(path, '\\') + 1;
+			m_serverDirectory = wcsrchr(path, '\\') + 1;
 	}
 
-	const wchar_t* IsFolder() const
+	void SetServerDirectory(const wchar_t *name)
 	{
-		return folderName;
+		if (name)
+			m_serverDirectory = name;
 	}
 
-	const wchar_t* GetFolderName() const
+	const wchar_t* GetServerDirectory() const
 	{
-		return folderName;
+		if (m_serverDirectory.IsEmpty())
+			return nullptr;
+		return m_serverDirectory.GetString();
 	}
 
 	void AddFile(const wchar_t *path)
@@ -149,6 +136,12 @@ public:
 		m_links.insert(mir_strdup(url));
 	}
 
+	const bool IsCurrentFileInSubDirectory() const
+	{
+		const wchar_t *backslash = wcschr(GetCurrentFilePath(), L'\\');
+		return backslash != nullptr;
+	}
+
 	const wchar_t* GetCurrentFilePath() const
 	{
 		return pfts.pszFiles.w[pfts.currentFileNumber];
@@ -156,12 +149,12 @@ public:
 
 	const wchar_t* GetCurrentRelativeFilePath() const
 	{
-		return &GetCurrentFilePath()[relativePathStart];
+		return &GetCurrentFilePath()[m_relativePathStart];
 	}
 
 	const wchar_t* GetCurrentFileName() const
 	{
-		return wcsrchr(pfts.pszFiles.w[pfts.currentFileNumber], '\\') + 1;
+		return wcsrchr(GetCurrentFilePath(), '\\') + 1;
 	}
 
 	void OpenCurrentFile()
diff --git a/plugins/CloudFile/src/http_request.h b/plugins/CloudFile/src/http_request.h
index d49c225013..db052604b8 100644
--- a/plugins/CloudFile/src/http_request.h
+++ b/plugins/CloudFile/src/http_request.h
@@ -117,6 +117,18 @@ protected:
 		va_end(urlArgs);
 	}
 
+	void AddUrlParameterWithEncode(const char *name, const char *valueFormat, ...)
+	{
+		va_list valueArgs;
+		va_start(valueArgs, valueFormat);
+		m_szUrl += m_szUrl.Find('?') == -1 ? '?' : '&';
+		m_szUrl.AppendFormat("%s=", name);
+		CMStringA value;
+		value.AppendFormatV(valueFormat, valueArgs);
+		m_szUrl.Append(ptrA(mir_urlEncode(value)));
+		va_end(valueArgs);
+	}
+
 	void SetData(const char *data, size_t size)
 	{
 		if (pData != NULL)
diff --git a/plugins/CloudFile/src/services.cpp b/plugins/CloudFile/src/services.cpp
index edaad32901..826554ca97 100644
--- a/plugins/CloudFile/src/services.cpp
+++ b/plugins/CloudFile/src/services.cpp
@@ -18,6 +18,10 @@ CCloudService* FindService(const char *szProto)
 
 static INT_PTR GetService(WPARAM wParam, LPARAM lParam)
 {
+	CFSERVICEINFO *info = (CFSERVICEINFO*)lParam;
+	if (info == nullptr)
+		return 1;
+
 	ptrA accountName(mir_strdup((char*)wParam));
 	if (!accountName || !mir_strlen(accountName))
 		accountName = db_get_sa(NULL, MODULE, "DefaultService");
@@ -28,11 +32,8 @@ static INT_PTR GetService(WPARAM wParam, LPARAM lParam)
 	if (service == nullptr)
 		return 3;
 
-	CFSERVICEINFO *info = (CFSERVICEINFO*)lParam;
-	if (info != nullptr) {
-		info->accountName = service->GetAccountName();
-		info->userName = service->GetUserName();
-	}
+	info->accountName = service->GetAccountName();
+	info->userName = service->GetUserName();
 
 	return 0;
 }
@@ -77,17 +78,15 @@ INT_PTR Upload(WPARAM wParam, LPARAM lParam)
 
 	FileTransferParam ftp(0);
 	ftp.SetWorkingDirectory(uploadData->localPath);
-	ftp.SetServerFolder(uploadData->serverFolder);
+	ftp.SetServerDirectory(uploadData->serverFolder);
 	ftp.AddFile(uploadData->localPath);
 
-	int res = service->Upload(&ftp);
+	int res = CCloudService::Upload(service, &ftp);
 	if (res == ACKRESULT_SUCCESS && lParam) {
-		CFUPLOADRESULT *result = (CFUPLOADRESULT*)lParam;
-		const char **links = ftp.GetSharedLinks(result->linkCount);
-		result->links = (char**)mir_calloc(sizeof(char*) * result->linkCount);
-		for (size_t i = 0; i < result->linkCount; i++)
-			result->links[i] = mir_strdup(links[i]);
-		result->description = mir_wstrdup(ftp.GetDescription());
+		size_t linkCount = 0;
+		const char **links = ftp.GetSharedLinks(linkCount);
+		if (linkCount > 0)
+			lParam = (LPARAM)mir_strdup(links[linkCount - 1]);
 	}
 
 	return res;
diff --git a/plugins/CloudFile/src/transfers.cpp b/plugins/CloudFile/src/transfers.cpp
index ca067399ca..5236e0c9f0 100644
--- a/plugins/CloudFile/src/transfers.cpp
+++ b/plugins/CloudFile/src/transfers.cpp
@@ -20,7 +20,7 @@ UINT UploadAndReportProgressThread(void *owner, void *arg)
 	CCloudService *service = (CCloudService*)owner;
 	FileTransferParam *ftp = (FileTransferParam*)arg;
 
-	int res = service->Upload(ftp);
+	int res = CCloudService::Upload(service, ftp);
 	if (res == ACKRESULT_SUCCESS) {
 		CMStringW data = ftp->GetDescription();
 		size_t linkCount;
diff --git a/plugins/CloudFile/src/utils.cpp b/plugins/CloudFile/src/utils.cpp
index 27ff876b19..65fd99e376 100644
--- a/plugins/CloudFile/src/utils.cpp
+++ b/plugins/CloudFile/src/utils.cpp
@@ -49,9 +49,9 @@ bool CanSendToContact(MCONTACT hContact)
 	if (!canSend)
 		return false;
 
-	bool isProtoOnline = Proto_GetStatus(proto) > ID_STATUS_OFFLINE;
-	if (isProtoOnline)
-		return true;
+	bool isProtoOffline = Proto_GetStatus(proto) <= ID_STATUS_OFFLINE;
+	if (isProtoOffline)
+		return false;
 
 	bool isContactOnline = db_get_w(hContact, proto, "Status", ID_STATUS_OFFLINE) > ID_STATUS_OFFLINE;
 	if (isContactOnline)
diff --git a/plugins/CloudFile/src/version.h b/plugins/CloudFile/src/version.h
index 295a3b73ef..28e640d870 100644
--- a/plugins/CloudFile/src/version.h
+++ b/plugins/CloudFile/src/version.h
@@ -1,7 +1,7 @@
 #define __MAJOR_VERSION            0
 #define __MINOR_VERSION            11
 #define __RELEASE_NUM              0
-#define __BUILD_NUM                4
+#define __BUILD_NUM                5
 
 #include <stdver.h>
 
diff --git a/plugins/Db_autobackups/src/backup.cpp b/plugins/Db_autobackups/src/backup.cpp
index d697e3ef5b..df31953a22 100644
--- a/plugins/Db_autobackups/src/backup.cpp
+++ b/plugins/Db_autobackups/src/backup.cpp
@@ -25,6 +25,7 @@ LRESULT CALLBACK DlgProcPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 	}
 	return DefWindowProc(hWnd, msg, wParam, lParam);
 }
+
 void ShowPopup(wchar_t* ptszText, wchar_t* ptszHeader, wchar_t* ptszPath)
 {
 	POPUPDATAT ppd = { 0 };
diff --git a/plugins/ExternalAPI/m_cloudfile.h b/plugins/ExternalAPI/m_cloudfile.h
index 505f9e3462..b7dee2f51b 100644
--- a/plugins/ExternalAPI/m_cloudfile.h
+++ b/plugins/ExternalAPI/m_cloudfile.h
@@ -9,7 +9,7 @@ struct CFSERVICEINFO
 
 // get cloud file service info by account name
 // wParam = (WPARAM)(const char*)accountName (can be NULL)
-// lParam = (LPARAM)(CFSERVICEINFO*)serviceInfo (can be NULL)
+// lParam = (LPARAM)(CFSERVICEINFO*)serviceInfo
 // returns 0 on success, nonzero on failure
 #define MS_CLOUDFILE_GETSERVICE "CloudFile/GetService"
 
@@ -24,30 +24,14 @@ typedef int(*enumCFServiceFunc)(const CFSERVICEINFO *serviceInfo, void *param);
 
 struct CFUPLOADDATA
 {
-	const char *accountName; // cloud service to upload (can be NULL)
-	const wchar_t *localPath; // local path
-	const wchar_t *serverFolder; // server folder in witch file will be placed (can be NULL)
+	const char *accountName;		// cloud service to upload (can be NULL)
+	const wchar_t *localPath;		// local path to file
+	const wchar_t *serverFolder;	// server folder in witch file will be placed (can be NULL)
 };
 
-struct CFUPLOADRESULT
-{
-	char **links; // need to be freed manually or by calling cfur_free
-	size_t linkCount;
-	wchar_t *description; // need to be freed manually or by calling cfur_free
-};
-
-// frees allocated fields of CFUPLOADRESULT
-__inline void cfur_free(CFUPLOADRESULT *ur)
-{
-	for (size_t i = 0; i < ur->linkCount; i++)
-		mir_free(ur->links[0]);
-	mir_free(ur->links);
-	mir_free(ur->description);
-}
-
 // upload file on cloud service
 // wParam = (WPARAM)(const CFUPLOADDATA*)uploadData
-// lParam = (LPARAM)(char CFUPLOADRESULT*)uploadResult (can be NULL)
+// lParam = (LPARAM)(char*)link to file in cloud service (needs to be freed) (can be NULL)
 // returns 0 on success, nonzero on failure
 #define MS_CLOUDFILE_UPLOAD "CloudFile/Upload"
 
diff --git a/plugins/SendScreenshotPlus/src/CSendCloudFile.cpp b/plugins/SendScreenshotPlus/src/CSendCloudFile.cpp
index bb061e3c2c..d06669df80 100644
--- a/plugins/SendScreenshotPlus/src/CSendCloudFile.cpp
+++ b/plugins/SendScreenshotPlus/src/CSendCloudFile.cpp
@@ -57,26 +57,16 @@ void CSendCloudFile::SendThread()
 	/// @todo : SS_DLG_DESCRIPTION and SS_DLG_DELETEAFTERSSEND are of no use as of now since we don't track upload progress
 
 	CFUPLOADDATA ud = { m_service, m_pszFile, L"SendSS" };
-	CFUPLOADRESULT ur = { };
 
-	if (CallService(MS_CLOUDFILE_UPLOAD, (WPARAM)&ud, (LPARAM)&ur))
-	{
+	if (CallService(MS_CLOUDFILE_UPLOAD, (WPARAM)&ud, (LPARAM)m_URL)) {
 		Error(LPGENW("%s (%i):\nCould not add a share to the CloudFile plugin."), TranslateW(m_pszSendTyp), 0);
 		Exit(ACKRESULT_FAILED); return;
 	}
 
-	CMStringA message;
-	for (size_t i = 0; i < ur.linkCount; i++)
-		message.AppendFormat("%s\r\n", ur.links[i]);
-	message.Delete(message.GetLength() - 2, 2);
-
-	m_URL = mir_strdup(message.GetString());
 	if (m_URL)
 		svcSendMsgExit(m_URL);
 	else
 		Exit(ACKRESULT_FAILED);
-
-	cfur_free(&ur);
 }
 
 void CSendCloudFile::SendThreadWrapper(void * Obj)
-- 
cgit v1.2.3