diff options
author | aunsane <aunsane@gmail.com> | 2017-05-07 02:25:29 +0300 |
---|---|---|
committer | aunsane <aunsane@gmail.com> | 2017-05-07 02:25:29 +0300 |
commit | ff6a107e5f566da2644fbfe36455467beafaeb1e (patch) | |
tree | 3d5b96794ee835c8686a74da6c418c440c91c403 /plugins | |
parent | 453b3de91c372ee7b2661771aead6675e12fe98f (diff) |
CloudFile:
- reworked options to dupport default service
- added options to select conflict behavior
- multiple fix and refactoring
- version bump
Diffstat (limited to 'plugins')
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> |