diff options
Diffstat (limited to 'plugins/CloudFile/src/Services/microsoft_service.cpp')
-rw-r--r-- | plugins/CloudFile/src/Services/microsoft_service.cpp | 262 |
1 files changed, 262 insertions, 0 deletions
diff --git a/plugins/CloudFile/src/Services/microsoft_service.cpp b/plugins/CloudFile/src/Services/microsoft_service.cpp new file mode 100644 index 0000000000..d002db45e6 --- /dev/null +++ b/plugins/CloudFile/src/Services/microsoft_service.cpp @@ -0,0 +1,262 @@ +#include "..\stdafx.h" +#include "microsoft_api.h" + +COneDriveService::COneDriveService(HNETLIBUSER hConnection) + : CCloudService(hConnection) +{ +} + +const char* COneDriveService::GetModule() const +{ + return "Microsoft"; +} + +const wchar_t* COneDriveService::GetText() const +{ + return L"OneDrive"; +} + +HANDLE COneDriveService::GetIcon() const +{ + return GetIconHandle(IDI_ONEDRIVE); +} + +bool COneDriveService::IsLoggedIn() +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + if (!token || token[0] == 0) + return false; + time_t now = time(NULL); + time_t expiresIn = db_get_dw(NULL, GetModule(), "ExpiresIn"); + return now < expiresIn; +} + +void COneDriveService::Login() +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + ptrA refreshToken(db_get_sa(NULL, GetModule(), "RefreshToken")); + if (token && refreshToken && refreshToken[0]) { + OneDriveAPI::RefreshTokenRequest request(refreshToken); + NLHR_PTR response(request.Send(hConnection)); + + JSONNode root = GetJsonResponse(response); + + JSONNode node = root.at("access_token"); + db_set_s(NULL, GetModule(), "TokenSecret", node.as_string().c_str()); + + node = root.at("expires_in"); + time_t expiresIn = time(NULL) + node.as_int(); + db_set_dw(NULL, GetModule(), "ExpiresIn", expiresIn); + + return; + } + + COAuthDlg dlg(this, MS_OAUTH "/authorize?response_type=code&scope=offline_access%20https%3A%2F%2Fgraph.microsoft.com%2Ffiles.readWrite&redirect_uri=https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient&client_id=" MS_APP_ID, RequestAccessTokenThread); + dlg.DoModal(); +} + +void COneDriveService::Logout() +{ + mir_forkthreadex(RevokeAccessTokenThread, this); +} + +unsigned COneDriveService::RequestAccessTokenThread(void *owner, void *param) +{ + HWND hwndDlg = (HWND)param; + COneDriveService *service = (COneDriveService*)owner; + + if (service->IsLoggedIn()) + service->Logout(); + + char requestToken[128]; + GetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, requestToken, _countof(requestToken)); + + OneDriveAPI::GetAccessTokenRequest request(requestToken); + NLHR_PTR response(request.Send(service->hConnection)); + + if (response == NULL || response->resultCode != HTTP_CODE_OK) { + const char *error = response->dataLength + ? response->pData + : service->HttpStatusToError(response->resultCode); + + Netlib_Logf(service->hConnection, "%s: %s", service->GetModule(), error); + 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); + return 0; + } + + JSONNode node = root.at("error"); + 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); + return 0; + } + + node = root.at("access_token"); + db_set_s(NULL, service->GetModule(), "TokenSecret", node.as_string().c_str()); + + node = root.at("expires_in"); + time_t expiresIn = time(NULL) + node.as_int(); + db_set_dw(NULL, service->GetModule(), "ExpiresIn", expiresIn); + + node = root.at("refresh_token"); + db_set_s(NULL, service->GetModule(), "RefreshToken", node.as_string().c_str()); + + SetDlgItemTextA(hwndDlg, IDC_OAUTH_CODE, ""); + + EndDialog(hwndDlg, 1); + + return 0; +} + +unsigned COneDriveService::RevokeAccessTokenThread(void *param) +{ + //COneDriveService *service = (COneDriveService*)param; + + /*ptrA token(db_get_sa(NULL, service->GetModule(), "TokenSecret")); + OneDriveAPI::RevokeAccessTokenRequest request(token); + NLHR_PTR response(request.Send(service->hConnection));*/ + + return 0; +} + +void COneDriveService::HandleJsonError(JSONNode &node) +{ + JSONNode error = node.at("error"); + if (!error.isnull()) { + json_string tag = error.at("message").as_string(); + throw Exception(tag.c_str()); + } +} + +void COneDriveService::CreateUploadSession(char *uploadUri, const char *name, const char *parentId) +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + OneDriveAPI::CreateUploadSessionRequest request = mir_strlen(parentId) + ? OneDriveAPI::CreateUploadSessionRequest(token, parentId, name) + : OneDriveAPI::CreateUploadSessionRequest(token, name); + NLHR_PTR response(request.Send(hConnection)); + + JSONNode root = GetJsonResponse(response); + JSONNode node = root.at("uploadUrl"); + 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) +{ + OneDriveAPI::UploadFileChunkRequest request(uploadUri, chunk, chunkSize, offset, fileSize); + NLHR_PTR response(request.Send(hConnection)); + + if (response == NULL) + throw Exception(HttpStatusToError()); + + if (response->resultCode == HTTP_CODE_ACCEPTED) + return; + + if (HTTP_CODE_SUCCESS(response->resultCode)) { + JSONNode root = GetJsonResponse(response); + JSONNode id = root.at("id"); + mir_strcpy(itemId, id.as_string().c_str()); + return; + } + + if (response->dataLength) + throw Exception(response->pData); + throw Exception(HttpStatusToError(response->resultCode)); +} + +void COneDriveService::CreateFolder(const char *path, char *itemId) +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + OneDriveAPI::CreateFolderRequest request(token, path); + NLHR_PTR response(request.Send(hConnection)); + + JSONNode root = GetJsonResponse(response); + JSONNode node = root.at("id"); + mir_strcpy(itemId, node.as_string().c_str()); +} + +void COneDriveService::CreateSharedLink(const char *itemId, char *url) +{ + ptrA token(db_get_sa(NULL, GetModule(), "TokenSecret")); + OneDriveAPI::CreateSharedLinkRequest request(token, itemId); + NLHR_PTR response(request.Send(hConnection)); + + JSONNode root = GetJsonResponse(response); + JSONNode node = root.at("webUrl"); + mir_strcpy(url, node.as_string().c_str()); +} + +UINT COneDriveService::Upload(FileTransferParam *ftp) +{ + try { + if (!IsLoggedIn()) + Login(); + + if (!IsLoggedIn()) { + ftp->SetStatus(ACKRESULT_FAILED); + return ACKRESULT_FAILED; + } + + char folderId[32] = { 0 }; + const wchar_t *folderName = ftp->GetFolderName(); + if (folderName) { + char path[MAX_PATH], link[MAX_PATH]; + PreparePath(folderName, path); + CreateFolder(path, folderId); + CreateSharedLink(path, link); + ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(link))); + } + + ftp->FirstFile(); + do + { + const wchar_t *fileName = ftp->GetCurrentRelativeFilePath(); + uint64_t fileSize = ftp->GetCurrentFileSize(); + + uint64_t offset = 0; + char fileId[32]; + char uploadUri[1024]; + CreateUploadSession(uploadUri, T2Utf(fileName), folderId); + + size_t chunkSize = ftp->GetCurrentFileChunkSize(); + mir_ptr<char>chunk((char*)mir_calloc(chunkSize)); + + size_t size = 0; + for (size_t i = 0; i < (fileSize / chunkSize); i++) + { + ftp->CheckCurrentFile(); + + size = ftp->ReadCurrentFile(chunk, chunkSize); + if (size == 0) + break; + + UploadFileChunk(uploadUri, chunk, size, offset, fileSize, fileId); + + offset += size; + ftp->Progress(size); + } + + if (!wcschr(fileName, L'\\')) { + char url[MAX_PATH]; + CreateSharedLink(fileId, url); + ftp->AppendFormatData(L"%s\r\n", ptrW(mir_utf8decodeW(url))); + } + } while (ftp->NextFile()); + } + catch (Exception &ex) { + Netlib_Logf(hConnection, "%s: %s", MODULE, ex.what()); + ftp->SetStatus(ACKRESULT_FAILED); + return ACKRESULT_FAILED; + } + + ftp->SetStatus(ACKRESULT_SUCCESS); + return ACKRESULT_SUCCESS; +} |