From 9d98fd2380b5e8bc66ab599e896cee5ad2ec7d58 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 10 Jan 2025 13:25:50 +0300 Subject: =?UTF-8?q?fixes=20#4829=20(SkypeWeb:=20=D0=BD=D0=B5=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D0=BE=D1=82=D1=81?= =?UTF-8?q?=D1=8B=D0=BB=D0=BA=D0=B0=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=B8=D1=85=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocols/SkypeWeb/src/requests/files.h | 67 ------------------ protocols/SkypeWeb/src/skype_files.cpp | 120 +++++++++++++++++++++++--------- protocols/SkypeWeb/src/skype_proto.h | 5 +- protocols/SkypeWeb/src/skype_utils.h | 17 ++--- protocols/SkypeWeb/src/stdafx.h | 1 - 5 files changed, 99 insertions(+), 111 deletions(-) delete mode 100644 protocols/SkypeWeb/src/requests/files.h (limited to 'protocols/SkypeWeb/src') diff --git a/protocols/SkypeWeb/src/requests/files.h b/protocols/SkypeWeb/src/requests/files.h deleted file mode 100644 index 7c04baabfb..0000000000 --- a/protocols/SkypeWeb/src/requests/files.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -struct ASMObjectCreateRequest : public AsyncHttpRequest -{ - ASMObjectCreateRequest(CSkypeProto *ppro, CFileUploadParam *fup) : - AsyncHttpRequest(REQUEST_POST, HOST_OTHER, "https://api.asm.skype.com/v1/objects", &CSkypeProto::OnASMObjectCreated) - { - flags &= (~NLHRF_DUMPASTEXT); - pUserInfo = fup; - - AddHeader("Authorization", CMStringA(FORMAT, "skype_token %s", ppro->m_szApiToken.get())); - AddHeader("Content-Type", "application/json"); - AddHeader("X-Client-Version", "0/0.0.0.0"); - - CMStringA szContact(ppro->getId(fup->hContact)); - T2Utf uszFileName(fup->tszFileName); - const char *szFileName = strrchr(uszFileName.get() + 1, '\\'); - - JSONNode node; - if (fup->isPicture) - node << CHAR_PARAM("type", "pish/image"); - else - node << CHAR_PARAM("type", "sharing/file"); - - JSONNode jPermission(JSON_ARRAY); jPermission.set_name(szContact.c_str()); jPermission << CHAR_PARAM("", "read"); - JSONNode jPermissions; jPermissions.set_name("permissions"); jPermissions << jPermission; - node << CHAR_PARAM("filename", szFileName) << jPermissions; - m_szParam = node.write().c_str(); - } -}; - -struct ASMObjectUploadRequest : public AsyncHttpRequest -{ - ASMObjectUploadRequest(CSkypeProto *ppro, const char *szObject, const uint8_t *data, int size, CFileUploadParam *fup) : - AsyncHttpRequest(REQUEST_PUT, HOST_OTHER, 0, &CSkypeProto::OnASMObjectUploaded) - { - m_szUrl.AppendFormat("https://api.asm.skype.com/v1/objects/%s/content/%s", - szObject, fup->isPicture ? "imgpsh" : "original"); - pUserInfo = fup; - - AddHeader("Authorization", CMStringA(FORMAT, "skype_token %s", ppro->m_szApiToken.get())); - AddHeader("Content-Type", fup->isPicture ? "application" : "application/octet-stream"); - - m_szParam.Truncate(size); - memcpy(m_szParam.GetBuffer(), data, size); - } -}; - -struct SendFileRequest : public AsyncHttpRequest -{ - SendFileRequest(CFileUploadParam *fup, const char *username, const char *message) : - AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, 0, &CSkypeProto::OnMessageSent) - { - m_szUrl.AppendFormat("/users/ME/conversations/%s/messages", mir_urlEncode(username).c_str()); - - JSONNode ref(JSON_ARRAY); ref.set_name("amsreferences"); ref << CHAR_PARAM("", fup->uid); - - JSONNode node; - if (fup->isPicture) - node << CHAR_PARAM("messagetype", "RichText/UriObject"); - else - node << CHAR_PARAM("messagetype", "RichText/Media_GenericFile"); - - node << INT64_PARAM("clientmessageid", time(0)) << CHAR_PARAM("contenttype", "text") << CHAR_PARAM("content", message) << ref; - m_szParam = node.write().c_str(); - } -}; diff --git a/protocols/SkypeWeb/src/skype_files.cpp b/protocols/SkypeWeb/src/skype_files.cpp index 24f279a600..6d3f6646db 100644 --- a/protocols/SkypeWeb/src/skype_files.cpp +++ b/protocols/SkypeWeb/src/skype_files.cpp @@ -101,37 +101,48 @@ INT_PTR CSkypeProto::SvcOfflineFile(WPARAM param, LPARAM) #define FILETRANSFER_FAILED(fup) { ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)fup); delete fup; fup = nullptr;} -HANDLE CSkypeProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) -{ - if (IsOnline()) { - CFileUploadParam *fup = new CFileUploadParam(hContact, szDescription, ppszFiles); - ForkThread(&CSkypeProto::SendFileThread, (void*)fup); - return (HANDLE)fup; - } - return INVALID_HANDLE_VALUE; -} - -void CSkypeProto::SendFileThread(void *p) +void CSkypeProto::SendFile(CFileUploadParam *fup) { - CFileUploadParam *fup = (CFileUploadParam *)p; - if (!IsOnline()) { - FILETRANSFER_FAILED(fup); - return; - } - if (!fup->IsAccess()) { + auto *pwszFileName = &fup->arFileName[0]; + if (!IsOnline() || _waccess(pwszFileName, 0)) { FILETRANSFER_FAILED(fup); return; } - if (auto *pBitmap = FreeImage_LoadU(FreeImage_GetFIFFromFilenameU(fup->tszFileName), fup->tszFileName)) { + if (auto *pBitmap = FreeImage_LoadU(FreeImage_GetFIFFromFilenameU(pwszFileName), pwszFileName)) { fup->isPicture = true; fup->width = FreeImage_GetWidth(pBitmap); fup->height = FreeImage_GetHeight(pBitmap); FreeImage_Unload(pBitmap); } + else fup->isPicture = false; ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTING, (HANDLE)fup); - PushRequest(new ASMObjectCreateRequest(this, fup)); + + // create upload slot + auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_OTHER, "https://api.asm.skype.com/v1/objects", &CSkypeProto::OnASMObjectCreated); + pReq->flags &= (~NLHRF_DUMPASTEXT); + pReq->pUserInfo = fup; + + pReq->AddHeader("Authorization", CMStringA(FORMAT, "skype_token %s", m_szApiToken.get())); + pReq->AddHeader("Content-Type", "application/json"); + pReq->AddHeader("X-Client-Version", "0/0.0.0.0"); + + CMStringA szContact(getId(fup->hContact)); + T2Utf uszFileName(&fup->arFileName[0]); + const char *szFileName = strrchr(uszFileName.get() + 1, '\\'); + + JSONNode node; + if (fup->isPicture) + node << CHAR_PARAM("type", "pish/image"); + else + node << CHAR_PARAM("type", "sharing/file"); + + JSONNode jPermission(JSON_ARRAY); jPermission.set_name(szContact.c_str()); jPermission << CHAR_PARAM("", "read"); + JSONNode jPermissions; jPermissions.set_name("permissions"); jPermissions << jPermission; + node << CHAR_PARAM("filename", szFileName) << jPermissions; + pReq->m_szParam = node.write().c_str(); + PushRequest(pReq); } void CSkypeProto::OnASMObjectCreated(MHttpResponse *response, AsyncHttpRequest *pRequest) @@ -156,8 +167,9 @@ LBL_Error: } fup->uid = mir_strdup(strObjectId.c_str()); - FILE *pFile = _wfopen(fup->tszFileName, L"rb"); - if (pFile == nullptr) return; + FILE *pFile = _wfopen(&fup->arFileName[0], L"rb"); + if (pFile == nullptr) + goto LBL_Error; fseek(pFile, 0, SEEK_END); long lFileLen = ftell(pFile); @@ -170,25 +182,37 @@ LBL_Error: mir_ptr pData((uint8_t*)mir_alloc(lFileLen)); long lBytes = (long)fread(pData, sizeof(uint8_t), lFileLen, pFile); - if (lBytes != lFileLen) { - fclose(pFile); + fclose(pFile); + + if (lBytes != lFileLen) goto LBL_Error; - } + fup->size = lBytes; ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, (HANDLE)fup); - PushRequest(new ASMObjectUploadRequest(this, strObjectId.c_str(), pData, lBytes, fup)); - fclose(pFile); + + // upload file to the previously created slot + auto *pReq = new AsyncHttpRequest(REQUEST_PUT, HOST_OTHER, 0, &CSkypeProto::OnASMObjectUploaded); + pReq->m_szUrl.Format("https://api.asm.skype.com/v1/objects/%s/content/%s", + strObjectId.c_str(), fup->isPicture ? "imgpsh" : "original"); + pReq->pUserInfo = fup; + + pReq->AddHeader("Authorization", CMStringA(FORMAT, "skype_token %s", m_szApiToken.get())); + pReq->AddHeader("Content-Type", fup->isPicture ? "application" : "application/octet-stream"); + + pReq->m_szParam.Truncate(lBytes); + memcpy(pReq->m_szParam.GetBuffer(), pData, lBytes); + PushRequest(pReq); } void CSkypeProto::OnASMObjectUploaded(MHttpResponse *response, AsyncHttpRequest *pRequest) { - auto *fup = (CFileUploadParam*)pRequest->pUserInfo; + auto *fup = (CFileUploadParam *)pRequest->pUserInfo; if (response == nullptr) { FILETRANSFER_FAILED(fup); return; } - wchar_t *tszFile = wcsrchr(fup->tszFileName, L'\\') + 1; + wchar_t *tszFile = wcsrchr(&fup->arFileName[0], L'\\') + 1; TiXmlDocument doc; auto *pRoot = doc.NewElement("URIObject"); @@ -224,7 +248,7 @@ void CSkypeProto::OnASMObjectUploaded(MHttpResponse *response, AsyncHttpRequest auto *xmlSize = doc.NewElement("FileSize"); xmlSize->SetAttribute("v", (int)fup->size); pRoot->InsertEndChild(xmlSize); if (fup->isPicture) { - auto xmlMeta = doc.NewElement("meta"); + auto xmlMeta = doc.NewElement("meta"); xmlMeta->SetAttribute("type", "photo"); xmlMeta->SetAttribute("originalName", tszFile); pRoot->InsertEndChild(xmlMeta); } @@ -236,11 +260,43 @@ void CSkypeProto::OnASMObjectUploaded(MHttpResponse *response, AsyncHttpRequest Utils_GetRandom(&hMessage, sizeof(hMessage)); hMessage &= ~0x80000000; - auto *pReq = new SendFileRequest(fup, getId(fup->hContact), printer.CStr()); + // create a new file transfer event using previously filled slot + auto *pReq = new AsyncHttpRequest(REQUEST_POST, HOST_DEFAULT, 0, &CSkypeProto::OnMessageSent); + pReq->m_szUrl.AppendFormat("/users/ME/conversations/%s/messages", mir_urlEncode(getId(fup->hContact)).c_str()); pReq->hContact = fup->hContact; pReq->pUserInfo = (HANDLE)hMessage; + + JSONNode ref(JSON_ARRAY); ref.set_name("amsreferences"); ref << CHAR_PARAM("", fup->uid); + + JSONNode node; + if (fup->isPicture) + node << CHAR_PARAM("messagetype", "RichText/UriObject"); + else + node << CHAR_PARAM("messagetype", "RichText/Media_GenericFile"); + + node << INT64_PARAM("clientmessageid", time(0)) << CHAR_PARAM("contenttype", "text") << CHAR_PARAM("content", printer.CStr()) << ref; + pReq->m_szParam = node.write().c_str(); + PushRequest(pReq); - ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)fup); - delete fup; + // if that's last file in the queue, finish file transfer, or proceed with the next file + if (fup->arFileName.getCount() == 1) { + ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)fup); + delete fup; + } + else { + fup->arFileName.remove(int(0)); + ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)fup); + SendFile(fup); + } +} + +HANDLE CSkypeProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) +{ + if (!IsOnline()) + return INVALID_HANDLE_VALUE; + + CFileUploadParam *fup = new CFileUploadParam(hContact, ppszFiles, szDescription); + SendFile(fup); + return fup; } diff --git a/protocols/SkypeWeb/src/skype_proto.h b/protocols/SkypeWeb/src/skype_proto.h index da73290f6e..b1feccf602 100644 --- a/protocols/SkypeWeb/src/skype_proto.h +++ b/protocols/SkypeWeb/src/skype_proto.h @@ -94,9 +94,6 @@ public: // search void __cdecl SearchBasicThread(void *param); - // threads - void __cdecl CSkypeProto::SendFileThread(void *p); - ////////////////////////////////////////////////////////////////////////////////////// // services @@ -251,6 +248,8 @@ private: MCONTACT GetContactFromAuthEvent(MEVENT hEvent); // files + void SendFile(CFileUploadParam *fup); + void __cdecl ReceiveFileThread(void *param); INT_PTR __cdecl SvcOfflineFile(WPARAM, LPARAM); diff --git a/protocols/SkypeWeb/src/skype_utils.h b/protocols/SkypeWeb/src/skype_utils.h index 8c9d73b1b0..feef9b8883 100644 --- a/protocols/SkypeWeb/src/skype_utils.h +++ b/protocols/SkypeWeb/src/skype_utils.h @@ -49,7 +49,7 @@ public: struct CFileUploadParam : public MZeroedObject { - ptrW tszFileName; + OBJLIST arFileName; ptrW tszDesc; ptrA atr; ptrA fname; @@ -59,13 +59,14 @@ struct CFileUploadParam : public MZeroedObject MCONTACT hContact; bool isPicture; - __forceinline CFileUploadParam(MCONTACT _hContact, const wchar_t* _desc, wchar_t** _files) : + CFileUploadParam(MCONTACT _hContact, wchar_t **_files, const wchar_t* _desc) : + arFileName(1), hContact(_hContact), - tszDesc(mir_wstrdup(_desc)), - tszFileName(mir_wstrdup(_files[0])) - {}; - - __forceinline bool IsAccess() { return ::_waccess(tszFileName, 0) == 0; } + tszDesc(mir_wstrdup(_desc)) + { + for (auto p = _files; *p != 0; p++) + arFileName.insert(newStrW(*p)); + } }; class JsonReply @@ -81,4 +82,4 @@ public: __forceinline int error() const { return m_errorCode; } }; -#endif //_UTILS_H_ \ No newline at end of file +#endif //_UTILS_H_ diff --git a/protocols/SkypeWeb/src/stdafx.h b/protocols/SkypeWeb/src/stdafx.h index 6d77964566..162b708a77 100644 --- a/protocols/SkypeWeb/src/stdafx.h +++ b/protocols/SkypeWeb/src/stdafx.h @@ -117,7 +117,6 @@ struct AsyncHttpRequest : public MTHttpRequest #include "requests/chatrooms.h" #include "requests/contacts.h" #include "requests/endpoint.h" -#include "requests/files.h" #include "requests/history.h" #include "requests/login.h" #include "requests/messages.h" -- cgit v1.2.3