From fc46c19a61d26fb610d173bb8fc5420eea966caa Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Wed, 19 Feb 2014 19:07:45 +0000 Subject: Dropbox: - global object replaced by singleton - added ability to upload folders git-svn-id: http://svn.miranda-ng.org/main/trunk@8183 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Dropbox/Dropbox_11.vcxproj | 1 + plugins/Dropbox/Dropbox_11.vcxproj.filters | 3 + plugins/Dropbox/src/common.h | 5 -- plugins/Dropbox/src/dropbox.cpp | 25 ++++-- plugins/Dropbox/src/dropbox.h | 53 +++++++++---- plugins/Dropbox/src/dropbox_events.cpp | 2 +- plugins/Dropbox/src/dropbox_services.cpp | 58 +++++++++----- plugins/Dropbox/src/dropbox_transfers.cpp | 122 ++++++++++++++++++----------- plugins/Dropbox/src/http_request.h | 25 +----- plugins/Dropbox/src/main.cpp | 8 +- plugins/Dropbox/src/singleton.h | 29 +++++++ 11 files changed, 210 insertions(+), 121 deletions(-) create mode 100644 plugins/Dropbox/src/singleton.h diff --git a/plugins/Dropbox/Dropbox_11.vcxproj b/plugins/Dropbox/Dropbox_11.vcxproj index 8f52177702..86a93e74c5 100644 --- a/plugins/Dropbox/Dropbox_11.vcxproj +++ b/plugins/Dropbox/Dropbox_11.vcxproj @@ -190,6 +190,7 @@ + diff --git a/plugins/Dropbox/Dropbox_11.vcxproj.filters b/plugins/Dropbox/Dropbox_11.vcxproj.filters index d5d53e93d6..1393a38512 100644 --- a/plugins/Dropbox/Dropbox_11.vcxproj.filters +++ b/plugins/Dropbox/Dropbox_11.vcxproj.filters @@ -45,6 +45,9 @@ Header Files + + Header Files + diff --git a/plugins/Dropbox/src/common.h b/plugins/Dropbox/src/common.h index d3b14a3e15..89afef0c2c 100644 --- a/plugins/Dropbox/src/common.h +++ b/plugins/Dropbox/src/common.h @@ -29,11 +29,6 @@ #define MODULE "Dropbox" -class CDropbox; - extern HINSTANCE g_hInstance; -extern CDropbox *g_dropbox; - -HANDLE CreateProtoServiceFunctionObj(const char *szModule, const char *szService, MIRANDASERVICEOBJ serviceProc, void* obj); #endif //_COMMON_H_ \ No newline at end of file diff --git a/plugins/Dropbox/src/dropbox.cpp b/plugins/Dropbox/src/dropbox.cpp index fa2d5cbc86..ed705d6dea 100644 --- a/plugins/Dropbox/src/dropbox.cpp +++ b/plugins/Dropbox/src/dropbox.cpp @@ -1,6 +1,6 @@ #include "dropbox.h" -CDropbox::CDropbox() +void CDropbox::Init() { PROTOCOLDESCRIPTOR pd = { PROTOCOLDESCRIPTOR_V3_SIZE }; pd.szName = MODULE; @@ -28,7 +28,7 @@ bool CDropbox::HasAccessToken() return db_get_sa(NULL, MODULE, "TokenSecret") != NULL; } -void CDropbox::RequestAcceessToken() +void CDropbox::RequestAcceessToken(MCONTACT hContact) { ShellExecuteA(NULL, "open", DROPBOX_WWW_URL DROPBOX_API_VER "/oauth2/authorize?response_type=code&client_id=" DROPBOX_API_KEY, NULL, NULL, SW_SHOWDEFAULT); @@ -71,7 +71,6 @@ void CDropbox::RequestAcceessToken() ptrA access_token = ptrA(mir_u2a(json_as_string(node))); db_set_s(NULL, MODULE, "TokenSecret", access_token); - MCONTACT hContact = GetDefaultContact(); if (hContact) { node = json_get(root, "uid"); @@ -107,20 +106,34 @@ void CDropbox::RequestAcceessToken() } } -void CDropbox::DestroyAcceessToken() +void CDropbox::DestroyAcceessToken(MCONTACT hContact) { HttpRequest *request = new HttpRequest(hNetlibUser, REQUEST_POST, DROPBOX_API_URL "/disable_access_token"); - //request->SendAsync(&CDropboxProto::AsyncFunc); NETLIBHTTPREQUEST *response = request->Send(); delete request; mir_free(response); db_unset(NULL, MODULE, "TokenSecret"); - MCONTACT hContact = GetDefaultContact(); if (hContact) { if (db_get_w(hContact, MODULE, "Status", ID_STATUS_ONLINE) == ID_STATUS_ONLINE) db_set_w(hContact, MODULE, "Status", ID_STATUS_OFFLINE); } +} + +void CDropbox::RequeriedAccessAsync(void *arg) +{ + MCONTACT hContact = (MCONTACT)arg; + + if (hContact && MessageBox( + NULL, + TranslateT("Are you sure you want to requeried access?"), + TranslateT("Requeried access"), + MB_YESNO | MB_ICONQUESTION) == IDYES) + { + if (HasAccessToken()) + Singleton::GetInstance()->DestroyAcceessToken(hContact); + Singleton::GetInstance()->RequestAcceessToken(hContact); + } } \ No newline at end of file diff --git a/plugins/Dropbox/src/dropbox.h b/plugins/Dropbox/src/dropbox.h index ba400d90d0..0789f508c7 100644 --- a/plugins/Dropbox/src/dropbox.h +++ b/plugins/Dropbox/src/dropbox.h @@ -1,7 +1,7 @@ -#ifndef _Dropbox_PROTO_H_ -#define _Dropbox_PROTO_H_ +#ifndef _DROPBOX_PROTO_H_ +#define _DROPBOX_PROTO_H_ -//#include "common.h" +#include "singleton.h" #include "http_request.h" #define DROPBOX_API_VER "1" @@ -18,7 +18,6 @@ enum { CMI_API_ACCESS_REQUERIED, - CMI_URL_OPEN_ROOT, CMI_MAX // this item shall be the last one }; @@ -27,36 +26,56 @@ struct FileTransferParam HANDLE hProcess; PROTOFILETRANSFERSTATUS pfts; - FileTransferParam() + int totalFolders; + char **pszFolders; + int relativePathStart; + + FileTransferParam() { + totalFolders = 0; + pszFolders = NULL; + relativePathStart = 0; + pfts.cbSize = sizeof(this->pfts); pfts.flags = PFTS_UTF; pfts.currentFileNumber = 0; pfts.currentFileProgress = 0; pfts.currentFileSize = 0; - pfts.currentFileTime = 0; pfts.totalBytes = 0; pfts.totalFiles = 0; pfts.totalProgress = 0; + pfts.pszFiles = NULL; pfts.tszWorkingDir = NULL; pfts.wszCurrentFile = NULL; } - ~FileTransferParam() + ~FileTransferParam() { - for (int i = 0; pfts.pszFiles[pfts.totalFiles]; i++) + /*if (pfts.pszFiles) { - delete pfts.pszFiles[i]; + for (int i = 0; pfts.pszFiles[i]; i++) + { + if (pfts.pszFiles[i]) delete pfts.pszFiles[i]; + } + delete pfts.pszFiles; } - delete pfts.pszFiles; + + if (pszFolders) + { + for (int i = 0; pszFolders[i]; i++) + { + if (pszFolders[i]) delete pszFolders[i]; + } + delete pszFolders; + }*/ } }; class CDropbox { public: - CDropbox(); - ~CDropbox() { } + void Init(); + void Uninit() { }; private: HANDLE hNetlibUser; @@ -78,8 +97,10 @@ private: // access token static bool HasAccessToken(); - void RequestAcceessToken(); - void DestroyAcceessToken(); + void RequestAcceessToken(MCONTACT hContact); + void DestroyAcceessToken(MCONTACT hContact); + + static void RequeriedAccessAsync(void *arg); // transrers HttpRequest *CreateFileSendChunkedRequest(const char *data, int length); @@ -87,6 +108,8 @@ private: void SendFileChunkedNext(const char *data, int length, const char *uploadId, int &offset); void SendFileChunkedLast(const char *fileName, const char *uploadId, MCONTACT hContact); + void CreateFolder(const char *folderName); + static void _cdecl SendFileAsync(void *arg); // contacts @@ -107,4 +130,4 @@ private: void ShowNotification(const wchar_t *message, int flags = 0, MCONTACT hContact = NULL); }; -#endif //_Dropbox_PROTO_H_ \ No newline at end of file +#endif //_DROPBOX_PROTO_H_ \ No newline at end of file diff --git a/plugins/Dropbox/src/dropbox_events.cpp b/plugins/Dropbox/src/dropbox_events.cpp index 83ee861712..62684d66d5 100644 --- a/plugins/Dropbox/src/dropbox_events.cpp +++ b/plugins/Dropbox/src/dropbox_events.cpp @@ -8,7 +8,7 @@ int CDropbox::OnModulesLoaded(WPARAM wParam, LPARAM lParam) nlu.szSettingsModule = MODULE; nlu.ptszDescriptiveName = L"Dropbox"; - g_dropbox->hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + Singleton::GetInstance()->hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); MCONTACT hContact = GetDefaultContact(); if (!hContact) diff --git a/plugins/Dropbox/src/dropbox_services.cpp b/plugins/Dropbox/src/dropbox_services.cpp index b61f9c54ad..0389021920 100644 --- a/plugins/Dropbox/src/dropbox_services.cpp +++ b/plugins/Dropbox/src/dropbox_services.cpp @@ -32,31 +32,53 @@ INT_PTR CDropbox::SendFile(WPARAM wParam, LPARAM lParam) for (int i = 0; files[i]; i++) { if (PathIsDirectoryA(files[i])) - continue; - ftp->pfts.totalFiles++; + ftp->totalFolders++; + else + ftp->pfts.totalFiles++; } + ftp->pszFolders = new char*[ftp->totalFolders + 1]; + ftp->pszFolders[ftp->totalFolders] = NULL; + ftp->pfts.pszFiles = new char*[ftp->pfts.totalFiles + 1]; ftp->pfts.pszFiles[ftp->pfts.totalFiles] = NULL; - for (int i = 0, j = 0; files[i]; i++) + + for (int i = 0, j = 0, k = 0; files[i]; i++) { if (PathIsDirectoryA(files[i])) - continue; + { + if (!ftp->relativePathStart) + { + char *rootFolder = files[j]; + char *relativePath = strrchr(rootFolder, '\\') + 1; + ftp->relativePathStart = relativePath - rootFolder; + } - ftp->pfts.pszFiles[j] = mir_strdup(files[i]); + ftp->pszFolders[j] = mir_strdup(&files[i][ftp->relativePathStart]); - FILE *file = fopen(files[j], "rb"); - if (file != NULL) - { - fseek(file, 0, SEEK_END); - ftp->pfts.totalBytes += ftell(file); - fseek(file, 0, SEEK_SET); - fclose(file); + j++; } + else + { + //if (!relativePathStart) + ftp->pfts.pszFiles[k] = mir_strdup(files[i]); + /*else + { + ftp->pfts.pszFiles[k] = mir_strdup(&files[i][relativePathStart]); + }*/ - j++; + FILE *file = fopen(files[i], "rb"); + if (file != NULL) + { + fseek(file, 0, SEEK_END); + ftp->pfts.totalBytes += ftell(file); + fseek(file, 0, SEEK_SET); + fclose(file); + } + k++; + } } - ULONG fileId = InterlockedIncrement(&g_dropbox->hFileProcess); + ULONG fileId = InterlockedIncrement(&Singleton::GetInstance()->hFileProcess); ftp->hProcess = (HANDLE)fileId; mir_forkthread(CDropbox::SendFileAsync, ftp); @@ -71,13 +93,7 @@ INT_PTR CDropbox::SendMessage( WPARAM wParam, LPARAM lParam) INT_PTR CDropbox::RequeriedApiAccess(WPARAM wParam, LPARAM lParam) { - int result = MessageBox(NULL, TranslateT("Are you sure you want to requeried access?"), TranslateT("Requeried access"), MB_YESNO | MB_ICONQUESTION); - if (result == IDYES) - { - if (HasAccessToken()) - g_dropbox->DestroyAcceessToken(); - g_dropbox->RequestAcceessToken(); - } + mir_forkthread(CDropbox::RequeriedAccessAsync, (void*)wParam); return 0; } \ No newline at end of file diff --git a/plugins/Dropbox/src/dropbox_transfers.cpp b/plugins/Dropbox/src/dropbox_transfers.cpp index 550e6b7e64..6a0d885894 100644 --- a/plugins/Dropbox/src/dropbox_transfers.cpp +++ b/plugins/Dropbox/src/dropbox_transfers.cpp @@ -76,14 +76,23 @@ void CDropbox::SendFileChunkedNext(const char *data, int length, const char *upl void CDropbox::SendFileChunkedLast(const char *fileName, const char *uploadId, MCONTACT hContact) { - char url[MAX_PATH]; + /*char url[MAX_PATH]; mir_snprintf( url, SIZEOF(url), + "%s/commit_chunked_upload/%s/%s", + DROPBOX_APICONTENT_URL, + DROPBOX_API_ROOT, + fileName);*/ + + CMStringA url; + url.AppendFormat( "%s/commit_chunked_upload/%s/%s", DROPBOX_APICONTENT_URL, DROPBOX_API_ROOT, fileName); + url.Replace('\\', '/'); + HttpRequest *request = new HttpRequest(hNetlibUser, REQUEST_POST, url); request->AddParameter("upload_id", uploadId); @@ -93,55 +102,76 @@ void CDropbox::SendFileChunkedLast(const char *fileName, const char *uploadId, M delete request; - if (response && response->resultCode == HttpStatus::OK) + if (response) { - mir_snprintf( - url, - SIZEOF(url), - "%s/shares/%s/%s", - DROPBOX_API_URL, - DROPBOX_API_ROOT, - fileName); + if (response->resultCode == HttpStatus::OK) + { + url.Replace(DROPBOX_APICONTENT_URL, DROPBOX_API_URL); + url.Replace("commit_chunked_upload", "shares"); - request = new HttpRequest(hNetlibUser, REQUEST_POST, url); - request->AddParameter("access_token", db_get_sa(NULL, MODULE, "TokenSecret")); + request = new HttpRequest(hNetlibUser, REQUEST_POST, url); + request->AddParameter("access_token", db_get_sa(NULL, MODULE, "TokenSecret")); - mir_free(response); + mir_free(response); - response = request->Send(); + response = request->Send(); - if (response) - { - if (response->resultCode == HttpStatus::OK) + if (response) { - JSONNODE *root = json_parse(response->pData); - if (root != NULL) + if (response->resultCode == HttpStatus::OK) { - JSONNODE *node = json_get(root, "url"); - char message[1024]; - mir_snprintf( - message, - SIZEOF(message), - Translate("Link to download file \"%s\": %s"), - fileName, - mir_utf8encodeW(json_as_string(node))); - - DBEVENTINFO dbei = { sizeof(dbei) }; - dbei.szModule = MODULE; - dbei.timestamp = time(NULL); - dbei.eventType = EVENTTYPE_MESSAGE; - dbei.cbBlob = strlen(message); - dbei.pBlob = (PBYTE)mir_strdup(message); - dbei.flags = DBEF_UTF; - ::db_event_add(hContact, &dbei); - - delete node; - delete root; + JSONNODE *root = json_parse(response->pData); + if (root != NULL) + { + JSONNODE *node = json_get(root, "url"); + char message[1024]; + mir_snprintf( + message, + SIZEOF(message), + Translate("Link to download file \"%s\": %s"), + fileName, + mir_utf8encodeW(json_as_string(node))); + + DBEVENTINFO dbei = { sizeof(dbei) }; + dbei.szModule = MODULE; + dbei.timestamp = time(NULL); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = strlen(message); + dbei.pBlob = (PBYTE)mir_strdup(message); + dbei.flags = DBEF_UTF; + ::db_event_add(hContact, &dbei); + + delete node; + delete root; + } } - } - mir_free(response); + mir_free(response); + } } + else + mir_free(response); + } +} + +void CDropbox::CreateFolder(const char *folderName) +{ + HttpRequest *request = new HttpRequest(hNetlibUser, REQUEST_POST, DROPBOX_API_URL "/fileops/create_folder"); + request->AddParameter("root", DROPBOX_API_ROOT); + request->AddParameter("path", folderName); + request->AddParameter("access_token", db_get_sa(NULL, MODULE, "TokenSecret")); + + NETLIBHTTPREQUEST *response = request->Send(); + + delete request; + + if (response) + { + /*if (response->resultCode == HttpStatus::OK) + { + }*/ + + mir_free(response); } } @@ -151,6 +181,9 @@ void _cdecl CDropbox::SendFileAsync(void *arg) ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ftp->hProcess, 0); + for (int i = 0; ftp->pszFolders[i]; i++) + Singleton::GetInstance()->CreateFolder(ftp->pszFolders[i]); + for (int i = 0; ftp->pfts.pszFiles[i]; i++) { FILE *file = fopen(ftp->pfts.pszFiles[i], "rb"); @@ -159,7 +192,8 @@ void _cdecl CDropbox::SendFileAsync(void *arg) int offset = 0; char *uploadId = new char[32]; - const char *fileName = strrchr(ftp->pfts.pszFiles[i], '\\') + 1; + //const char *fileName = strrchr(ftp->pfts.pszFiles[i], '\\') + 1; + const char *fileName = &ftp->pfts.pszFiles[i][ftp->relativePathStart]; fseek(file, 0, SEEK_END); DWORD fileSize = ftell(file); @@ -184,9 +218,9 @@ void _cdecl CDropbox::SendFileAsync(void *arg) size_t count = fread(data, sizeof(char), chunkSize, file); if (!offset) - g_dropbox->SendFileChunkedFirst(data, count, uploadId, offset); + Singleton::GetInstance()->SendFileChunkedFirst(data, count, uploadId, offset); else - g_dropbox->SendFileChunkedNext(data, count, uploadId, offset); + Singleton::GetInstance()->SendFileChunkedNext(data, count, uploadId, offset); ftp->pfts.currentFileProgress += count; ftp->pfts.totalProgress += count; @@ -196,7 +230,7 @@ void _cdecl CDropbox::SendFileAsync(void *arg) fclose(file); - g_dropbox->SendFileChunkedLast(fileName, uploadId, ftp->pfts.hContact); + Singleton::GetInstance()->SendFileChunkedLast(fileName, uploadId, ftp->pfts.hContact); ftp->pfts.currentFileProgress = ftp->pfts.currentFileSize; if (i < ftp->pfts.totalFiles - 1) diff --git a/plugins/Dropbox/src/http_request.h b/plugins/Dropbox/src/http_request.h index b17ef16b58..43b1b311ec 100644 --- a/plugins/Dropbox/src/http_request.h +++ b/plugins/Dropbox/src/http_request.h @@ -43,7 +43,7 @@ public: void AddParameter(LPCSTR szName, LPCSTR szValue) { - if(m_szUrl.Find('?') == -1) + if (m_szUrl.Find('?') == -1) m_szUrl.AppendFormat("?%s=%s", szName, szValue); else m_szUrl.AppendFormat("&%s=%s", szName, szValue); @@ -51,7 +51,7 @@ public: void AddParameter(LPCSTR szName, int value) { - if(m_szUrl.Find('?') == -1) + if (m_szUrl.Find('?') == -1) m_szUrl.AppendFormat("?%s=%i", szName, value); else m_szUrl.AppendFormat("&%s=%i", szName, value); @@ -63,30 +63,9 @@ public: return (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)this); } - //void SendAsync(typename CBaseProto::AsyncHttpRequest callback) - //{ - // szUrl = m_szUrl.GetBuffer(); - // AsyncParam param = { this, proto, callback }; - // /*HANDLE hThread = */mir_forkthread(SendAsync, ¶m); - // //WaitForSingleObject(hThread, INFINITE); - //} - private: - CMStringA m_szUrl; HANDLE m_hNetlibUser; - - /*static void SendAsync(void *arg) - { - AsyncParam *param = (AsyncParam*)arg; - NETLIBHTTPREQUEST* response = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)param->m_proto->m_hNetlibUser, (LPARAM)param->m_request); - - CBaseProto *proto = param->m_proto; - AsyncRequestCallback callback = param->m_callback; - proto->*callback(response); - - delete response; - }*/ }; #endif //_HTTP_REQUEST_H_ \ No newline at end of file diff --git a/plugins/Dropbox/src/main.cpp b/plugins/Dropbox/src/main.cpp index da1ccca07f..c5bfbd358a 100644 --- a/plugins/Dropbox/src/main.cpp +++ b/plugins/Dropbox/src/main.cpp @@ -1,9 +1,7 @@ -//#include "common.h" #include "dropbox.h" int hLangpack; HINSTANCE g_hInstance; -CDropbox *g_dropbox; PLUGININFOEX pluginInfo = { @@ -33,20 +31,18 @@ extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD miranda return &pluginInfo; } -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; - extern "C" int __declspec(dllexport) Load(void) { mir_getLP(&pluginInfo); - g_dropbox = new CDropbox(); + Singleton::GetInstance()->Init(); return 0; } extern "C" int __declspec(dllexport) Unload(void) { - delete g_dropbox; + Singleton::GetInstance()->Uninit(); return 0; } \ No newline at end of file diff --git a/plugins/Dropbox/src/singleton.h b/plugins/Dropbox/src/singleton.h new file mode 100644 index 0000000000..432e2ed7f0 --- /dev/null +++ b/plugins/Dropbox/src/singleton.h @@ -0,0 +1,29 @@ +#ifndef _SINGLETON_H_ +#define _SINGLETON_H_ + +template +class Singleton +{ +public: + static T *GetInstance() + { + if (!instance) + instance = new T; + return instance; + } + +private: + static T* instance; + + Singleton(); + Singleton(Singleton const&); + + ~Singleton(); + + Singleton &operator=(Singleton const&); +}; + +template T *Singleton::instance = 0; + + +#endif //_SINGLETON_H_ \ No newline at end of file -- cgit v1.2.3