#include "stdafx.h" void CDropbox::SendFile(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); mir_ptr response(request.Send(hNetlibConnection)); HandleHttpResponseError(response); } void CDropbox::SendFileChunkedFirst(const char *data, size_t size, char *uploadId, size_t &offset) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); UploadFileChunkRequest request(token, data, size); mir_ptr response(request.Send(hNetlibConnection)); HandleHttpResponseError(response); JSONROOT root(response->pData); if (root) { JSONNODE *node = json_get(root, "upload_id"); mir_strcpy(uploadId, mir_u2a(json_as_string(node))); node = json_get(root, "offset"); offset = json_as_int(node); } } void CDropbox::SendFileChunkedNext(const char *data, size_t size, const char *uploadId, size_t &offset) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); UploadFileChunkRequest request(token, uploadId, offset, data, size); mir_ptr response(request.Send(hNetlibConnection)); HandleHttpResponseError(response); JSONROOT root(response->pData); if (root) { JSONNODE *node = json_get(root, "offset"); offset = json_as_int(node); } } void CDropbox::SendFileChunkedLast(const char *path, const char *uploadId) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); ptrA encodedPath(mir_utf8encode(path)); UploadFileChunkRequest request(token, uploadId, (char*)encodedPath); mir_ptr response(request.Send(hNetlibConnection)); HandleHttpResponseError(response); } void CDropbox::CreateFolder(const char *path) { ptrA token(db_get_sa(NULL, MODULE, "TokenSecret")); ptrA encodedPath(mir_utf8encode(path)); CreateFolderRequest request(token, encodedPath); mir_ptr response(request.Send(hNetlibConnection)); // forder exists on server if (response->resultCode == HTTP_STATUS_FORBIDDEN) return; HandleHttpResponseError(response); } void CDropbox::CreateDownloadUrl(const char *path, char *url) { 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); mir_ptr response(request.Send(hNetlibConnection)); HandleHttpResponseError(response); JSONROOT root(response->pData); if (root) { JSONNODE *node = json_get(root, "url"); mir_strcpy(url, _T2A(json_as_string(node))); } } UINT CDropbox::SendFilesAsync(void *owner, void *arg) { CDropbox *instance = (CDropbox*)owner; FileTransferParam *ftp = (FileTransferParam*)arg; ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ftp->hProcess, 0); try { if (ftp->ptszFolders) { for (int i = 0; ftp->ptszFolders[i]; i++) { if(ftp->isTerminated) throw TransferException("Transfer was terminated"); ptrA utf8_folderName(mir_utf8encodeW(ftp->ptszFolders[i])); instance->CreateFolder(utf8_folderName); if (!strchr(utf8_folderName, '\\')) { char url[MAX_PATH]; instance->CreateDownloadUrl(utf8_folderName, url); ftp->AddUrl(url); } } } for (int i = 0; ftp->pfts.ptszFiles[i]; i++) { if (ftp->isTerminated) throw TransferException("Transfer was terminated"); FILE *hFile = _tfopen(ftp->pfts.ptszFiles[i], _T("rb")); if (hFile == NULL) throw TransferException("Unable to open file"); const TCHAR *fileName = NULL; if (!ftp->relativePathStart) fileName = _tcsrchr(ftp->pfts.ptszFiles[i], L'\\') + 1; else fileName = &ftp->pfts.ptszFiles[i][ftp->relativePathStart]; _fseeki64(hFile, 0, SEEK_END); uint64_t fileSize = _ftelli64(hFile); rewind(hFile); ftp->pfts.currentFileNumber = i; ftp->pfts.currentFileSize = fileSize; ftp->pfts.currentFileProgress = 0; ftp->pfts.tszCurrentFile = _tcsrchr(ftp->pfts.ptszFiles[i], '\\') + 1; size_t offset = 0; char uploadId[32]; int chunkSize = DROPBOX_FILE_CHUNK_SIZE / 4; if (fileSize < 1024 * 1024) chunkSize = DROPBOX_FILE_CHUNK_SIZE / 20; else if (fileSize > 20 * 1024 * 1024) chunkSize = DROPBOX_FILE_CHUNK_SIZE; char *data = (char*)mir_alloc(chunkSize); while (!feof(hFile) && fileSize != offset) { if (ferror(hFile)) throw TransferException("Error while file sending"); if (ftp->isTerminated) throw TransferException("Transfer was terminated"); size_t size = fread(data, sizeof(char), chunkSize, hFile); try { if (offset == 0) instance->SendFileChunkedFirst(data, size, uploadId, offset); else instance->SendFileChunkedNext(data, size, uploadId, offset); } catch (TransferException) { mir_free(data); fclose(hFile); throw; } ftp->pfts.currentFileProgress += size; ftp->pfts.totalProgress += size; ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ftp->hProcess, (LPARAM)&ftp->pfts); } mir_free(data); fclose(hFile); if (ftp->pfts.currentFileProgress < ftp->pfts.currentFileSize) throw TransferException("Transfer was terminated"); ptrA utf8_fileName(mir_utf8encodeW(fileName)); instance->SendFileChunkedLast(utf8_fileName, uploadId); if (!_tcschr(fileName, L'\\')) { char url[MAX_PATH]; instance->CreateDownloadUrl(utf8_fileName, url); ftp->AddUrl(url); } ftp->pfts.currentFileProgress = ftp->pfts.currentFileSize; if (i < ftp->pfts.totalFiles - 1) ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ftp->hProcess, 0); } } catch (TransferException &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; } ProtoBroadcastAck(MODULE, ftp->pfts.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ftp->hProcess, 0); return 0; } UINT CDropbox::SendFilesAndReportAsync(void *owner, void *arg) { CDropbox *instance = (CDropbox*)owner; FileTransferParam *ftp = (FileTransferParam*)arg; int res = SendFilesAsync(owner, arg); if (res) { instance->transfers.remove(ftp); delete ftp; return res; } CMStringA urls; for (int i = 0; i < ftp->urlList.getCount(); i++) urls.AppendFormat("%s\r\n", ftp->urlList[i]); char *data = urls.GetBuffer(); if (db_get_b(NULL, MODULE, "UrlAutoSend", 1)) { char *message = mir_utf8encode(data); if (ftp->hContact != instance->GetDefaultContact()) { if (CallContactService(ftp->hContact, PSS_MESSAGE, 0, (LPARAM)message) != ACKRESULT_FAILED) { DBEVENTINFO dbei = { sizeof(dbei) }; dbei.flags = DBEF_UTF | DBEF_SENT/* | DBEF_READ*/; dbei.szModule = MODULE; dbei.timestamp = time(NULL); dbei.eventType = EVENTTYPE_MESSAGE; dbei.cbBlob = (int)mir_strlen(data); dbei.pBlob = (PBYTE)message; db_event_add(ftp->hContact, &dbei); } else { CallServiceSync(MS_MSG_SENDMESSAGE, (WPARAM)ftp->hContact, (LPARAM)data); mir_free(message); } } else { DBEVENTINFO dbei = { sizeof(dbei) }; dbei.flags = DBEF_UTF; dbei.szModule = MODULE; dbei.timestamp = time(NULL); dbei.eventType = EVENTTYPE_MESSAGE; dbei.cbBlob = (int)mir_strlen(data); dbei.pBlob = (PBYTE)message; db_event_add(ftp->hContact, &dbei); } } if (db_get_b(NULL, MODULE, "UrlPasteToMessageInputArea", 0)) CallServiceSync(MS_MSG_SENDMESSAGE, (WPARAM)ftp->hContact, (LPARAM)data); if (db_get_b(NULL, MODULE, "UrlCopyToClipboard", 0)) { if (OpenClipboard(NULL)) { EmptyClipboard(); size_t size = sizeof(TCHAR) * (urls.GetLength() + 1); HGLOBAL hClipboardData = GlobalAlloc(NULL, size); if (hClipboardData) { TCHAR *pchData = (TCHAR*)GlobalLock(hClipboardData); if (pchData) { memcpy(pchData, (TCHAR*)data, size); GlobalUnlock(hClipboardData); SetClipboardData(CF_TEXT, hClipboardData); } } CloseClipboard(); } } instance->transfers.remove(ftp); delete ftp; return res; } UINT CDropbox::SendFilesAndEventAsync(void *owner, void *arg) { CDropbox *instance = (CDropbox*)owner; FileTransferParam *ftp = (FileTransferParam*)arg; int res = SendFilesAsync(owner, arg); TRANSFERINFO ti = { 0 }; ti.hProcess = ftp->hProcess; ti.status = res; ti.data = ftp->urlList.getArray(); NotifyEventHooks(instance->hFileSentEventHook, ftp->hContact, (LPARAM)&ti); instance->transfers.remove(ftp); delete ftp; return res; }