diff options
26 files changed, 471 insertions, 385 deletions
diff --git a/plugins/CloudFile/res/resource.rc b/plugins/CloudFile/res/resource.rc index 93713dece3..b071d664f7 100644 --- a/plugins/CloudFile/res/resource.rc +++ b/plugins/CloudFile/res/resource.rc @@ -83,15 +83,20 @@ STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD  EXSTYLE WS_EX_CONTROLPARENT  FONT 8, "MS Shell Dlg", 0, 0, 0x1  BEGIN -    GROUPBOX        "Download link",IDC_STATIC,5,5,297,57 +    GROUPBOX        "Download link",IDC_STATIC,5,100,297,57      CONTROL         "Autosend download link to contact",IDC_URL_AUTOSEND, -                    "Button",BS_AUTORADIOBUTTON,11,19,282,10 +                    "Button",BS_AUTORADIOBUTTON,11,114,282,10      CONTROL         "Paste download link into message input area",IDC_URL_COPYTOMIA, -                    "Button",BS_AUTORADIOBUTTON,11,32,282,10 +                    "Button",BS_AUTORADIOBUTTON,11,127,282,10      CONTROL         "Copy download link to clipboard",IDC_URL_COPYTOCB, -                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,45,282,10 -    GROUPBOX        "Services",IDC_STATIC,5,65,297,96 -    CONTROL         "",IDC_SERVICES,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,11,76,285,76 +                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,140,282,10 +    GROUPBOX        "General",IDC_STATIC,5,5,297,33 +    COMBOBOX        IDC_DEFAULTSERVICE,102,17,194,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP +    LTEXT           "Default service",IDC_STATIC,11,19,85,8 +    GROUPBOX        "On conflict when upload",IDC_STATIC,5,41,297,56 +    CONTROL         "Try to rename",IDC_RENAMEONCONFLICT,"Button",BS_AUTORADIOBUTTON,11,67,285,10 +    CONTROL         "Try to replace",IDC_REPLACEONCONFLICT,"Button",BS_AUTORADIOBUTTON,11,80,285,10 +    CONTROL         "Nothing",IDC_DONOTHING,"Button",BS_AUTORADIOBUTTON,11,54,41,10  END  IDD_OAUTH DIALOGEX 0, 0, 193, 83 @@ -138,6 +143,8 @@ BEGIN          LEFTMARGIN, 5          RIGHTMARGIN, 302          VERTGUIDE, 11 +        VERTGUIDE, 96 +        VERTGUIDE, 102          VERTGUIDE, 296          TOPMARGIN, 5          BOTTOMMARGIN, 229 diff --git a/plugins/CloudFile/src/Services/dropbox_api.h b/plugins/CloudFile/src/Services/dropbox_api.h index 3db69250e8..890ff420f6 100644 --- a/plugins/CloudFile/src/Services/dropbox_api.h +++ b/plugins/CloudFile/src/Services/dropbox_api.h @@ -58,23 +58,23 @@ namespace DropboxAPI  		}  	}; -	class StartUploadSessionRequest : public HttpRequest +	class CreateUploadSessionRequest : public HttpRequest  	{  	public: -		StartUploadSessionRequest(const char *token, const char *data, size_t size) : +		CreateUploadSessionRequest(const char *token, const char *chunk, size_t chunkSize) :  			HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/start")  		{  			AddBearerAuthHeader(token);  			AddHeader("Content-Type", "application/octet-stream"); -			SetData(data, size); +			SetData(chunk, chunkSize);  		}  	}; -	class AppendToUploadSessionRequest : public HttpRequest +	class UploadFileChunkRequest : public HttpRequest  	{  	public: -		AppendToUploadSessionRequest(const char *token, const char *sessionId, size_t offset, const char *data, size_t size) : +		UploadFileChunkRequest(const char *token, const char *sessionId, size_t offset, const char *chunk, size_t chunkSize) :  			HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/append_v2")  		{  			AddBearerAuthHeader(token); @@ -92,14 +92,14 @@ namespace DropboxAPI  			AddHeader("Dropbox-API-Arg", param.write().c_str()); -			SetData(data, size); +			SetData(chunk, chunkSize);  		}  	}; -	class FinishUploadSessionRequest : public HttpRequest +	class CommitUploadSessionRequest : public HttpRequest  	{  	public: -		FinishUploadSessionRequest(const char *token, const char *sessionId, size_t offset, const char *path, const char *data, size_t size) : +		CommitUploadSessionRequest(const char *token, const char *sessionId, size_t offset, const char *path, const char *chunk, size_t chunkSize) :  			HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/finish")  		{  			AddBearerAuthHeader(token); @@ -124,7 +124,7 @@ namespace DropboxAPI  			AddHeader("Dropbox-API-Arg", params.write().c_str()); -			SetData(data, size); +			SetData(chunk, chunkSize);  		}  	}; diff --git a/plugins/CloudFile/src/Services/dropbox_service.cpp b/plugins/CloudFile/src/Services/dropbox_service.cpp index 409494e9d3..fdd904e5e3 100644 --- a/plugins/CloudFile/src/Services/dropbox_service.cpp +++ b/plugins/CloudFile/src/Services/dropbox_service.cpp @@ -119,10 +119,10 @@ char* CDropboxService::UploadFile(const char *data, size_t size, char *path)  	return path;  } -void CDropboxService::StartUploadSession(const char *data, size_t size, char *sessionId) +void CDropboxService::CreateUploadSession(const char *chunk, size_t chunkSize, char *sessionId)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	DropboxAPI::StartUploadSessionRequest request(token, data, size); +	DropboxAPI::CreateUploadSessionRequest request(token, chunk, chunkSize);  	NLHR_PTR response(request.Send(hConnection));  	JSONNode root = GetJsonResponse(response); @@ -130,19 +130,19 @@ void CDropboxService::StartUploadSession(const char *data, size_t size, char *se  	mir_strcpy(sessionId, node.as_string().c_str());  } -void CDropboxService::AppendToUploadSession(const char *data, size_t size, const char *sessionId, size_t offset) +void CDropboxService::UploadFileChunk(const char *chunk, size_t chunkSize, const char *sessionId, size_t offset)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	DropboxAPI::AppendToUploadSessionRequest request(token, sessionId, offset, data, size); +	DropboxAPI::UploadFileChunkRequest request(token, sessionId, offset, chunk, chunkSize);  	NLHR_PTR response(request.Send(hConnection));  	GetJsonResponse(response);  } -char* CDropboxService::FinishUploadSession(const char *data, size_t size, const char *sessionId, size_t offset, char *path) +char* CDropboxService::CommitUploadSession(const char *data, size_t size, const char *sessionId, size_t offset, char *path)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	DropboxAPI::FinishUploadSessionRequest request(token, sessionId, offset, path, data, size); +	DropboxAPI::CommitUploadSessionRequest request(token, sessionId, offset, path, data, size);  	NLHR_PTR response(request.Send(hConnection));  	JSONNode root = GetJsonResponse(response); @@ -214,62 +214,57 @@ UINT CDropboxService::Upload(FileTransferParam *ftp)  		Login();  	try { -		const wchar_t *folderName = ftp->GetFolderName(); -		if (folderName) { -			char path[MAX_PATH], url[MAX_PATH]; +		if (ftp->IsFolder()) { +			T2Utf folderName(ftp->GetFolderName()); + +			char path[MAX_PATH];  			PreparePath(folderName, path);  			CreateFolder(path); -			CreateSharedLink(path, url); -			ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url))); + +			char link[MAX_PATH]; +			CreateSharedLink(path, link); +			ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));  		}  		ftp->FirstFile();  		do  		{ -			const wchar_t *fileName = ftp->GetCurrentRelativeFilePath(); +			T2Utf fileName(ftp->GetCurrentRelativeFilePath());  			uint64_t fileSize = ftp->GetCurrentFileSize();  			int chunkSize = ftp->GetCurrentFileChunkSize();  			mir_ptr<char>data((char*)mir_calloc(chunkSize)); -			size_t size = ftp->ReadCurrentFile(data, chunkSize); -			size_t offset = 0;  			char sessionId[64]; -			StartUploadSession(data, size, sessionId); +			size_t size = ftp->ReadCurrentFile(data, chunkSize); +			CreateUploadSession(data, size, sessionId); -			offset += size;  			ftp->Progress(size); -			for (size_t chunk = 0; chunk < (fileSize / chunkSize) - 1; chunk++) +			size_t offset = size; +			size_t chunkCount = ceil(fileSize / chunkSize) - 2; +			while (chunkCount--)  			{  				ftp->CheckCurrentFile();  				size = ftp->ReadCurrentFile(data, chunkSize); -				AppendToUploadSession(data, size, sessionId, offset); +				UploadFileChunk(data, size, sessionId, offset);  				offset += size;  				ftp->Progress(size);  			} -			if (offset < fileSize) -				size = ftp->ReadCurrentFile(data, fileSize - offset); -			else -				size = 0; +			size = offset < fileSize +				? ftp->ReadCurrentFile(data, fileSize - offset) +				: 0;  			char path[MAX_PATH]; -			const wchar_t *serverFolder = ftp->GetServerFolder(); -			if (serverFolder) { -				wchar_t serverPath[MAX_PATH] = { 0 }; -				mir_snwprintf(serverPath, L"%s\\%s", serverFolder, fileName); -				PreparePath(serverPath, path); -			} -			else -				PreparePath(fileName, path); -			FinishUploadSession(data, size, sessionId, offset, path); +			PreparePath(fileName, path); +			CommitUploadSession(data, size, sessionId, offset, path);  			ftp->Progress(size); -			if (!wcschr(fileName, L'\\')) { +			if (!ftp->IsFolder()) {  				char url[MAX_PATH];  				CreateSharedLink(path, url);  				ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url))); diff --git a/plugins/CloudFile/src/Services/dropbox_service.h b/plugins/CloudFile/src/Services/dropbox_service.h index 362a9751fc..c498b52178 100644 --- a/plugins/CloudFile/src/Services/dropbox_service.h +++ b/plugins/CloudFile/src/Services/dropbox_service.h @@ -10,9 +10,9 @@ private:  	void HandleJsonError(JSONNode &node);  	char* UploadFile(const char *data, size_t size, char *path); -	void StartUploadSession(const char *data, size_t size, char *sessionId); -	void AppendToUploadSession(const char *data, size_t size, const char *sessionId, size_t offset); -	char* FinishUploadSession(const char *data, size_t size, const char *sessionId, size_t offset, char *path); +	void CreateUploadSession(const char *chunk, size_t chunkSize, char *sessionId); +	void UploadFileChunk(const char *chunk, size_t chunkSize, const char *sessionId, size_t offset); +	char* CommitUploadSession(const char *chunk, size_t chunkSize, const char *sessionId, size_t offset, char *path);  	void CreateFolder(const char *path);  	void CreateSharedLink(const char *path, char *url); diff --git a/plugins/CloudFile/src/Services/google_api.h b/plugins/CloudFile/src/Services/google_api.h index b609507caa..c73124cdad 100644 --- a/plugins/CloudFile/src/Services/google_api.h +++ b/plugins/CloudFile/src/Services/google_api.h @@ -54,7 +54,7 @@ namespace GDriveAPI  	class UploadFileRequest : public HttpRequest  	{  	public: -		UploadFileRequest(const char *token, const char *name, const char *data, size_t size) : +		UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size) :  			HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)  		{  			AddBearerAuthHeader(token); @@ -67,6 +67,8 @@ namespace GDriveAPI  			body.AppendChar(0x0A);  			body.Append("{");  			body.AppendFormat("\"name\": \"%s\"", name); +			if (parentId) +				body.AppendFormat("\"parents\": [\"%s\"]", parentId);  			body.Append("}");  			body.AppendChar(0x0A);  			body.AppendChar(0x0A); @@ -86,7 +88,7 @@ namespace GDriveAPI  	class CreateUploadSessionRequest : public HttpRequest  	{  	public: -		CreateUploadSessionRequest(const char *token, const char *name) : +		CreateUploadSessionRequest(const char *token, const char *parentId, const char *name) :  			HttpRequest(REQUEST_POST, GDRIVE_UPLOAD)  		{  			AddUrlParameter("uploadType=resumable"); @@ -94,8 +96,12 @@ namespace GDriveAPI  			AddBearerAuthHeader(token);  			AddHeader("Content-Type", "application/json"); +			JSONNode parents(JSON_ARRAY); +			parents << JSONNode("", parentId); +  			JSONNode params(JSON_NODE);  			params << JSONNode("name", name); +			params << parents;  			json_string data = params.write();  			SetData(data.c_str(), data.length()); diff --git a/plugins/CloudFile/src/Services/google_service.cpp b/plugins/CloudFile/src/Services/google_service.cpp index bf6c7de90e..ac1d71b0f1 100644 --- a/plugins/CloudFile/src/Services/google_service.cpp +++ b/plugins/CloudFile/src/Services/google_service.cpp @@ -80,14 +80,14 @@ unsigned CGDriveService::RequestAccessTokenThread(void *owner, void *param)  			: service->HttpStatusToError(response->resultCode);  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), error); -		ShowNotification(TranslateT("server does not respond"), MB_ICONERROR); +		//ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);  		return 0;  	}  	JSONNode root = JSONNode::parse(response->pData);  	if (root.empty()) {  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode)); -		ShowNotification(TranslateT("server does not respond"), MB_ICONERROR); +		//ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);  		return 0;  	} @@ -95,7 +95,7 @@ unsigned CGDriveService::RequestAccessTokenThread(void *owner, void *param)  	if (!node.isnull()) {  		ptrW error_description(mir_a2u_cp(node.as_string().c_str(), CP_UTF8));  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode)); -		ShowNotification((wchar_t*)error_description, MB_ICONERROR); +		//ShowNotification((wchar_t*)error_description, MB_ICONERROR);  		return 0;  	} @@ -136,10 +136,10 @@ void CGDriveService::HandleJsonError(JSONNode &node)  	}  } -void CGDriveService::UploadFile(const char *name, const char *data, size_t size, char *fileId) +void CGDriveService::UploadFile(const char *parentId, const char *name, const char *data, size_t size, char *fileId)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	GDriveAPI::UploadFileRequest request(token, name, data, size); +	GDriveAPI::UploadFileRequest request(token, parentId, name, data, size);  	NLHR_PTR response(request.Send(hConnection));  	JSONNode root = GetJsonResponse(response); @@ -147,14 +147,13 @@ void CGDriveService::UploadFile(const char *name, const char *data, size_t size,  	mir_strcpy(fileId, node.as_string().c_str());  } -void CGDriveService::CreateUploadSession(char *uploadUri, const char *name) +void CGDriveService::CreateUploadSession(const char *parentId, const char *name, char *uploadUri)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	GDriveAPI::CreateUploadSessionRequest request(token, name); +	GDriveAPI::CreateUploadSessionRequest request(token, parentId, name);  	NLHR_PTR response(request.Send(hConnection)); -	if (response == NULL) -		throw Exception(HttpStatusToError()); +	HandleHttpError(response);  	if (HTTP_CODE_SUCCESS(response->resultCode)) {  		for (int i = 0; i < response->headersCount; i++) @@ -167,9 +166,7 @@ void CGDriveService::CreateUploadSession(char *uploadUri, const char *name)  		}  	} -	if (response->dataLength) -		throw Exception(response->pData); -	throw Exception(HttpStatusToError(response->resultCode)); +	HttpResponseToError(response);  }  void CGDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId) @@ -177,8 +174,7 @@ void CGDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, s  	GDriveAPI::UploadFileChunkRequest request(uploadUri, chunk, chunkSize, offset, fileSize);  	NLHR_PTR response(request.Send(hConnection)); -	if (response == NULL) -		throw Exception(HttpStatusToError()); +	HandleHttpError(response);  	if (response->resultCode == HTTP_CODE_PERMANENT_REDIRECT)  		return; @@ -190,38 +186,35 @@ void CGDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, s  		return;  	} -	if (response->dataLength) -		throw Exception(response->pData); -	throw Exception(HttpStatusToError(response->resultCode)); +	HttpResponseToError(response);  } -void CGDriveService::CreateFolder(const char *path) +void CGDriveService::CreateFolder(const char *path, char *folderId)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));  	GDriveAPI::CreateFolderRequest request(token, path);  	NLHR_PTR response(request.Send(hConnection)); -	GetJsonResponse(response); +	JSONNode root = GetJsonResponse(response); +	JSONNode node = root.at("id"); +	mir_strcpy(folderId, node.as_string().c_str());  } -void CGDriveService::CreateSharedLink(const char *fileId, char *url) +void CGDriveService::CreateSharedLink(const char *itemId, char *url)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	GDriveAPI::GrantPermissionsRequest request(token, fileId); +	GDriveAPI::GrantPermissionsRequest request(token, itemId);  	NLHR_PTR response(request.Send(hConnection)); -	if (response == NULL) -		throw Exception(HttpStatusToError()); +	HandleHttpError(response);  	if (HTTP_CODE_SUCCESS(response->resultCode)) { -		CMStringA sharedUrl(CMStringDataFormat::FORMAT, GDRIVE_SHARE, fileId); +		CMStringA sharedUrl(CMStringDataFormat::FORMAT, GDRIVE_SHARE, itemId);  		mir_strcpy(url, sharedUrl);  		return;  	} -	if (response->dataLength) -		throw Exception(response->pData); -	throw Exception(HttpStatusToError(response->resultCode)); +	HttpResponseToError(response);  }  UINT CGDriveService::Upload(FileTransferParam *ftp) @@ -235,22 +228,23 @@ UINT CGDriveService::Upload(FileTransferParam *ftp)  			return ACKRESULT_FAILED;  		} -		const wchar_t *folderName = ftp->GetFolderName(); -		if (folderName) { -			char path[MAX_PATH], link[MAX_PATH]; -			PreparePath(folderName, path); -			CreateFolder(path); -			CreateSharedLink(path, link); +		char folderId[32] = { 0 }; +		if (ftp->IsFolder()) { +			T2Utf folderName(ftp->GetFolderName()); + +			CreateFolder(folderName, folderId); +			char link[MAX_PATH]; + +			CreateSharedLink(folderId, link);  			ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));  		}  		ftp->FirstFile();  		do  		{ -			const wchar_t *fileName = ftp->GetCurrentRelativeFilePath(); +			T2Utf fileName(ftp->GetCurrentRelativeFilePath());  			uint64_t fileSize = ftp->GetCurrentFileSize(); -			uint64_t offset = 0;  			char fileId[32];  			size_t chunkSize = ftp->GetCurrentFileChunkSize(); @@ -259,24 +253,21 @@ UINT CGDriveService::Upload(FileTransferParam *ftp)  			if (chunkSize == fileSize)  			{  				ftp->CheckCurrentFile(); -  				size_t size = ftp->ReadCurrentFile(chunk, chunkSize); -				UploadFile(chunk, T2Utf(fileName), size, fileId); +				UploadFile(folderId, fileName, chunk, size, fileId);  			}  			else  			{  				char uploadUri[1024]; -				CreateUploadSession(uploadUri, T2Utf(fileName)); +				CreateUploadSession(uploadUri, folderId, fileName); -				size_t size = 0; -				for (size_t i = 0; i < (fileSize / chunkSize); i++) +				uint64_t offset = 0; +				size_t chunkCount = ceil(fileSize / chunkSize); +				while (chunkCount--)  				{  					ftp->CheckCurrentFile(); - -					size = ftp->ReadCurrentFile(chunk, chunkSize); -					if (size == 0) -						break; +					size_t size = ftp->ReadCurrentFile(chunk, chunkSize);  					UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId); @@ -285,10 +276,10 @@ UINT CGDriveService::Upload(FileTransferParam *ftp)  				}  			} -			if (!wcschr(fileName, L'\\')) { -				char url[MAX_PATH]; -				CreateSharedLink(fileId, url); -				ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url))); +			if (!ftp->IsFolder()) { +				char link[MAX_PATH]; +				CreateSharedLink(fileId, link); +				ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));  			}  		} while (ftp->NextFile());  	} diff --git a/plugins/CloudFile/src/Services/google_service.h b/plugins/CloudFile/src/Services/google_service.h index 1da21b5fef..878fa8f442 100644 --- a/plugins/CloudFile/src/Services/google_service.h +++ b/plugins/CloudFile/src/Services/google_service.h @@ -9,11 +9,11 @@ private:  	void HandleJsonError(JSONNode &node); -	void UploadFile(const char *name, const char *data, size_t size, char *fileId); -	void CreateUploadSession(char *uploadUri, const char *name); +	void UploadFile(const char *parentId, const char *name, const char *data, size_t size, char *fileId); +	void CreateUploadSession(const char *parentId, const char *name, char *uploadUri);  	void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId); -	void CreateFolder(const char *path); -	void CreateSharedLink(const char *fileId, char *url); +	void CreateFolder(const char *path, char *folderId); +	void CreateSharedLink(const char *itemId, char *url);  public:  	CGDriveService(HNETLIBUSER hConnection); diff --git a/plugins/CloudFile/src/Services/microsoft_api.h b/plugins/CloudFile/src/Services/microsoft_api.h index 395d6e434d..cc27a80756 100644 --- a/plugins/CloudFile/src/Services/microsoft_api.h +++ b/plugins/CloudFile/src/Services/microsoft_api.h @@ -40,20 +40,26 @@ namespace OneDriveAPI  	class UploadFileRequest : public HttpRequest  	{  	public: -		UploadFileRequest(const char *token, const char *name, const char *data, size_t size) : +		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("@microsoft.graph.conflictBehavior=rename"); +			if (strategy == OnConflict::RENAME) +				AddUrlParameter("@microsoft.graph.conflictBehavior=rename"); +			else if (strategy == OnConflict::REPLACE) +				AddUrlParameter("@microsoft.graph.conflictBehavior=replace");  			AddBearerAuthHeader(token);  			SetData(data, size);  		} -		UploadFileRequest(const char *token, const char *parentId, const char *name, const char *data, size_t size) : +		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)))  		{ -			AddUrlParameter("@microsoft.graph.conflictBehavior=rename"); +			if (strategy == OnConflict::RENAME) +				AddUrlParameter("@microsoft.graph.conflictBehavior=rename"); +			else if (strategy == OnConflict::REPLACE) +				AddUrlParameter("@microsoft.graph.conflictBehavior=replace");  			AddBearerAuthHeader(token); @@ -64,7 +70,7 @@ namespace OneDriveAPI  	class CreateUploadSessionRequest : public HttpRequest  	{  	public: -		CreateUploadSessionRequest(const char *token, const char *name) : +		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); @@ -72,8 +78,10 @@ namespace OneDriveAPI  			JSONNode item(JSON_NODE);  			item.set_name("item"); -			item -				<< JSONNode("@microsoft.graph.conflictBehavior", "rename"); +			if (strategy == OnConflict::RENAME) +				item << JSONNode("@microsoft.graph.conflictBehavior", "rename"); +			if (strategy == OnConflict::REPLACE) +				item << JSONNode("@microsoft.graph.conflictBehavior", "replace");  			JSONNode params(JSON_NODE);  			params << item; @@ -82,7 +90,7 @@ namespace OneDriveAPI  			SetData(data.c_str(), data.length());  		} -		CreateUploadSessionRequest(const char *token, const char *parentId, const char *name) : +		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)  		{  			AddBearerAuthHeader(token); @@ -90,9 +98,10 @@ namespace OneDriveAPI  			JSONNode item(JSON_NODE);  			item.set_name("item"); -			item -				<< JSONNode("@microsoft.graph.conflictBehavior", "rename") -				<< JSONNode("name", name); +			if (strategy == OnConflict::RENAME) +				item << JSONNode("@microsoft.graph.conflictBehavior", "rename"); +			if (strategy == OnConflict::REPLACE) +				item << JSONNode("@microsoft.graph.conflictBehavior", "replace");  			JSONNode params(JSON_NODE);  			params << item; diff --git a/plugins/CloudFile/src/Services/microsoft_service.cpp b/plugins/CloudFile/src/Services/microsoft_service.cpp index 0cf41eb738..77919574e0 100644 --- a/plugins/CloudFile/src/Services/microsoft_service.cpp +++ b/plugins/CloudFile/src/Services/microsoft_service.cpp @@ -82,14 +82,14 @@ unsigned COneDriveService::RequestAccessTokenThread(void *owner, void *param)  			: service->HttpStatusToError(response->resultCode);  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), error); -		ShowNotification(TranslateT("server does not respond"), MB_ICONERROR); +		//ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);  		return 0;  	}  	JSONNode root = JSONNode::parse(response->pData);  	if (root.empty()) {  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode)); -		ShowNotification(TranslateT("server does not respond"), MB_ICONERROR); +		//ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);  		return 0;  	} @@ -97,7 +97,7 @@ unsigned COneDriveService::RequestAccessTokenThread(void *owner, void *param)  	if (!node.isnull()) {  		ptrW error_description(mir_a2u_cp(node.as_string().c_str(), CP_UTF8));  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode)); -		ShowNotification((wchar_t*)error_description, MB_ICONERROR); +		//ShowNotification((wchar_t*)error_description, MB_ICONERROR);  		return 0;  	} @@ -141,7 +141,7 @@ void COneDriveService::UploadFile(const char *parentId, const char *name, const  	mir_strcpy(fileId, node.as_string().c_str());  } -void COneDriveService::CreateUploadSession(char *uploadUri, const char *name, const char *parentId) +void COneDriveService::CreateUploadSession(const char *parentId, const char *name, char *uploadUri)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));  	OneDriveAPI::CreateUploadSessionRequest *request = mir_strlen(parentId) @@ -155,13 +155,12 @@ void COneDriveService::CreateUploadSession(char *uploadUri, const char *name, co  	mir_strcpy(uploadUri, node.as_string().c_str());  } -void COneDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *itemId) +void COneDriveService::UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId)  {  	OneDriveAPI::UploadFileChunkRequest request(uploadUri, chunk, chunkSize, offset, fileSize);  	NLHR_PTR response(request.Send(hConnection)); -	if (response == NULL) -		throw Exception(HttpStatusToError()); +	HandleHttpError(response);  	if (response->resultCode == HTTP_CODE_ACCEPTED)  		return; @@ -169,16 +168,14 @@ void COneDriveService::UploadFileChunk(const char *uploadUri, const char *chunk,  	if (HTTP_CODE_SUCCESS(response->resultCode)) {  		JSONNode root = GetJsonResponse(response);  		JSONNode node = root.at("id"); -		mir_strcpy(itemId, node.as_string().c_str()); +		mir_strcpy(fileId, node.as_string().c_str());  		return;  	} -	if (response->dataLength) -		throw Exception(response->pData); -	throw Exception(HttpStatusToError(response->resultCode)); +	HttpResponseToError(response);  } -void COneDriveService::CreateFolder(const char *path, char *itemId) +void COneDriveService::CreateFolder(const char *path, char *folderId)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));  	OneDriveAPI::CreateFolderRequest request(token, path); @@ -186,7 +183,7 @@ void COneDriveService::CreateFolder(const char *path, char *itemId)  	JSONNode root = GetJsonResponse(response);  	JSONNode node = root.at("id"); -	mir_strcpy(itemId, node.as_string().c_str()); +	mir_strcpy(folderId, node.as_string().c_str());  }  void COneDriveService::CreateSharedLink(const char *itemId, char *url) @@ -213,11 +210,14 @@ UINT COneDriveService::Upload(FileTransferParam *ftp)  		}  		char folderId[32] = { 0 }; -		const wchar_t *folderName = ftp->GetFolderName(); -		if (folderName) { -			char path[MAX_PATH], link[MAX_PATH]; +		if (ftp->IsFolder()) { +			T2Utf folderName(ftp->GetFolderName()); + +			char path[MAX_PATH];  			PreparePath(folderName, path);  			CreateFolder(path, folderId); + +			char link[MAX_PATH];  			CreateSharedLink(path, link);  			ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));  		} @@ -225,10 +225,9 @@ UINT COneDriveService::Upload(FileTransferParam *ftp)  		ftp->FirstFile();  		do  		{ -			const wchar_t *fileName = ftp->GetCurrentRelativeFilePath(); +			T2Utf fileName(ftp->GetCurrentRelativeFilePath());  			uint64_t fileSize = ftp->GetCurrentFileSize(); -			uint64_t offset = 0;  			char fileId[32];  			size_t chunkSize = ftp->GetCurrentFileChunkSize(); @@ -237,7 +236,6 @@ UINT COneDriveService::Upload(FileTransferParam *ftp)  			if (chunkSize == fileSize)  			{  				ftp->CheckCurrentFile(); -  				size_t size = ftp->ReadCurrentFile(chunk, chunkSize);  				UploadFile(folderId, T2Utf(fileName), chunk, size, fileId); @@ -247,14 +245,10 @@ UINT COneDriveService::Upload(FileTransferParam *ftp)  				char uploadUri[1024];  				CreateUploadSession(uploadUri, T2Utf(fileName), folderId); -				size_t size = 0; -				for (size_t i = 0; i < (fileSize / chunkSize); i++) -				{ +				uint64_t offset = 0; +				for (size_t i = 0; i < (fileSize / chunkSize); i++) {  					ftp->CheckCurrentFile(); - -					size = ftp->ReadCurrentFile(chunk, chunkSize); -					if (size == 0) -						break; +					size_t size = ftp->ReadCurrentFile(chunk, chunkSize);  					UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId); @@ -263,10 +257,10 @@ UINT COneDriveService::Upload(FileTransferParam *ftp)  				}  			} -			if (!wcschr(fileName, L'\\')) { -				char url[MAX_PATH]; -				CreateSharedLink(fileId, url); -				ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url))); +			if (!ftp->IsFolder()) { +				char link[MAX_PATH]; +				CreateSharedLink(fileId, link); +				ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));  			}  		} while (ftp->NextFile());  	} diff --git a/plugins/CloudFile/src/Services/microsoft_service.h b/plugins/CloudFile/src/Services/microsoft_service.h index 3b49e1f6f3..cdd9d53976 100644 --- a/plugins/CloudFile/src/Services/microsoft_service.h +++ b/plugins/CloudFile/src/Services/microsoft_service.h @@ -9,9 +9,9 @@ private:  	void HandleJsonError(JSONNode &node);  	void UploadFile(const char *parentId, const char *name, const char *data, size_t size, char *fileId); -	void CreateUploadSession(char *uploadUri, const char *name, const char *parentId = NULL); -	void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *itemId); -	void CreateFolder(const char *path, char *itemId); +	void CreateUploadSession(const char *parentId, const char *name, char *uploadUri); +	void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize, char *fileId); +	void CreateFolder(const char *path, char *folderId);  	void CreateSharedLink(const char *itemId, char *url);  public: diff --git a/plugins/CloudFile/src/Services/yandex_api.h b/plugins/CloudFile/src/Services/yandex_api.h index 2a83abb634..56d77feb8c 100644 --- a/plugins/CloudFile/src/Services/yandex_api.h +++ b/plugins/CloudFile/src/Services/yandex_api.h @@ -52,27 +52,41 @@ namespace YandexAPI  	class GetUploadUrlRequest : public HttpRequest  	{  	public: -		GetUploadUrlRequest(const char *token, const char *path) : +		GetUploadUrlRequest(const char *token, const char *path, OnConflict strategy = NONE) :  			HttpRequest(REQUEST_GET, YADISK_API "/upload")  		{  			AddOAuthHeader(token);  			AddUrlParameter("path=%s", ptrA(mir_urlEncode(path))); -			AddUrlParameter("overwrite=true"); +			if (strategy == OnConflict::REPLACE) +				AddUrlParameter("overwrite=true");  		}  	};  	class UploadFileRequest : public HttpRequest  	{  	public: -		UploadFileRequest(const char *token, const char *url, const char *data, size_t size) : +		UploadFileRequest(const char *url, const char *data, size_t size) :  			HttpRequest(REQUEST_PUT, url)  		{ -			AddOAuthHeader(token); -  			SetData(data, size);  		}  	}; +	class UploadFileChunkRequest : public HttpRequest +	{ +	public: +		UploadFileChunkRequest(const char *url, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) : +			HttpRequest(REQUEST_PUT, url) +		{ +			uint64_t rangeMin = offset; +			uint64_t rangeMax = offset + chunkSize - 1; +			CMStringA range(CMStringDataFormat::FORMAT, "bytes %I64u-%I64u/%I64u", rangeMin, rangeMax, fileSize); +			AddHeader("Content-Range", range); + +			SetData(chunk, chunkSize); +		} +	}; +  	class CreateFolderRequest : public HttpRequest  	{  	public: diff --git a/plugins/CloudFile/src/Services/yandex_service.cpp b/plugins/CloudFile/src/Services/yandex_service.cpp index 1b8abecf96..bce62324a1 100644 --- a/plugins/CloudFile/src/Services/yandex_service.cpp +++ b/plugins/CloudFile/src/Services/yandex_service.cpp @@ -83,14 +83,14 @@ unsigned CYandexService::RequestAccessTokenThread(void *owner, void *param)  			: service->HttpStatusToError(response->resultCode);  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), error); -		ShowNotification(TranslateT("server does not respond"), MB_ICONERROR); +		//ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);  		return 0;  	}  	JSONNode root = JSONNode::parse(response->pData);  	if (root.empty()) {  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode)); -		ShowNotification(TranslateT("server does not respond"), MB_ICONERROR); +		//ShowNotification(TranslateT("server does not respond"), MB_ICONERROR);  		return 0;  	} @@ -98,7 +98,7 @@ unsigned CYandexService::RequestAccessTokenThread(void *owner, void *param)  	if (!node.isnull()) {  		ptrW error_description(mir_a2u_cp(node.as_string().c_str(), CP_UTF8));  		Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), service->HttpStatusToError(response->resultCode)); -		ShowNotification((wchar_t*)error_description, MB_ICONERROR); +		//ShowNotification((wchar_t*)error_description, MB_ICONERROR);  		return 0;  	} @@ -139,7 +139,7 @@ void CYandexService::HandleJsonError(JSONNode &node)  	}  } -void CYandexService::GetUploadUrl(char *path, char *url) +void CYandexService::CreateUploadSession(const char *path, char *uploadUri)  {  	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret"));  	YandexAPI::GetUploadUrlRequest request(token, path); @@ -147,26 +147,34 @@ void CYandexService::GetUploadUrl(char *path, char *url)  	JSONNode root = GetJsonResponse(response);  	JSONNode node = root.at("href"); -	mir_strcpy(url, node.as_string().c_str()); +	mir_strcpy(uploadUri, node.as_string().c_str());  } -void CYandexService::UploadFile(const char *url, const char *data, size_t size) +void CYandexService::UploadFile(const char *uploadUri, const char *data, size_t size)  { -	ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); -	YandexAPI::UploadFileRequest request(token, url, data, size); +	YandexAPI::UploadFileRequest request(uploadUri, data, size);  	NLHR_PTR response(request.Send(hConnection)); -	if (response == NULL) -		throw Exception(HttpStatusToError()); +	HandleHttpError(response); -	if (response->resultCode >= HTTP_CODE_OK && -		response->resultCode <= HTTP_CODE_MULTIPLE_CHOICES) { +	if (response->resultCode == HTTP_CODE_CREATED)  		return; -	} -	if (response->dataLength) -		throw Exception(response->pData); -	throw Exception(HttpStatusToError(response->resultCode)); +	HttpResponseToError(response); +} + +void CYandexService::UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize) +{ +	YandexAPI::UploadFileChunkRequest request(uploadUri, chunk, chunkSize, offset, fileSize); +	NLHR_PTR response(request.Send(hConnection)); + +	HandleHttpError(response); + +	if (response->resultCode == HTTP_CODE_ACCEPTED || +		response->resultCode == HTTP_CODE_CREATED) +		return; + +	HttpResponseToError(response);  }  void CYandexService::CreateFolder(const char *path) @@ -206,11 +214,14 @@ UINT CYandexService::Upload(FileTransferParam *ftp)  			return ACKRESULT_FAILED;  		} -		const wchar_t *folderName = ftp->GetFolderName(); -		if (folderName) { -			char path[MAX_PATH], link[MAX_PATH]; +		if (ftp->IsFolder()) { +			T2Utf folderName(ftp->GetFolderName()); + +			char path[MAX_PATH];   			PreparePath(folderName, path);  			CreateFolder(path); + +			char link[MAX_PATH];  			CreateSharedLink(path, link);  			ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link)));  		} @@ -218,28 +229,40 @@ UINT CYandexService::Upload(FileTransferParam *ftp)  		ftp->FirstFile();  		do  		{ -			const wchar_t *fileName = ftp->GetCurrentRelativeFilePath(); +			T2Utf fileName(ftp->GetCurrentRelativeFilePath());  			uint64_t fileSize = ftp->GetCurrentFileSize();  			char path[MAX_PATH]; -			const wchar_t *serverFolder = ftp->GetServerFolder(); -			if (serverFolder) { -				wchar_t serverPath[MAX_PATH] = { 0 }; -				mir_snwprintf(serverPath, L"%s\\%s", serverFolder, fileName); -				PreparePath(serverPath, path); -			} -			else -				PreparePath(fileName, path); -			char url[MAX_PATH]; -			GetUploadUrl(path, url); +			PreparePath(fileName, path); +			 +			char uploadUri[1024]; +			CreateUploadSession(path, uploadUri); + +			size_t chunkSize = ftp->GetCurrentFileChunkSize(); +			mir_ptr<char>chunk((char*)mir_calloc(chunkSize)); -			mir_ptr<char>data((char*)mir_calloc(fileSize)); -			size_t size = ftp->ReadCurrentFile(data, fileSize); -			UploadFile(url, data, size); +			if (chunkSize == fileSize) { +				ftp->CheckCurrentFile(); +				size_t size = ftp->ReadCurrentFile(chunk, chunkSize); -			ftp->Progress(size); +				UploadFile(uploadUri, chunk, size); +			} +			else { +				uint64_t offset = 0; +				size_t chunkCount = ceil(fileSize / chunkSize); +				while (chunkCount--) +				{ +					ftp->CheckCurrentFile(); +					size_t size = ftp->ReadCurrentFile(chunk, chunkSize); + +					UploadFileChunk(uploadUri, chunk, size, offset, fileSize); + +					offset += size; +					ftp->Progress(size); +				} +			} -			if (!wcschr(fileName, L'\\')) { +			if (!ftp->IsFolder()) {  				char url[MAX_PATH];  				CreateSharedLink(path, url);  				ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url))); diff --git a/plugins/CloudFile/src/Services/yandex_service.h b/plugins/CloudFile/src/Services/yandex_service.h index e3b122ffa1..85c0ad12de 100644 --- a/plugins/CloudFile/src/Services/yandex_service.h +++ b/plugins/CloudFile/src/Services/yandex_service.h @@ -9,8 +9,9 @@ private:  	void HandleJsonError(JSONNode &node); -	void GetUploadUrl(char *path, char *url); -	void UploadFile(const char *url, const char *data, size_t size); +	void CreateUploadSession(const char *path, char *uploadUri); +	void UploadFile(const char *uploadUri, const char *data, size_t size); +	void UploadFileChunk(const char *uploadUri, const char *chunk, size_t chunkSize, uint64_t offset, uint64_t fileSize);  	void CreateFolder(const char *path);  	void CreateSharedLink(const char *path, char *url); diff --git a/plugins/CloudFile/src/cloud_service.cpp b/plugins/CloudFile/src/cloud_service.cpp index f8b8b1e976..3ad83d1e2f 100644 --- a/plugins/CloudFile/src/cloud_service.cpp +++ b/plugins/CloudFile/src/cloud_service.cpp @@ -20,23 +20,21 @@ void InitServices()  	for (size_t i = 0; i < count; i++) {  		CCloudService *service = Services[i]; -		if (!db_get_b(NULL, service->GetModule(), "IsEnable", TRUE)) -			continue; - -		CMStringA moduleName(CMStringDataFormat::FORMAT, "%s/%s", MODULE, service->GetModule()); +		CMStringA moduleName = MODULE; +		moduleName.AppendFormat("/%s", service->GetModule());  		pd.type = PROTOTYPE_VIRTUAL;  		pd.szName = moduleName.GetBuffer();  		Proto_RegisterModule(&pd); -		CMStringA serviceName(CMStringDataFormat::FORMAT, "%s%s", moduleName, PSS_FILE); +		CMStringA serviceName = moduleName + PSS_FILE;  		CreateServiceFunctionObj(serviceName, ProtoSendFile, service); -		moduleName = CMStringA(CMStringDataFormat::FORMAT, "%s/%s/Interceptor", MODULE, service->GetModule()); +		moduleName += "/Interceptor";  		pd.szName = moduleName.GetBuffer();  		pd.type = PROTOTYPE_FILTER;  		Proto_RegisterModule(&pd); -		serviceName = CMStringA(CMStringDataFormat::FORMAT, "%s%s", moduleName, PSS_FILE); +		serviceName = moduleName + PSS_FILE;  		CreateServiceFunctionObj(serviceName, ProtoSendFileInterceptor, service);  	}  } @@ -46,6 +44,16 @@ CCloudService::CCloudService(HNETLIBUSER hConnection)  {  } +const wchar_t* CCloudService::GetText() const +{ +	return _A2T(GetModule()); +} + +int CCloudService::GetIconId() const +{ +	return 0; +} +  void CCloudService::OpenUploadDialog(MCONTACT hContact)  {  	char *proto = GetContactProto(hContact); @@ -62,44 +70,6 @@ void CCloudService::OpenUploadDialog(MCONTACT hContact)  		SetActiveWindow(it->second);  } -void CCloudService::SendToContact(MCONTACT hContact, const wchar_t *data) -{ -	const char *szProto = GetContactProto(hContact); -	if (db_get_b(hContact, szProto, "ChatRoom", 0) == TRUE) { -		ptrW tszChatRoom(db_get_wsa(hContact, szProto, "ChatRoomID")); -		Chat_SendUserMessage(szProto, tszChatRoom, data); -		return; -	} - -	char *message = mir_utf8encodeW(data); -	if (ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)message) != ACKRESULT_FAILED) -		AddEventToDb(hContact, EVENTTYPE_MESSAGE, DBEF_UTF | DBEF_SENT, (DWORD)mir_strlen(message), (PBYTE)message); -} - -void CCloudService::PasteToInputArea(MCONTACT hContact, const wchar_t *data) -{ -	CallService(MS_MSG_SENDMESSAGEW, hContact, (LPARAM)data); -} - -void CCloudService::PasteToClipboard(const wchar_t *data) -{ -	if (OpenClipboard(NULL)) { -		EmptyClipboard(); - -		size_t size = sizeof(wchar_t) * (mir_wstrlen(data) + 1); -		HGLOBAL hClipboardData = GlobalAlloc(NULL, size); -		if (hClipboardData) { -			wchar_t *pchData = (wchar_t*)GlobalLock(hClipboardData); -			if (pchData) { -				memcpy(pchData, (wchar_t*)data, size); -				GlobalUnlock(hClipboardData); -				SetClipboardData(CF_UNICODETEXT, hClipboardData); -			} -		} -		CloseClipboard(); -	} -} -  void CCloudService::Report(MCONTACT hContact, const wchar_t *data)  {  	if (db_get_b(NULL, MODULE, "UrlAutoSend", 1)) @@ -157,16 +127,20 @@ char* CCloudService::HttpStatusToError(int status)  	return "Unknown error";  } +void CCloudService::HttpResponseToError(NETLIBHTTPREQUEST *response) +{ +	if (response->dataLength) +		throw Exception(response->pData); +	throw Exception(HttpStatusToError(response->resultCode)); +} +  void CCloudService::HandleHttpError(NETLIBHTTPREQUEST *response)  {  	if (response == NULL)  		throw Exception(HttpStatusToError()); -	if (!HTTP_CODE_SUCCESS(response->resultCode)) { -		if (response->dataLength) -			throw Exception(response->pData); -		throw Exception(HttpStatusToError(response->resultCode)); -	} +	if (!HTTP_CODE_SUCCESS(response->resultCode)) +		HttpResponseToError(response);  }  JSONNode CCloudService::GetJsonResponse(NETLIBHTTPREQUEST *response) diff --git a/plugins/CloudFile/src/cloud_service.h b/plugins/CloudFile/src/cloud_service.h index ed35961cd6..edc4cdd90d 100644 --- a/plugins/CloudFile/src/cloud_service.h +++ b/plugins/CloudFile/src/cloud_service.h @@ -1,6 +1,13 @@  #ifndef _CLOUD_SERVICE_H_  #define _CLOUD_SERVICE_H_ +enum OnConflict +{ +	NONE, +	RENAME, +	REPLACE, +}; +  class CCloudService  {  protected: @@ -12,6 +19,7 @@ protected:  	char* PreparePath(const wchar_t *oldPath, char *newPath);  	virtual char* HttpStatusToError(int status = 0); +	virtual void HttpResponseToError(NETLIBHTTPREQUEST *response);  	virtual void HandleHttpError(NETLIBHTTPREQUEST *response);  	virtual void HandleJsonError(JSONNode &node) = 0; @@ -23,8 +31,8 @@ public:  	CCloudService(HNETLIBUSER hConnection);  	virtual const char* GetModule() const = 0; -	virtual const wchar_t* GetText() const = 0; -	virtual int GetIconId() const = 0; +	virtual const wchar_t* GetText() const; +	virtual int GetIconId() const;  	virtual bool IsLoggedIn() = 0;  	virtual void Login() = 0; @@ -34,11 +42,28 @@ public:  	virtual UINT Upload(FileTransferParam *ftp) = 0; -	void SendToContact(MCONTACT hContact, const wchar_t *data); -	void PasteToInputArea(MCONTACT hContact, const wchar_t *data); -	void PasteToClipboard(const wchar_t *data); -  	void Report(MCONTACT hContact, const wchar_t *data);  }; +class CCloudServiceSearch : public CCloudService +{ +private: +	const char *m_search; + +protected: +	void HandleJsonError(JSONNode&) { } + +public: +	CCloudServiceSearch(const char *search) +		: CCloudService(NULL), m_search(search) { } + +	const char* GetModule() const { return m_search; } + +	bool IsLoggedIn() { return false; } +	void Login() { } +	void Logout() { } + +	UINT Upload(FileTransferParam*) { return 0; } +}; +  #endif //_CLOUD_SERVICE_H_
\ No newline at end of file diff --git a/plugins/CloudFile/src/events.cpp b/plugins/CloudFile/src/events.cpp index df71721dfb..248397b8f4 100644 --- a/plugins/CloudFile/src/events.cpp +++ b/plugins/CloudFile/src/events.cpp @@ -2,16 +2,6 @@  int OnModulesLoaded(WPARAM, LPARAM)  { -	// init -	InitServices(); -	InitializeIcons(); -	InitializeMenus(); -	// netlib -	NETLIBUSER nlu = {}; -	nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; -	nlu.szSettingsModule = MODULE; -	nlu.szDescriptiveName.w = _A2W("MODULE"); -	hNetlibConnection = Netlib_RegisterUser(&nlu);  	// options  	HookEvent(ME_OPT_INITIALISE, OnOptionsInitialized);  	// srfile @@ -35,27 +25,21 @@ int OnProtoAck(WPARAM, LPARAM lParam)  {  	ACKDATA *ack = (ACKDATA*)lParam; -	if (!mir_strcmp(ack->szModule, MODULE)) -		return 0; // don't rebroadcast our own acks - -	if (ack->type == ACKTYPE_STATUS) { -		WORD status = ack->lParam; -		bool canSendOffline = (CallProtoService(ack->szModule, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDOFFLINE) > 0; - -		for (MCONTACT hContact = db_find_first(ack->szModule); hContact; hContact = db_find_next(hContact, ack->szModule)) { -			MessageWindowData msgw; -			if (!Srmm_GetWindowData(hContact, msgw) && msgw.uState & MSG_WINDOW_STATE_EXISTS) { -				BBButton bbd = {}; -				bbd.pszModuleName = MODULE; -				bbd.dwButtonID = BBB_ID_FILE_SEND; -				bbd.bbbFlags = BBSF_RELEASED; - -				if (status == ID_STATUS_OFFLINE && !canSendOffline) -					bbd.bbbFlags = BBSF_DISABLED; - -				Srmm_SetButtonState(hContact, &bbd); -			} -		} +	if (ack->type != ACKTYPE_STATUS) +		return 0; + +	for (MCONTACT hContact = db_find_first(ack->szModule); hContact; hContact = db_find_next(hContact, ack->szModule)) { +		MessageWindowData msgw; +		if (Srmm_GetWindowData(hContact, msgw) || !(msgw.uState & MSG_WINDOW_STATE_EXISTS)) +			continue; + +		BBButton bbd = {}; +		bbd.pszModuleName = MODULE; +		bbd.dwButtonID = BBB_ID_FILE_SEND; +		bbd.bbbFlags = CanSendToContact(hContact) +			? BBSF_RELEASED +			: BBSF_DISABLED; +		Srmm_SetButtonState(hContact, &bbd);  	}  	return 0; diff --git a/plugins/CloudFile/src/file_transfer.h b/plugins/CloudFile/src/file_transfer.h index 700988eaf4..cdf4475aeb 100644 --- a/plugins/CloudFile/src/file_transfer.h +++ b/plugins/CloudFile/src/file_transfer.h @@ -14,9 +14,7 @@ private:  	const wchar_t* folderName;  	int relativePathStart; - -	CMStringW serverFolder; - +	  	CMStringW data;  public: @@ -96,17 +94,9 @@ public:  			folderName = wcsrchr(path, '\\') + 1;  	} -	void SetServerFolder(const wchar_t *path) -	{ -		if (path) -			serverFolder = path; -	} - -	const wchar_t* GetServerFolder() const +	const wchar_t* IsFolder() const  	{ -		if (serverFolder.IsEmpty()) -			return NULL; -		return serverFolder; +		return folderName;  	}  	const wchar_t* GetFolderName() const diff --git a/plugins/CloudFile/src/main.cpp b/plugins/CloudFile/src/main.cpp index a95c9db056..40a660a490 100644 --- a/plugins/CloudFile/src/main.cpp +++ b/plugins/CloudFile/src/main.cpp @@ -39,6 +39,16 @@ extern "C" int __declspec(dllexport) Load(void)  	HookEvent(ME_PROTO_ACK, OnProtoAck);  	HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); +	NETLIBUSER nlu = {}; +	nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; +	nlu.szSettingsModule = MODULE; +	nlu.szDescriptiveName.w = _A2W("MODULE"); +	hNetlibConnection = Netlib_RegisterUser(&nlu); + +	InitServices(); +	InitializeIcons(); +	InitializeMenus(); +  	return 0;  } diff --git a/plugins/CloudFile/src/menus.cpp b/plugins/CloudFile/src/menus.cpp index 235ed4e196..13791c13de 100644 --- a/plugins/CloudFile/src/menus.cpp +++ b/plugins/CloudFile/src/menus.cpp @@ -15,25 +15,40 @@ void InitializeMenus()  {  	CMenuItem mi;  	SET_UID(mi, 0x93d4495b, 0x259b, 0x4fba, 0xbc, 0x14, 0xf9, 0x46, 0x2c, 0xda, 0xfc, 0x6d); -	mi.name.a = LPGEN("Upload files to..."); -	mi.position = -2000020001; +	mi.name.a = LPGEN("Upload to ..."); + +	ptrA defaultService(db_get_sa(NULL, MODULE, "DefaultService")); +	if (defaultService) { +		CCloudServiceSearch search(defaultService); +		CCloudService *service = Services.find(&search); +		if (service) { +			mi.name.a = LPGEN("Upload"); +			mi.pszService = MODULE "/Default/Upload"; +			CreateServiceFunctionObj(mi.pszService, UploadMenuCommand, service); +		} +	} + +	mi.position = -2000019999;  	mi.hIcon = LoadIconEx(IDI_UPLOAD);  	hContactMenu = Menu_AddContactMenuItem(&mi); +	if (defaultService) +		return; +  	UNSET_UID(mi); -	mi.flags |= CMIF_SYSTEM | CMIF_UNICODE; +	  	mi.root = hContactMenu;  	size_t count = Services.getCount(); +	  	for (size_t i = 0; i < count; i++) {  		CCloudService *service = Services[i]; -		if (!db_get_b(NULL, service->GetModule(), "IsEnable", TRUE)) -			continue; - -		CMStringA serviceName(CMStringDataFormat::FORMAT, "%s/%s/Upload", MODULE, service->GetModule()); -	 +		CMStringA serviceName = MODULE; +		serviceName.AppendFormat("/%s/Upload", service->GetModule());  		mi.pszService = serviceName.GetBuffer(); + +		mi.flags = CMIF_SYSTEM | CMIF_UNICODE;  		mi.name.w = (wchar_t*)service->GetText();  		mi.position = i;  		mi.hIcolibItem = GetIconHandle(Services[i]->GetIconId()); @@ -44,19 +59,7 @@ void InitializeMenus()  int OnPrebuildContactMenu(WPARAM hContact, LPARAM)  { -	bool bShow = false; -	char *proto = GetContactProto(hContact); -	if (proto) { -		bool bHasIM = (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) != 0; -		if (bHasIM) { -			bool isProtoOnline = CallProtoService(proto, PS_GETSTATUS, 0, 0) > ID_STATUS_OFFLINE; -			WORD status = db_get_w(hContact, proto, "Status", ID_STATUS_OFFLINE); -			bool canSendOffline = (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDOFFLINE) > 0; -			if (isProtoOnline && (status != ID_STATUS_OFFLINE || canSendOffline)) -				bShow = true; -		} -	} -	Menu_ShowItem(hContactMenu, bShow); +	Menu_ShowItem(hContactMenu, CanSendToContact(hContact));  	return 0;  }
\ No newline at end of file diff --git a/plugins/CloudFile/src/options.cpp b/plugins/CloudFile/src/options.cpp index e09b659bc1..ca9a860962 100644 --- a/plugins/CloudFile/src/options.cpp +++ b/plugins/CloudFile/src/options.cpp @@ -2,11 +2,18 @@  COptionsMain::COptionsMain()  	: CPluginDlgBase(hInstance, IDD_OPTIONS_MAIN, MODULE), +	m_defaultService(this, IDC_DEFAULTSERVICE), +	m_renameOnConflict(this, IDC_RENAMEONCONFLICT), +	m_repalceOnConflict(this, IDC_REPLACEONCONFLICT),  	m_urlAutoSend(this, IDC_URL_AUTOSEND),  	m_urlPasteToMessageInputArea(this, IDC_URL_COPYTOMIA), -	m_urlCopyToClipboard(this, IDC_URL_COPYTOCB), -	m_services(this, IDC_SERVICES), isServiceListInit(false) +	m_urlCopyToClipboard(this, IDC_URL_COPYTOCB)  { +	/*CreateLink(m_defaultService, "DefaultService", L""); + +	CreateLink(m_renameOnConflict, "RenameOnConflict", DBVT_BYTE, 1); +	CreateLink(m_repalceOnConflict, "RepalceOnConflict", DBVT_BYTE, 0);*/ +  	CreateLink(m_urlAutoSend, "UrlAutoSend", DBVT_BYTE, 1);  	CreateLink(m_urlPasteToMessageInputArea, "UrlPasteToMessageInputArea", DBVT_BYTE, 0);  	CreateLink(m_urlCopyToClipboard, "UrlCopyToClipboard", DBVT_BYTE, 0); @@ -16,58 +23,41 @@ void COptionsMain::OnInitDialog()  {  	CDlgBase::OnInitDialog(); -	m_services.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_INFOTIP); - -	m_services.AddColumn(0, TranslateT("Account name"), 50); +	ptrA defaultService(db_get_sa(NULL, MODULE, "DefaultService")); +	int iItem = m_defaultService.AddString(TranslateT("No")); +	m_defaultService.SetCurSel(iItem);  	size_t count = Services.getCount();  	for (size_t i = 0; i < count; i++) {  		CCloudService *service = Services[i]; -		int iItem = m_services.AddItem(mir_wstrdup(service->GetText()), -1, (LPARAM)service); -		//m_services.SetItem(iItem, 1, mir_a2u(service->GetModule)); -		int isEnable = db_get_b(NULL, service->GetModule(), "IsEnable", TRUE); -		m_services.SetCheckState(iItem, isEnable); +		iItem = m_defaultService.AddString(mir_wstrdup(service->GetText()), (LPARAM)service); +		if (!mir_strcmpi(service->GetModule(), defaultService)) +			m_defaultService.SetCurSel(iItem);  	} -	m_services.SetColumnWidth(0, LVSCW_AUTOSIZE_USEHEADER); - -	isServiceListInit = true; +	BYTE strategy = db_get_b(NULL, MODULE, "ConflictStrategy", OnConflict::NONE); +	if (strategy == OnConflict::RENAME) +		m_renameOnConflict.SetState(TRUE); +	else if (strategy == OnConflict::REPLACE) +		m_repalceOnConflict.SetState(TRUE);  }  void COptionsMain::OnApply()  { -	int count = m_services.GetItemCount(); -	for (int iItem = 0; iItem < count; iItem++) -	{ -		CCloudService *service = (CCloudService*)m_services.GetItemData(iItem); - -		int isEnable = m_services.GetCheckState(iItem); -		db_set_b(NULL, service->GetModule(), "IsEnable", isEnable); -	} -} - -INT_PTR COptionsMain::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ -	switch (msg) -	{ -	case WM_NOTIFY: -	{ -		LPNMHDR lpnmHdr = (LPNMHDR)lParam; -		if (lpnmHdr->idFrom == (UINT_PTR)m_services.GetCtrlId() && lpnmHdr->code == LVN_ITEMCHANGED) -		{ -			LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam; -			if (pnmv->uChanged & LVIF_STATE && pnmv->uNewState & LVIS_STATEIMAGEMASK) -			{ -				if (isServiceListInit) -					NotifyChange(); -			} -		} -	} -	break; -	} - -	return CDlgBase::DlgProc(msg, wParam, lParam); +	int iItem = m_defaultService.GetCurSel(); +	CCloudService *service = (CCloudService*)m_defaultService.GetItemData(iItem); +	if (service) +		db_set_s(NULL, MODULE, "DefaultService", service->GetModule()); +	else +		db_unset(NULL, MODULE, "DefaultService"); + +	if (m_renameOnConflict.GetState()) +		db_set_b(NULL, MODULE, "ConflictStrategy", OnConflict::RENAME); +	else if (m_repalceOnConflict.GetState()) +		db_set_b(NULL, MODULE, "ConflictStrategy", OnConflict::REPLACE); +	else +		db_unset(NULL, MODULE, "ConflictStrategy");  }  ///////////////////////////////////////////////////////////////////////////////// diff --git a/plugins/CloudFile/src/options.h b/plugins/CloudFile/src/options.h index d6f5e7caaf..a0fd102c7d 100644 --- a/plugins/CloudFile/src/options.h +++ b/plugins/CloudFile/src/options.h @@ -4,19 +4,19 @@  class COptionsMain : public CPluginDlgBase  {  private: +	CCtrlCombo m_defaultService; + +	CCtrlCheck m_renameOnConflict; +	CCtrlCheck m_repalceOnConflict; +  	CCtrlCheck m_urlAutoSend;  	CCtrlCheck m_urlPasteToMessageInputArea;  	CCtrlCheck m_urlCopyToClipboard; -	bool isServiceListInit; -	CCtrlListView m_services; -  protected:  	void OnInitDialog();  	void OnApply(); -	INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); -  public:  	COptionsMain();  }; diff --git a/plugins/CloudFile/src/resource.h b/plugins/CloudFile/src/resource.h index 4360fd84b5..90d32f5162 100644 --- a/plugins/CloudFile/src/resource.h +++ b/plugins/CloudFile/src/resource.h @@ -13,12 +13,14 @@  #define IDC_OAUTH_CODE                  121  #define IDC_OAUTH_AUTHORIZE             122  #define IDD_OPTIONS_MAIN                1000 -#define IDC_URL_ISTEMPORARY             1001 -#define IDC_URL_COPYTOCB                1002 -#define IDC_URL_COPYTOMIA               1003 -#define IDC_URL_AUTOSEND                1004 -#define IDC_ACCOUNTS                    1011 -#define IDC_SERVICES                    1011 +#define IDC_DEFAULTSERVICE              1001 +#define IDC_DONOTHING                   1010 +#define IDC_RENAMEONCONFLICT            1011 +#define IDC_REPLACEONCONFLICT           1012 +#define IDC_URL_ISTEMPORARY             1021 +#define IDC_URL_COPYTOCB                1022 +#define IDC_URL_COPYTOMIA               1023 +#define IDC_URL_AUTOSEND                1024  // Next default values for new objects  //  @@ -26,7 +28,7 @@  #ifndef APSTUDIO_READONLY_SYMBOLS  #define _APS_NEXT_RESOURCE_VALUE        130  #define _APS_NEXT_COMMAND_VALUE         40001 -#define _APS_NEXT_CONTROL_VALUE         1013 +#define _APS_NEXT_CONTROL_VALUE         1030  #define _APS_NEXT_SYMED_VALUE           101  #endif  #endif diff --git a/plugins/CloudFile/src/srmm.cpp b/plugins/CloudFile/src/srmm.cpp index 8781479c1b..58d8ef9708 100644 --- a/plugins/CloudFile/src/srmm.cpp +++ b/plugins/CloudFile/src/srmm.cpp @@ -4,9 +4,9 @@ int OnSrmmToolbarLoaded(WPARAM, LPARAM)  {  	BBButton bbd = {};  	bbd.pszModuleName = MODULE; -	bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON; +	bbd.bbbFlags = BBBF_ISIMBUTTON | BBBF_ISCHATBUTTON | BBBF_ISRSIDEBUTTON | BBBF_ISARROWBUTTON; -	CMStringW tooltip(CMStringDataFormat::FORMAT, TranslateT("Upload files to...")); +	CMStringW tooltip(FORMAT, TranslateT("Upload files to..."));  	bbd.pwszTooltip = tooltip;  	bbd.hIcon = GetIconHandle(IDI_UPLOAD);  	bbd.dwButtonID = BBB_ID_FILE_SEND; @@ -20,18 +20,12 @@ int OnSrmmWindowOpened(WPARAM, LPARAM lParam)  {  	MessageWindowEventData *ev = (MessageWindowEventData*)lParam;  	if (ev->uType == MSG_WINDOW_EVT_OPENING && ev->hContact) { -		char *proto = GetContactProto(ev->hContact); -		bool isProtoOnline = CallProtoService(proto, PS_GETSTATUS, 0, 0) > ID_STATUS_OFFLINE; -		WORD status = db_get_w(ev->hContact, proto, "Status", ID_STATUS_OFFLINE); -		bool canSendOffline = (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDOFFLINE) > 0; -  		BBButton bbd = {};  		bbd.pszModuleName = MODULE;  		bbd.dwButtonID = BBB_ID_FILE_SEND; -		bbd.bbbFlags = BBSF_RELEASED; -		if (!isProtoOnline || (status == ID_STATUS_OFFLINE && !canSendOffline)) -			bbd.bbbFlags = BBSF_DISABLED; - +		bbd.bbbFlags = CanSendToContact(ev->hContact) +			? BBSF_RELEASED +			: BBSF_DISABLED;  		Srmm_SetButtonState(ev->hContact, &bbd);  	} @@ -48,23 +42,31 @@ int OnSrmmButtonPressed(WPARAM, LPARAM lParam)  	if (cbc->dwButtonId != BBB_ID_FILE_SEND)  		return 0; +	if (cbc->flags != BBCF_ARROWCLICKED) { +		ptrA defaultService(db_get_sa(NULL, MODULE, "DefaultService")); +		if (defaultService) { +			CCloudServiceSearch search(defaultService); +			CCloudService *service = Services.find(&search); +			if (service) +				service->OpenUploadDialog(cbc->hContact); +			return 0; +		} +	} +  	HMENU hMenu = CreatePopupMenu();  	size_t count = Services.getCount();  	for (size_t i = 0; i < count; i++) {  		CCloudService *service = Services[i]; -		if (!db_get_b(NULL, service->GetModule(), "IsEnable", TRUE)) -			continue; - -		InsertMenu(hMenu, i, MF_STRING, i + 1, TranslateW(service->GetText())); +		InsertMenu(hMenu, i, MF_STRING | MF_BYPOSITION, i + 1,TranslateW(service->GetText()));  		//HBITMAP hBitmap = (HBITMAP)LoadImage(hInstance, MAKEINTRESOURCE(service->GetIconId()), IMAGE_ICON, 16, 16, 0);  		//SetMenuItemBitmaps(hMenu, i, MF_BITMAP, hBitmap, hBitmap);  	} -	int ind = TrackPopupMenu(hMenu, TPM_RETURNCMD, cbc->pt.x, cbc->pt.y, 0, cbc->hwndFrom, NULL); -	if (ind > 0) { -		CCloudService *service = Services[ind - 1]; +	int pos = TrackPopupMenu(hMenu, TPM_RETURNCMD, cbc->pt.x, cbc->pt.y, 0, cbc->hwndFrom, NULL); +	if (pos > 0) { +		CCloudService *service = Services[pos - 1];  		service->OpenUploadDialog(cbc->hContact);  	} diff --git a/plugins/CloudFile/src/stdafx.h b/plugins/CloudFile/src/stdafx.h index e74711a96a..a002e334c2 100644 --- a/plugins/CloudFile/src/stdafx.h +++ b/plugins/CloudFile/src/stdafx.h @@ -108,5 +108,9 @@ UINT UploadAndReportProgressThread(void *owner, void *arg);  void ShowNotification(const wchar_t *caption, const wchar_t *message, int flags, MCONTACT hContact = NULL);  void ShowNotification(const wchar_t *message, int flags, MCONTACT hContact = NULL);  MEVENT AddEventToDb(MCONTACT hContact, WORD type, DWORD flags, DWORD cbBlob, PBYTE pBlob); +bool CanSendToContact(MCONTACT hContact); +void SendToContact(MCONTACT hContact, const wchar_t *data); +void PasteToInputArea(MCONTACT hContact, const wchar_t *data); +void PasteToClipboard(const wchar_t *data);  #endif //_COMMON_H_
\ No newline at end of file diff --git a/plugins/CloudFile/src/utils.cpp b/plugins/CloudFile/src/utils.cpp index cabcd7de97..e4846baf31 100644 --- a/plugins/CloudFile/src/utils.cpp +++ b/plugins/CloudFile/src/utils.cpp @@ -38,3 +38,65 @@ MEVENT AddEventToDb(MCONTACT hContact, WORD type, DWORD flags, DWORD cbBlob, PBY  	dbei.flags = flags;  	return db_event_add(hContact, &dbei);  } + +bool CanSendToContact(MCONTACT hContact) +{ +	if (!hContact) +		return false; + +	const char *proto = GetContactProto(hContact); +	if (!proto) +		return false; + +	bool canSend = (CallProtoService(proto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND) != 0; +	if (!canSend) +		return false; + +	bool isProtoOnline = CallProtoService(proto, PS_GETSTATUS, 0, 0) > ID_STATUS_OFFLINE; +	if (isProtoOnline) +		return true; + +	bool isContactOnline = db_get_w(hContact, proto, "Status", ID_STATUS_OFFLINE) > ID_STATUS_OFFLINE; +	if (isContactOnline) +		return true; + +	return CallProtoService(proto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_IMSENDOFFLINE; +} + +void SendToContact(MCONTACT hContact, const wchar_t *data) +{ +	const char *szProto = GetContactProto(hContact); +	if (db_get_b(hContact, szProto, "ChatRoom", 0) == TRUE) { +		ptrW tszChatRoom(db_get_wsa(hContact, szProto, "ChatRoomID")); +		Chat_SendUserMessage(szProto, tszChatRoom, data); +		return; +	} + +	char *message = mir_utf8encodeW(data); +	if (ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)message) != ACKRESULT_FAILED) +		AddEventToDb(hContact, EVENTTYPE_MESSAGE, DBEF_UTF | DBEF_SENT, (DWORD)mir_strlen(message), (PBYTE)message); +} + +void PasteToInputArea(MCONTACT hContact, const wchar_t *data) +{ +	CallService(MS_MSG_SENDMESSAGEW, hContact, (LPARAM)data); +} + +void PasteToClipboard(const wchar_t *data) +{ +	if (OpenClipboard(NULL)) { +		EmptyClipboard(); + +		size_t size = sizeof(wchar_t) * (mir_wstrlen(data) + 1); +		HGLOBAL hClipboardData = GlobalAlloc(NULL, size); +		if (hClipboardData) { +			wchar_t *pchData = (wchar_t*)GlobalLock(hClipboardData); +			if (pchData) { +				memcpy(pchData, (wchar_t*)data, size); +				GlobalUnlock(hClipboardData); +				SetClipboardData(CF_UNICODETEXT, hClipboardData); +			} +		} +		CloseClipboard(); +	} +} diff --git a/plugins/CloudFile/src/version.h b/plugins/CloudFile/src/version.h index 1f08a3d35b..9c733ab819 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                1 +#define __BUILD_NUM                2  #include <stdver.h>  | 
