From 0b82b879821c7e73b86f189be747c5634c8b46b7 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Mon, 22 Feb 2016 21:12:25 +0000 Subject: Dropbox: - updated api to v2 - version bump git-svn-id: http://svn.miranda-ng.org/main/trunk@16326 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Dropbox/src/api/account.h | 19 ++++---- plugins/Dropbox/src/api/operations.h | 74 ++++++++++++++++++++-------- plugins/Dropbox/src/api/upload.h | 67 ++++++++++++++++++++----- plugins/Dropbox/src/dropbox.cpp | 47 ++++++++++-------- plugins/Dropbox/src/dropbox.h | 13 +++-- plugins/Dropbox/src/dropbox_commands.cpp | 81 +++++++++++++++---------------- plugins/Dropbox/src/dropbox_options.cpp | 2 +- plugins/Dropbox/src/dropbox_services.cpp | 2 +- plugins/Dropbox/src/dropbox_transfers.cpp | 81 +++++++++++++++---------------- plugins/Dropbox/src/dropbox_utils.cpp | 34 +++++++++++-- plugins/Dropbox/src/file_transfer.h | 16 ------ plugins/Dropbox/src/stdafx.h | 26 ++++++++-- plugins/Dropbox/src/version.h | 4 +- 13 files changed, 290 insertions(+), 176 deletions(-) (limited to 'plugins/Dropbox/src') diff --git a/plugins/Dropbox/src/api/account.h b/plugins/Dropbox/src/api/account.h index 9c8bf20e7e..2842804dcc 100644 --- a/plugins/Dropbox/src/api/account.h +++ b/plugins/Dropbox/src/api/account.h @@ -5,30 +5,31 @@ class GetAccessTokenRequest : public HttpRequest { public: GetAccessTokenRequest(const char *requestToken) : - HttpRequest(REQUEST_POST, DROPBOX_API_URL "/oauth2/token") + HttpRequest(REQUEST_POST, DROPBOX_API_OLD "/oauth2/token") { - AddBasicAuthHeader(DROPBOX_APP_KEY, DROPBOX_API_SECRET); AddHeader("Content-Type", "application/x-www-form-urlencoded"); - CMStringA data(CMStringDataFormat::FORMAT, "grant_type=authorization_code&code=%s", requestToken); + CMStringA data(CMStringDataFormat::FORMAT, + "client_id=%s&client_secret=%s&grant_type=authorization_code&code=%s", + DROPBOX_APP_KEY, DROPBOX_API_SECRET, requestToken); SetData(data.GetBuffer(), data.GetLength()); } }; -class DisableAccessTokenRequest : public HttpRequest +/*class DisableAccessTokenRequest : public HttpRequest { public: DisableAccessTokenRequest() : - HttpRequest(REQUEST_POST, DROPBOX_API_URL "/disable_access_token") + HttpRequest(REQUEST_POST, DROPBOX_API_OLD "/disable_access_token") { } -}; +};*/ -class GetAccountInfoRequest : public HttpRequest +class GetCurrentAccountRequest : public HttpRequest { public: - GetAccountInfoRequest(const char *token) : - HttpRequest(REQUEST_GET, DROPBOX_API_URL "/account/info") + GetCurrentAccountRequest(const char *token) : + HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/users/get_current_account") { AddBearerAuthHeader(token); } diff --git a/plugins/Dropbox/src/api/operations.h b/plugins/Dropbox/src/api/operations.h index e41dbaabfe..71c455d1e8 100644 --- a/plugins/Dropbox/src/api/operations.h +++ b/plugins/Dropbox/src/api/operations.h @@ -4,54 +4,88 @@ class ShareRequest : public HttpRequest { public: - ShareRequest(const char *token, const char *path, bool useShortUrl, const char *root = "auto") : - HttpRequest(REQUEST_POST, FORMAT, DROPBOX_API_URL "/shares/%s/%s", root, path) + ShareRequest(const char *token, const char *path, time_t expires = 0) : + HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/sharing/create_shared_link_with_settings") { - if (!useShortUrl) - AddUrlParameter("short_url=false"); - AddBearerAuthHeader(token); - AddHeader("Content-Type", "application/x-www-form-urlencoded"); + AddHeader("Content-Type", "application/json"); + + JSONNode root(JSON_NODE); + root << JSONNode("path", path); + + if (expires) + root << JSONNode("expires", (unsigned int)expires); + + json_string data = root.write(); + SetData(data.c_str(), data.length()); } }; class DeleteRequest : public HttpRequest { public: - DeleteRequest(const char *token, const char *path, const char *root = "auto") : - HttpRequest(REQUEST_POST, DROPBOX_API_URL "/fileops/delete") + DeleteRequest(const char *token, const char *path) : + HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/files/delete") { AddBearerAuthHeader(token); - AddHeader("Content-Type", "application/x-www-form-urlencoded"); + AddHeader("Content-Type", "application/json"); + + JSONNode root(JSON_NODE); + root << JSONNode("path", path); - CMStringA data(CMStringDataFormat::FORMAT, "root=%s&path=%s", root, path); - data.Replace('\\', '/'); - SetData(data.GetBuffer(), data.GetLength()); + json_string data = root.write(); + SetData(data.c_str(), data.length()); } }; class CreateFolderRequest : public HttpRequest { public: - CreateFolderRequest(const char *token, const char *path, const char *root = "auto") : - HttpRequest(REQUEST_POST, DROPBOX_API_URL "/fileops/create_folder") + CreateFolderRequest(const char *token, const char *path) : + HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/files/create_folder") { AddBearerAuthHeader(token); - AddHeader("Content-Type", "application/x-www-form-urlencoded"); + AddHeader("Content-Type", "application/json"); - CMStringA data(CMStringDataFormat::FORMAT, "root=%s&path=%s", root, path); - data.Replace('\\', '/'); - SetData(data.GetBuffer(), data.GetLength()); + JSONNode root(JSON_NODE); + root << JSONNode("path", path); + + json_string data = root.write(); + SetData(data.c_str(), data.length()); } }; class GetMetadataRequest : public HttpRequest { public: - GetMetadataRequest(const char *token, const char *path, const char *root = "auto") : - HttpRequest(REQUEST_GET, FORMAT, DROPBOX_API_URL "/metadata/%s/%s", root, path) + GetMetadataRequest(const char *token, const char *path) : + HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/files/get_metadata") { AddBearerAuthHeader(token); + AddHeader("Content-Type", "application/json"); + + JSONNode root(JSON_NODE); + root << JSONNode("path", path); + + json_string data = root.write(); + SetData(data.c_str(), data.length()); + } +}; + +class ListFolderRequest : public HttpRequest +{ +public: + ListFolderRequest(const char *token, const char *path) : + HttpRequest(REQUEST_POST, DROPBOX_API_RPC "/files/list_folder") + { + AddBearerAuthHeader(token); + AddHeader("Content-Type", "application/json"); + + JSONNode root(JSON_NODE); + root << JSONNode("path", path); + + json_string data = root.write(); + SetData(data.c_str(), data.length()); } }; diff --git a/plugins/Dropbox/src/api/upload.h b/plugins/Dropbox/src/api/upload.h index 4bc9da9043..22125ed66d 100644 --- a/plugins/Dropbox/src/api/upload.h +++ b/plugins/Dropbox/src/api/upload.h @@ -4,39 +4,84 @@ class UploadFileRequest : public HttpRequest { public: - UploadFileRequest(const char *token, const char *fileName, const char *data, size_t size, const char *root = "auto") : - HttpRequest(REQUEST_PUT, FORMAT, DROPBOX_APICONTENT_URL "/files_put/%s/%s", root, fileName) + UploadFileRequest(const char *token, const char *path, const char *data, size_t size) : + HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload") { AddBearerAuthHeader(token); + AddHeader("Content-Type", "application/octet-stream"); + + JSONNode root(JSON_NODE); + root << JSONNode("path", path); + + json_string params = root.write(); + AddHeader("Dropbox-API-Arg", params.c_str()); + SetData(data, size); } }; -class UploadFileChunkRequest : public HttpRequest +class StartUploadSessionRequest : public HttpRequest { public: - UploadFileChunkRequest(const char *token, const char *data, size_t size) : - HttpRequest(REQUEST_PUT, DROPBOX_APICONTENT_URL "/chunked_upload") + StartUploadSessionRequest(const char *token, const char *data, size_t size) : + HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/start") { AddBearerAuthHeader(token); AddHeader("Content-Type", "application/octet-stream"); + SetData(data, size); } +}; - UploadFileChunkRequest(const char *token, const char *uploadId, size_t offset, const char *data, size_t size) : - HttpRequest(REQUEST_PUT, FORMAT, DROPBOX_APICONTENT_URL "/chunked_upload?upload_id=%s&offset=%i", uploadId, offset) +class AppendToUploadSessionRequest : public HttpRequest +{ +public: + AppendToUploadSessionRequest(const char *token, const char *sessionId, size_t offset, const char *data, size_t size) : + HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/append") { AddBearerAuthHeader(token); AddHeader("Content-Type", "application/octet-stream"); + + JSONNode root(JSON_NODE); + root + << JSONNode("session_id", sessionId) + << JSONNode("offset", offset); + + json_string params = root.write(); + AddHeader("Dropbox-API-Arg", params.c_str()); + SetData(data, size); } +}; - UploadFileChunkRequest(const char *token, const char *uploadId, const char *path, const char *root = "auto") : - HttpRequest(REQUEST_POST, FORMAT, DROPBOX_APICONTENT_URL "/commit_chunked_upload/%s/%s", root, path) +class FinishUploadSessionRequest : public HttpRequest +{ +public: + FinishUploadSessionRequest(const char *token, const char *sessionId, size_t offset, const char *path, const char *data, size_t size) : + HttpRequest(REQUEST_POST, DROPBOX_API_CU "/files/upload_session/finish") { AddBearerAuthHeader(token); - AddHeader("Content-Type", "application/x-www-form-urlencoded"); - AddUrlParameter("upload_id=%s", uploadId); + AddHeader("Content-Type", "application/octet-stream"); + + JSONNode cursor(JSON_NODE); + cursor.set_name("cursor"); + cursor + << JSONNode("session_id", sessionId) + << JSONNode("offset", offset); + + JSONNode commit(JSON_NODE); + commit.set_name("commit"); + commit << JSONNode("path", path); + + JSONNode root(JSON_NODE); + root + << cursor + << commit; + + json_string params = root.write(); + AddHeader("Dropbox-API-Arg", params.c_str()); + + SetData(data, size); } }; diff --git a/plugins/Dropbox/src/dropbox.cpp b/plugins/Dropbox/src/dropbox.cpp index 880f8a07c8..46d8d5fa8c 100644 --- a/plugins/Dropbox/src/dropbox.cpp +++ b/plugins/Dropbox/src/dropbox.cpp @@ -65,9 +65,9 @@ void CDropbox::RequestAccountInfo(void *p) MCONTACT hContact = self->GetDefaultContact(); ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - GetAccountInfoRequest request(token); + GetCurrentAccountRequest request(token); NLHR_PTR response(request.Send(self->hNetlibConnection)); - HandleHttpResponseError(response); + HandleJsonResponseError(response); JSONNode root = JSONNode::parse(response->pData); if (root.empty()) @@ -77,18 +77,27 @@ void CDropbox::RequestAccountInfo(void *p) if (!referral_link.empty()) db_set_s(hContact, MODULE, "Homepage", referral_link.as_string().c_str()); - JSONNode display_name = root.at("display_name"); - if (!display_name.empty()) { - CMString tszDisplayName(display_name.as_mstring()); - int pos = tszDisplayName.ReverseFind(' '); - if (pos != -1) { - db_set_ts(hContact, MODULE, "LastName", tszDisplayName.Mid(pos + 1)); - db_set_ts(hContact, MODULE, "FirstName", tszDisplayName.Left(pos)); - } - else { - db_set_ts(hContact, MODULE, "FirstName", tszDisplayName); - db_unset(hContact, MODULE, "LastName"); - } + JSONNode email = root.at("email"); + if (!email.empty()) + db_set_s(hContact, MODULE, "e-mail", email.as_string().c_str()); + + JSONNode name = root.at("name"); + if (!name.empty()) { + db_set_s(hContact, MODULE, "FirstName", name.at("given_name").as_string().c_str()); + db_set_s(hContact, MODULE, "LastName", name.at("surname").as_string().c_str()); + /*JSONNode display_name = root.at("display_name"); + if (!display_name.empty()) { + CMString tszDisplayName(display_name.as_mstring()); + int pos = tszDisplayName.ReverseFind(' '); + if (pos != -1) { + db_set_ts(hContact, MODULE, "LastName", tszDisplayName.Mid(pos + 1)); + db_set_ts(hContact, MODULE, "FirstName", tszDisplayName.Left(pos)); + } + else { + db_set_ts(hContact, MODULE, "FirstName", tszDisplayName); + db_unset(hContact, MODULE, "LastName"); + } + }*/ } JSONNode country = root.at("country"); @@ -103,7 +112,7 @@ void CDropbox::RequestAccountInfo(void *p) } } - JSONNode quota_info = root.at("quota_info"); + /*JSONNode quota_info = root.at("quota_info"); if (!quota_info.empty()) { ULONG lTotalQuota = quota_info.at("quota").as_int(); ULONG lNormalQuota = quota_info.at("normal").as_int(); @@ -114,13 +123,13 @@ void CDropbox::RequestAccountInfo(void *p) db_set_dw(hContact, MODULE, "TotalQuota", lTotalQuota); db_set_s(hContact, "CList", "StatusMsg", CMStringA(FORMAT, Translate("Free %ld of %ld MB"), (lTotalQuota - lNormalQuota) / (1024 * 1024), lTotalQuota / (1024 * 1024))); - } + }*/ } void CDropbox::DestroyAccessToken() { - DisableAccessTokenRequest request; - NLHR_PTR response(request.Send(hNetlibConnection)); + //DisableAccessTokenRequest request; + //NLHR_PTR response(request.Send(hNetlibConnection)); db_unset(NULL, MODULE, "TokenSecret"); MCONTACT hContact = CDropbox::GetDefaultContact(); @@ -191,7 +200,7 @@ UINT CDropbox::RequestAccessTokenAsync(void *owner, void *param) try { RequestAccountInfo(instance); } - catch (TransferException &ex) { + catch (DropboxException &ex) { Netlib_Logf(instance->hNetlibConnection, "%s: %s", MODULE, ex.what()); return 0; } diff --git a/plugins/Dropbox/src/dropbox.h b/plugins/Dropbox/src/dropbox.h index d9af25ae73..2331ed1922 100644 --- a/plugins/Dropbox/src/dropbox.h +++ b/plugins/Dropbox/src/dropbox.h @@ -84,10 +84,10 @@ private: static void __cdecl RequestAccountInfo(void*); // transfers - void SendFile(const char *path, const char *data, size_t size); - void SendFileChunkedFirst(const char *data, size_t size, char *uploadId, size_t &offset); - void SendFileChunkedNext(const char *data, size_t size, const char *uploadId, size_t &offset); - void SendFileChunkedLast(const char *path, const char *uploadId); + void UploadFile(const char *path, const char *data, size_t size); + void StartUploadSession(const char *data, size_t size, char *sessionId); + void AppendToUploadSession(const char *data, size_t size, const char *sessionId, size_t &offset); + void FinishUploadSession(const char *data, size_t size, const char *sessionId, size_t offset, const char *path); void CreateFolder(const char *encodedPath); @@ -110,8 +110,11 @@ private: static void DisableSrmmButton(MCONTACT hContact); // utils + static CMStringA PreparePath(const char *path); + static CMStringA PreparePath(const TCHAR *path); + static char* HttpStatusToText(HTTP_STATUS status); - static void HandleHttpResponseError(NETLIBHTTPREQUEST *response); + static void HandleJsonResponseError(NETLIBHTTPREQUEST *response); static MEVENT AddEventToDb(MCONTACT hContact, WORD type, DWORD flags, DWORD cbBlob, PBYTE pBlob); diff --git a/plugins/Dropbox/src/dropbox_commands.cpp b/plugins/Dropbox/src/dropbox_commands.cpp index 19b6baeb62..76c373ae80 100644 --- a/plugins/Dropbox/src/dropbox_commands.cpp +++ b/plugins/Dropbox/src/dropbox_commands.cpp @@ -6,7 +6,7 @@ void CDropbox::CommandHelp(void *arg) CMStringA help = (char*)T2Utf(TranslateT("Dropbox supports the following commands:")); help += "\n"; - help += "\"/content [dir]\" \t- "; help += T2Utf(TranslateT("shows all files in folder \"dir\" (\"dir\" can be omitted for root folder)")); + help += "\"/list [dir]\" \t- "; help += T2Utf(TranslateT("shows all files in folder \"path\" (\"path\" is relative from root folder)")); help += "\n"; help += "\"/share \" \t- "; help += T2Utf(TranslateT("returns download link for file or folder with specified path (\"path\" is relative from root folder)")); help += "\n"; @@ -20,13 +20,17 @@ void CDropbox::CommandContent(void *arg) { CommandParam *param = (CommandParam*)arg; - char *path = (char*)param->data; - if (path == NULL) - path = ""; + CMStringA path = PreparePath((char*)param->data); + if (path.IsEmpty()) { + CMStringA error(FORMAT, T2Utf(TranslateT("\"%s\" command has invalid parameter.\nUse \"/help\" for more info.")), "/share"); + ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hProcess, 0); + CallContactService(param->instance->GetDefaultContact(), PSR_MESSAGE, 0, (LPARAM)error.GetBuffer()); + + return; + } ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - ptrA encodedPath(mir_utf8encode(path)); - GetMetadataRequest request(token, encodedPath); + ListFolderRequest request(token, path); NLHR_PTR response(request.Send(param->instance->hNetlibConnection)); if (response == NULL || response->resultCode != HTTP_STATUS_OK) { @@ -41,22 +45,17 @@ void CDropbox::CommandContent(void *arg) } CMStringA message; - bool isDir = root.at("is_dir").as_bool(); - if (!isDir) - message.AppendFormat("\"%s\" %s", encodedPath, T2Utf(TranslateT("is file"))); - else { - JSONNode content = root.at("contents").as_array(); - for (size_t i = 0; i < content.size(); i++) { - JSONNode item = content[i]; - if (item.empty()) { - if (i == 0) - message.AppendFormat("\"%s\" %s", encodedPath, T2Utf(TranslateT("is empty"))); - break; - } - - CMStringA subName(item.at("path").as_string().c_str()); - message.AppendFormat("%s\n", (subName[0] == '/') ? subName.Mid(1) : subName); + JSONNode content = root.at("entries").as_array(); + for (size_t i = 0; i < content.size(); i++) { + JSONNode item = content[i]; + if (item.empty()) { + if (i == 0) + message.AppendFormat("\"%s\" %s", path, T2Utf(TranslateT("is empty"))); + break; } + + CMStringA subName(item.at("path_lower ").as_string().c_str()); + message.AppendFormat("%s\n", (subName[0] == '/') ? subName.Mid(1) : subName); } ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hProcess, 0); @@ -67,8 +66,8 @@ void CDropbox::CommandShare(void *arg) { CommandParam *param = (CommandParam*)arg; - char *path = (char*)param->data; - if (path == NULL) { + CMStringA path = PreparePath((char*)param->data); + if (path.IsEmpty()) { CMStringA error(FORMAT, T2Utf(TranslateT("\"%s\" command has invalid parameter.\nUse \"/help\" for more info.")), "/share"); ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hProcess, 0); CallContactService(param->instance->GetDefaultContact(), PSR_MESSAGE, 0, (LPARAM)error.GetBuffer()); @@ -77,9 +76,8 @@ void CDropbox::CommandShare(void *arg) } ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - ptrA encodedPath(mir_utf8encode(path)); - bool useShortUrl = db_get_b(NULL, MODULE, "UseSortLinks", 1) > 0; - ShareRequest request(token, encodedPath, useShortUrl); + //bool useShortUrl = db_get_b(NULL, MODULE, "UseSortLinks", 1) > 0; + ShareRequest request(token, path); NLHR_PTR response(request.Send(param->instance->hNetlibConnection)); if (response == NULL || response->resultCode != HTTP_STATUS_OK) { @@ -102,8 +100,8 @@ void CDropbox::CommandDelete(void *arg) { CommandParam *param = (CommandParam*)arg; - char *path = (char*)param->data; - if (path == NULL) { + CMStringA path = PreparePath((char*)param->data); + if (path.IsEmpty()) { CMStringA error(FORMAT, T2Utf(TranslateT("\"%s\" command has invalid parameter.\nUse \"/help\" for more info.")), "/delete"); ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hProcess, 0); CallContactService(param->instance->GetDefaultContact(), PSR_MESSAGE, 0, (LPARAM)error.GetBuffer()); @@ -111,23 +109,22 @@ void CDropbox::CommandDelete(void *arg) return; } ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - ptrA encodedPath(mir_utf8encode(path)); - DeleteRequest request(token, encodedPath); + DeleteRequest request(token, path); NLHR_PTR response(request.Send(param->instance->hNetlibConnection)); - if (response == NULL || response->resultCode != HTTP_STATUS_OK) { - ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hProcess, 0); - return; - } + try + { + HandleJsonResponseError(response); - JSONNode root = JSONNode::parse(response->pData); - if (root.empty()) { - ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hProcess, 0); + CMStringA message(FORMAT, "%s %s", path, T2Utf(TranslateT("is deleted"))); + ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hProcess, 0); + CallContactService(param->instance->GetDefaultContact(), PSR_MESSAGE, 0, (LPARAM)message.GetBuffer()); + } + catch (DropboxException &ex) + { + ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hProcess, (LPARAM)ex.what()); return; } - - bool isDeleted = root.at("is_deleted").as_bool(); - CMStringA message(FORMAT, "%s %s", path, !isDeleted ? T2Utf(TranslateT("is not deleted")) : T2Utf(TranslateT("is deleted"))); - ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, param->hProcess, 0); - CallContactService(param->instance->GetDefaultContact(), PSR_MESSAGE, 0, (LPARAM)message.GetBuffer()); + + ProtoBroadcastAck(MODULE, param->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, param->hProcess, 0); } \ No newline at end of file diff --git a/plugins/Dropbox/src/dropbox_options.cpp b/plugins/Dropbox/src/dropbox_options.cpp index 7612a35ba5..2ae67aecb6 100644 --- a/plugins/Dropbox/src/dropbox_options.cpp +++ b/plugins/Dropbox/src/dropbox_options.cpp @@ -2,7 +2,7 @@ CDropboxOptionsMain::CDropboxOptionsMain(CDropbox *instance, int idDialog) : CDropboxDlgBase(instance, idDialog), - m_auth(this, IDC_GETAUTH, DROPBOX_WWW_URL DROPBOX_API_VER "/oauth2/authorize?response_type=code&client_id=" DROPBOX_APP_KEY), + m_auth(this, IDC_GETAUTH, DROPBOX_WWW_URL "/oauth2/authorize?response_type=code&client_id=" DROPBOX_APP_KEY), m_requestCode(this, IDC_REQUEST_CODE), m_authorize(this, IDC_AUTHORIZE), m_authStatus(this, IDC_AUTH_STATUS), m_useShortUrl(this, IDC_USE_SHORT_LINKS), m_urlAutoSend(this, IDC_URL_AUTOSEND), m_urlPasteToMessageInputArea(this, IDC_URL_COPYTOMIA), m_urlCopyToClipboard(this, IDC_URL_COPYTOCB) diff --git a/plugins/Dropbox/src/dropbox_services.cpp b/plugins/Dropbox/src/dropbox_services.cpp index d4cdd244c7..cece2a4bc3 100644 --- a/plugins/Dropbox/src/dropbox_services.cpp +++ b/plugins/Dropbox/src/dropbox_services.cpp @@ -153,7 +153,7 @@ INT_PTR CDropbox::ProtoSendMessage(WPARAM, LPARAM lParam) static commands[] = { { "help", &CDropbox::CommandHelp }, - { "content", &CDropbox::CommandContent }, + { "list", &CDropbox::CommandContent }, { "share", &CDropbox::CommandShare }, { "delete", &CDropbox::CommandDelete } }; diff --git a/plugins/Dropbox/src/dropbox_transfers.cpp b/plugins/Dropbox/src/dropbox_transfers.cpp index 09fec2daf8..d46b0871ed 100644 --- a/plugins/Dropbox/src/dropbox_transfers.cpp +++ b/plugins/Dropbox/src/dropbox_transfers.cpp @@ -1,40 +1,38 @@ #include "stdafx.h" -void CDropbox::SendFile(const char *path, const char *data, size_t size) +void CDropbox::UploadFile(const char *path, const char *data, size_t size) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); ptrA encodedPath(mir_utf8encode(path)); UploadFileRequest request(token, encodedPath, data, size); NLHR_PTR response(request.Send(hNetlibConnection)); - HandleHttpResponseError(response); + + HandleJsonResponseError(response); } -void CDropbox::SendFileChunkedFirst(const char *data, size_t size, char *uploadId, size_t &offset) +void CDropbox::StartUploadSession(const char *data, size_t size, char *sessionId) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - UploadFileChunkRequest request(token, data, size); + StartUploadSessionRequest request(token, data, size); NLHR_PTR response(request.Send(hNetlibConnection)); - HandleHttpResponseError(response); + HandleJsonResponseError(response); JSONNode root = JSONNode::parse(response->pData); if (root.empty()) return; - JSONNode node = root.at("upload_id"); - mir_strcpy(uploadId, node.as_string().c_str()); - - node = root.at("offset"); - offset = node.as_int(); + JSONNode node = root.at("session_id"); + mir_strcpy(sessionId, node.as_string().c_str()); } -void CDropbox::SendFileChunkedNext(const char *data, size_t size, const char *uploadId, size_t &offset) +void CDropbox::AppendToUploadSession(const char *data, size_t size, const char *sessionId, size_t &offset) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - UploadFileChunkRequest request(token, uploadId, offset, data, size); + AppendToUploadSessionRequest request(token, sessionId, offset, data, size); NLHR_PTR response(request.Send(hNetlibConnection)); - HandleHttpResponseError(response); + HandleJsonResponseError(response); JSONNode root = JSONNode::parse(response->pData); if (root.empty()) @@ -43,12 +41,13 @@ void CDropbox::SendFileChunkedNext(const char *data, size_t size, const char *up offset = root.at("offset").as_int(); } -void CDropbox::SendFileChunkedLast(const char *path, const char *uploadId) +void CDropbox::FinishUploadSession(const char *data, size_t size, const char *sessionId, size_t offset, const char *path) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - UploadFileChunkRequest request(token, uploadId, path); + FinishUploadSessionRequest request(token, sessionId, offset, path, data, size); NLHR_PTR response(request.Send(hNetlibConnection)); - HandleHttpResponseError(response); + + HandleJsonResponseError(response); } void CDropbox::CreateFolder(const char *path) @@ -61,17 +60,17 @@ void CDropbox::CreateFolder(const char *path) if (response->resultCode == HTTP_STATUS_FORBIDDEN) return; - HandleHttpResponseError(response); + HandleJsonResponseError(response); } void CDropbox::CreateDownloadUrl(const char *path, char *url) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); - bool useShortUrl = db_get_b(NULL, MODULE, "UseSortLinks", 1) > 0; - ShareRequest request(token, path, useShortUrl); + //bool useShortUrl = db_get_b(NULL, MODULE, "UseSortLinks", 1) > 0; + ShareRequest request(token, path); NLHR_PTR response(request.Send(hNetlibConnection)); - HandleHttpResponseError(response); + HandleJsonResponseError(response); JSONNode root = JSONNode::parse(response->pData); if (root.empty()) @@ -92,14 +91,13 @@ UINT CDropbox::SendFilesAsync(void *owner, void *arg) if (ftp->ptszFolders) { for (int i = 0; ftp->ptszFolders[i]; i++) { if (ftp->isTerminated) - throw TransferException("Transfer was terminated"); + throw DropboxException("Transfer was terminated"); - ptrA utf8_folderName(mir_utf8encodeW(ftp->ptszFolders[i])); - - instance->CreateFolder(utf8_folderName); - if (!strchr(utf8_folderName, '\\')) { + CMStringA path = PreparePath(ftp->ptszFolders[i]); + instance->CreateFolder(path); + if (!strchr(path, '\\')) { char url[MAX_PATH]; - instance->CreateDownloadUrl(utf8_folderName, url); + instance->CreateDownloadUrl(path, url); ftp->AddUrl(url); } } @@ -107,11 +105,11 @@ UINT CDropbox::SendFilesAsync(void *owner, void *arg) for (int i = 0; ftp->pfts.ptszFiles[i]; i++) { if (ftp->isTerminated) - throw TransferException("Transfer was terminated"); + throw DropboxException("Transfer was terminated"); FILE *hFile = _tfopen(ftp->pfts.ptszFiles[i], _T("rb")); if (hFile == NULL) - throw TransferException("Unable to open file"); + throw DropboxException("Unable to open file"); const TCHAR *fileName = NULL; if (!ftp->relativePathStart) @@ -129,7 +127,7 @@ UINT CDropbox::SendFilesAsync(void *owner, void *arg) ftp->pfts.tszCurrentFile = _tcsrchr(ftp->pfts.ptszFiles[i], '\\') + 1; size_t offset = 0; - char uploadId[32]; + char sessionId[32]; int chunkSize = DROPBOX_FILE_CHUNK_SIZE / 4; if (fileSize < 1024 * 1024) chunkSize = DROPBOX_FILE_CHUNK_SIZE / 20; @@ -140,22 +138,24 @@ UINT CDropbox::SendFilesAsync(void *owner, void *arg) while (!feof(hFile) && fileSize != offset) { try { if (ferror(hFile)) - throw TransferException("Error while file sending"); + throw DropboxException("Error while file sending"); if (ftp->isTerminated) - throw TransferException("Transfer was terminated"); + throw DropboxException("Transfer was terminated"); size_t size = fread(data, sizeof(char), chunkSize, hFile); - if (offset == 0) - instance->SendFileChunkedFirst(data, size, uploadId, offset); + if (offset == 0) { + instance->StartUploadSession(data, size, sessionId); + offset += size; + } else - instance->SendFileChunkedNext(data, size, uploadId, offset); + instance->AppendToUploadSession(data, size, sessionId, offset); ftp->pfts.currentFileProgress += size; ftp->pfts.totalProgress += size; } - catch (TransferException&) { + catch (DropboxException&) { mir_free(data); fclose(hFile); throw; @@ -167,15 +167,14 @@ UINT CDropbox::SendFilesAsync(void *owner, void *arg) fclose(hFile); if (ftp->pfts.currentFileProgress < ftp->pfts.currentFileSize) - throw TransferException("Transfer was terminated"); - - ptrA utf8_fileName(mir_utf8encodeW(fileName)); + throw DropboxException("Transfer was terminated"); - instance->SendFileChunkedLast(utf8_fileName, uploadId); + CMStringA path = PreparePath(fileName); + instance->FinishUploadSession(0, 0, sessionId, offset, path); if (!_tcschr(fileName, L'\\')) { char url[MAX_PATH]; - instance->CreateDownloadUrl(utf8_fileName, url); + instance->CreateDownloadUrl(path, url); ftp->AddUrl(url); } @@ -185,7 +184,7 @@ UINT CDropbox::SendFilesAsync(void *owner, void *arg) ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ftp->hProcess, 0); } } - catch (TransferException &ex) { + catch (DropboxException &ex) { Netlib_Logf(instance->hNetlibConnection, "%s: %s", MODULE, ex.what()); ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ftp->hProcess, 0); return ACKRESULT_FAILED; diff --git a/plugins/Dropbox/src/dropbox_utils.cpp b/plugins/Dropbox/src/dropbox_utils.cpp index aee70273eb..f9e726fe92 100644 --- a/plugins/Dropbox/src/dropbox_utils.cpp +++ b/plugins/Dropbox/src/dropbox_utils.cpp @@ -1,5 +1,21 @@ #include "stdafx.h" +CMStringA CDropbox::PreparePath(const char *path) +{ + CMStringA result("/"); + result.Append(path); + result.Replace("\\", "/"); + return result; +} + +CMStringA CDropbox::PreparePath(const TCHAR *path) +{ + CMStringA result("/"); + result.Append(ptrA(mir_utf8encodeW(path))); + result.Replace("\\", "/"); + return result; +} + char* CDropbox::HttpStatusToText(HTTP_STATUS status) { switch (status) { @@ -28,13 +44,23 @@ char* CDropbox::HttpStatusToText(HTTP_STATUS status) return "Unknown error"; } -void CDropbox::HandleHttpResponseError(NETLIBHTTPREQUEST *response) +void CDropbox::HandleJsonResponseError(NETLIBHTTPREQUEST *response) { if (response == NULL) - throw TransferException(HttpStatusToText(HTTP_STATUS_ERROR)); + throw DropboxException(HttpStatusToText(HTTP_STATUS_ERROR)); + + JSONNode root = JSONNode::parse(response->pData); + if (root.empty()) { + if (response->dataLength) + throw DropboxException(response->pData); + throw DropboxException(HttpStatusToText((HTTP_STATUS)response->resultCode)); + } + + JSONNode error = root.at("error_summary"); + if (error.empty()) + return; - if (response->resultCode != HTTP_STATUS_OK) - throw TransferException(HttpStatusToText((HTTP_STATUS)response->resultCode)); + throw DropboxException(error.as_string().c_str()); } MEVENT CDropbox::AddEventToDb(MCONTACT hContact, WORD type, DWORD flags, DWORD cbBlob, PBYTE pBlob) diff --git a/plugins/Dropbox/src/file_transfer.h b/plugins/Dropbox/src/file_transfer.h index 1a86ec7588..0c5e592294 100644 --- a/plugins/Dropbox/src/file_transfer.h +++ b/plugins/Dropbox/src/file_transfer.h @@ -1,22 +1,6 @@ #ifndef _FILE_TRANSFER_H_ #define _FILE_TRANSFER_H_ -class TransferException -{ - CMStringA message; - -public: - TransferException(const char *message) : - message(message) - { - } - - const char* what() const throw() - { - return message.c_str(); - } -}; - struct FileTransferParam { HANDLE hProcess; diff --git a/plugins/Dropbox/src/stdafx.h b/plugins/Dropbox/src/stdafx.h index ae52bb9fb4..e8117bd649 100644 --- a/plugins/Dropbox/src/stdafx.h +++ b/plugins/Dropbox/src/stdafx.h @@ -36,15 +36,31 @@ class CDropbox; -#define DROPBOX_API_VER "1" -#define DROPBOX_API_ROOT "sandbox" -#define DROPBOX_WWW_URL "https://www.dropbox.com/" -#define DROPBOX_API_URL "https://api.dropbox.com/" DROPBOX_API_VER -#define DROPBOX_APICONTENT_URL "https://api-content.dropbox.com/" DROPBOX_API_VER +#define DROPBOX_API_VER "2" +#define DROPBOX_WWW_URL "https://www.dropbox.com/1" +#define DROPBOX_API_OLD "https://api.dropboxapi.com/1" +#define DROPBOX_API_RPC "https://api.dropboxapi.com/" DROPBOX_API_VER +#define DROPBOX_API_CU "https://content.dropboxapi.com/" DROPBOX_API_VER #define DROPBOX_APP_KEY "fa8du7gkf2q8xzg" #include "..\..\..\miranda-private-keys\Dropbox\secret_key.h" +class DropboxException +{ + CMStringA message; + +public: + DropboxException(const char *message) : + message(message) + { + } + + const char* what() const throw() + { + return message.c_str(); + } +}; + #include "dropbox_dialogs.h" #include "dropbox_options.h" #include "http_request.h" diff --git a/plugins/Dropbox/src/version.h b/plugins/Dropbox/src/version.h index 9386d394a4..38b5566b58 100644 --- a/plugins/Dropbox/src/version.h +++ b/plugins/Dropbox/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 12 -#define __RELEASE_NUM 0 -#define __BUILD_NUM 8 +#define __RELEASE_NUM 1 +#define __BUILD_NUM 0 #include -- cgit v1.2.3