summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--protocols/ICQ-WIM/src/file.cpp17
-rw-r--r--protocols/ICQ-WIM/src/proto.cpp115
-rw-r--r--protocols/ICQ-WIM/src/proto.h16
-rw-r--r--protocols/ICQ-WIM/src/server.cpp125
-rw-r--r--src/core/stdfile/src/file.cpp1
5 files changed, 117 insertions, 157 deletions
diff --git a/protocols/ICQ-WIM/src/file.cpp b/protocols/ICQ-WIM/src/file.cpp
index 76b55026f9..1dc58ba06b 100644
--- a/protocols/ICQ-WIM/src/file.cpp
+++ b/protocols/ICQ-WIM/src/file.cpp
@@ -17,23 +17,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdafx.h"
-// create an object for receiving
-IcqFileTransfer::IcqFileTransfer(MCONTACT hContact, const char *pszUrl) :
- m_szHost(pszUrl)
-{
- pfts.hContact = hContact;
- pfts.totalFiles = 1;
- pfts.flags = PFTS_UNICODE | PFTS_RECEIVING;
-
- ptrW pwszFileName(mir_utf8decodeW(pszUrl));
- if (pwszFileName == nullptr)
- pwszFileName = mir_a2u(pszUrl);
-
- const wchar_t *p = wcsrchr(pwszFileName, '/');
- m_wszFileName = (p == nullptr) ? pwszFileName : p + 1;
- m_wszShortName = m_wszFileName;
-}
-
// create an object for sending
IcqFileTransfer::IcqFileTransfer(MCONTACT hContact, const wchar_t *pwszFileName) :
m_wszFileName(pwszFileName)
diff --git a/protocols/ICQ-WIM/src/proto.cpp b/protocols/ICQ-WIM/src/proto.cpp
index 9cade4f8d9..09496b46c4 100644
--- a/protocols/ICQ-WIM/src/proto.cpp
+++ b/protocols/ICQ-WIM/src/proto.cpp
@@ -74,6 +74,9 @@ CIcqProto::CIcqProto(const char *aProtoName, const wchar_t *aUserName) :
CreateProtoService(PS_GETUNREADEMAILCOUNT, &CIcqProto::GetEmailCount);
CreateProtoService(PS_GOTO_INBOX, &CIcqProto::GotoInbox);
+ // offline file transfer
+ CreateProtoService(PS_OFFLINEFILE, &CIcqProto::SvcOfflineFile);
+
// events
HookProtoEvent(ME_CLIST_GROUPCHANGE, &CIcqProto::OnGroupChange);
HookProtoEvent(ME_GC_EVENT, &CIcqProto::GroupchatEventHook);
@@ -165,11 +168,73 @@ void CIcqProto::OnContactDeleted(MCONTACT hContact)
<< AIMSID(this) << WCHAR_PARAM("buddy", szId) << INT_PARAM("allGroups", 1));
}
+void CIcqProto::OnCreateOfflineFile(DB::FILE_BLOB &blob, void *hTransfer)
+{
+ if (auto *pFileInfo = (IcqFileInfo *)hTransfer) {
+ blob.setUrl(pFileInfo->szUrl);
+ blob.setSize(pFileInfo->dwFileSize);
+ }
+}
+
void CIcqProto::OnEventEdited(MCONTACT, MEVENT)
{
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CIcqProto::OnFileRecv(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ if (pReply->resultCode != 200)
+ return;
+
+ auto *ofd = (OFDTHREAD *)pReq->pUserInfo;
+ debugLogW(L"Saving to [%s]", ofd->wszPath.c_str());
+ int fileId = _wopen(ofd->wszPath, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if (fileId == -1) {
+ debugLogW(L"Cannot open [%s] for writing", ofd->wszPath.c_str());
+ return;
+ }
+
+ int result = _write(fileId, pReply->pData, pReply->dataLength);
+ _close(fileId);
+ if (result != pReply->dataLength) {
+ debugLogW(L"Error writing data into [%s]", ofd->wszPath.c_str());
+ return;
+ }
+
+ delete ofd;
+}
+
+void __cdecl CIcqProto::OfflineFileThread(void *pParam)
+{
+ auto *ofd = (OFDTHREAD *)pParam;
+
+ DB::EventInfo dbei(ofd->hDbEvent);
+ if (dbei && !strcmp(dbei.szModule, m_szModuleName) && dbei.eventType == EVENTTYPE_FILE) {
+ JSONNode root = JSONNode::parse((const char *)dbei.pBlob);
+ if (m_bOnline && root) {
+ auto *pReq = new AsyncHttpRequest(CONN_NONE, REQUEST_GET, root["u"].as_string().c_str(), &CIcqProto::OnFileRecv);
+ pReq->pUserInfo = ofd;
+ pReq->AddHeader("Sec-Fetch-User", "?1");
+ pReq->AddHeader("Sec-Fetch-Site", "cross-site");
+ pReq->AddHeader("Sec-Fetch-Mode", "navigate");
+ Push(pReq);
+ return;
+ }
+ }
+
+ delete ofd;
+}
+
+INT_PTR __cdecl CIcqProto::SvcOfflineFile(WPARAM param, LPARAM)
+{
+ ForkThread((MyThreadFunc)&CIcqProto::OfflineFileThread, (void *)param);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
INT_PTR CIcqProto::OnMenuLoadHistory(WPARAM hContact, LPARAM)
{
delSetting(hContact, DB_KEY_LASTMSGID);
@@ -341,56 +406,6 @@ int CIcqProto::AuthRequest(MCONTACT hContact, const wchar_t* szMessage)
}
////////////////////////////////////////////////////////////////////////////////////////
-// File operations
-
-HANDLE CIcqProto::FileAllow(MCONTACT, HANDLE hTransfer, const wchar_t *pwszSavePath)
-{
- if (!m_bOnline)
- return nullptr;
-
- auto *ft = (IcqFileTransfer *)hTransfer;
- ft->m_wszFileName.Insert(0, pwszSavePath);
- ft->pfts.szCurrentFile.w = ft->m_wszFileName.GetBuffer();
- ft->Acquire();
-
- auto *pReq = new AsyncHttpRequest(CONN_NONE, REQUEST_GET, ft->m_szHost, &CIcqProto::OnFileRecv);
- pReq->pUserInfo = ft;
- pReq->AddHeader("Sec-Fetch-User", "?1");
- pReq->AddHeader("Sec-Fetch-Site", "cross-site");
- pReq->AddHeader("Sec-Fetch-Mode", "navigate");
- Push(pReq);
-
- return hTransfer;
-}
-
-int CIcqProto::FileCancel(MCONTACT hContact, HANDLE hTransfer)
-{
- ProtoBroadcastAck(hContact, ACKTYPE_FILE, ACKRESULT_FAILED, hTransfer);
-
- auto *ft = (IcqFileTransfer *)hTransfer;
- if (ft->pfts.currentFileTime != 0)
- ft->m_bCanceled = true;
- else
- ft->Release();
- return 0;
-}
-
-int CIcqProto::FileResume(HANDLE hTransfer, int, const wchar_t *szFilename)
-{
- auto *ft = (IcqFileTransfer *)hTransfer;
- if (!m_bOnline || ft == nullptr)
- return 1;
-
- if (szFilename != nullptr) {
- ft->m_wszFileName = szFilename;
- ft->pfts.szCurrentFile.w = ft->m_wszFileName.GetBuffer();
- }
-
- ::SetEvent(ft->hWaitEvent);
- return 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////
// GetCaps - return protocol capabilities bits
INT_PTR CIcqProto::GetCaps(int type, MCONTACT)
diff --git a/protocols/ICQ-WIM/src/proto.h b/protocols/ICQ-WIM/src/proto.h
index b7cac8f5c4..018a4e1399 100644
--- a/protocols/ICQ-WIM/src/proto.h
+++ b/protocols/ICQ-WIM/src/proto.h
@@ -144,7 +144,7 @@ struct IcqConn
int lastTs, timeout;
};
-struct IcqFileTransfer : public MZeroedObject, public MShareable
+struct IcqFileTransfer : public MZeroedObject
{
bool m_bCanceled = false, m_bStarted = false;
int m_fileId = -1;
@@ -152,15 +152,11 @@ struct IcqFileTransfer : public MZeroedObject, public MShareable
CMStringW m_wszFileName, m_wszDescr;
const wchar_t *m_wszShortName;
PROTOFILETRANSFERSTATUS pfts;
- HANDLE hWaitEvent;
-
- // create an object for receiving
- IcqFileTransfer(MCONTACT hContact, const char *pszUrl);
// create an object for sending
IcqFileTransfer(MCONTACT hContact, const wchar_t *pwszFileName);
- ~IcqFileTransfer() override;
+ ~IcqFileTransfer();
void FillHeaders(AsyncHttpRequest *pReq);
};
@@ -353,6 +349,7 @@ class CIcqProto : public PROTO<CIcqProto>
HANDLE m_hWorkerThread;
void __cdecl ServerThread(void*);
void __cdecl PollThread(void*);
+ void __cdecl OfflineFileThread(void*);
////////////////////////////////////////////////////////////////////////////////////////
// services
@@ -362,6 +359,8 @@ class CIcqProto : public PROTO<CIcqProto>
INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM);
INT_PTR __cdecl SetAvatar(WPARAM, LPARAM);
+ INT_PTR __cdecl SvcOfflineFile(WPARAM, LPARAM);
+
INT_PTR __cdecl EditGroups(WPARAM, LPARAM);
INT_PTR __cdecl EditProfile(WPARAM, LPARAM);
INT_PTR __cdecl GetEmailCount(WPARAM, LPARAM);
@@ -390,10 +389,6 @@ class CIcqProto : public PROTO<CIcqProto>
HANDLE SearchBasic(const wchar_t *id) override;
- HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath) override;
- int FileCancel(MCONTACT hContact, HANDLE hTransfer) override;
- int FileResume(HANDLE hTransfer, int action, const wchar_t *szFilename) override;
-
HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override;
int SendMsg(MCONTACT hContact, int flags, const char *msg) override;
@@ -406,6 +401,7 @@ class CIcqProto : public PROTO<CIcqProto>
void OnContactAdded(MCONTACT) override;
void OnContactDeleted(MCONTACT) override;
MWindow OnCreateAccMgrUI(MWindow) override;
+ void OnCreateOfflineFile(DB::FILE_BLOB &blob, void *ft) override;
void OnEventEdited(MCONTACT, MEVENT) override;
void OnMarkRead(MCONTACT, MEVENT) override;
void OnModulesLoaded() override;
diff --git a/protocols/ICQ-WIM/src/server.cpp b/protocols/ICQ-WIM/src/server.cpp
index e8f360144c..6a1eb0cbef 100644
--- a/protocols/ICQ-WIM/src/server.cpp
+++ b/protocols/ICQ-WIM/src/server.cpp
@@ -124,6 +124,42 @@ void CIcqProto::CheckPassword()
}
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CIcqProto::OnFileInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ IcqFileInfo **res = (IcqFileInfo **)pReq->pUserInfo;
+ *res = nullptr;
+
+ RobustReply root(pReply);
+ if (root.error() != 200)
+ return;
+
+ auto &pData = root.result();
+ auto &pInfo = pData["info"];
+ std::string szUrl(pInfo["dlink"].as_string());
+ if (szUrl.empty())
+ return;
+
+ OnMarkRead(pReq->hContact, 0);
+
+ bool bIsSticker;
+ CMStringW wszDescr(pInfo["file_name"].as_mstring());
+ if (!mir_wstrncmp(wszDescr, L"dnld", 4)) {
+ bIsSticker = true;
+
+ std::string szPreview = pData["previews"]["192"].as_string();
+ if (!szPreview.empty())
+ szUrl = szPreview;
+ }
+ else bIsSticker = false;
+
+ mir_urlDecode(&*szUrl.begin());
+
+ *res = new IcqFileInfo(szUrl, wszDescr, pInfo["file_size"].as_int());
+ res[0]->bIsSticker = bIsSticker;
+}
+
IcqFileInfo* CIcqProto::CheckFile(MCONTACT hContact, CMStringW &wszText, bool &bIsFile)
{
CMStringW wszUrl(wszText.Mid(26));
@@ -522,17 +558,20 @@ void CIcqProto::ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNo
// convert a file info into Miranda's file transfer
if (bIsFileTransfer) {
- auto *ft = new IcqFileTransfer(hContact, pFileInfo->szUrl);
- ft->pfts.totalBytes = ft->pfts.currentFileSize = pFileInfo->dwFileSize;
- ft->pfts.szCurrentFile.w = ft->m_wszFileName.GetBuffer();
+ ptrW pwszFileName(mir_utf8decodeW(pFileInfo->szUrl));
+ if (pwszFileName == nullptr)
+ pwszFileName = mir_a2u(pFileInfo->szUrl);
+
+ const wchar_t *p = wcsrchr(pwszFileName, '/');
+ const wchar_t *m_wszShortName = (p == nullptr) ? pwszFileName : p + 1;
PROTORECVFILE pre = {};
- pre.dwFlags = PRFF_UNICODE;
+ pre.dwFlags = PRFF_UNICODE | PRFF_SILENT;
pre.fileCount = 1;
pre.timestamp = iMsgTime;
- pre.files.w = &ft->m_wszShortName;
+ pre.files.w = &m_wszShortName;
pre.descr.w = pFileInfo->wszDescr;
- pre.lParam = (LPARAM)ft;
+ pre.lParam = (LPARAM)pFileInfo;
ProtoChainRecvFile(hContact, &pre);
delete pFileInfo;
@@ -944,80 +983,6 @@ void CIcqProto::OnGetSticker(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
}
/////////////////////////////////////////////////////////////////////////////////////////
-// File info request
-
-void CIcqProto::OnFileInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- IcqFileInfo **res = (IcqFileInfo **)pReq->pUserInfo;
- *res = nullptr;
-
- RobustReply root(pReply);
- if (root.error() != 200)
- return;
-
- auto &pData = root.result();
- auto &pInfo = pData["info"] ;
- std::string szUrl(pInfo["dlink"].as_string());
- if (szUrl.empty())
- return;
-
- OnMarkRead(pReq->hContact, 0);
-
- bool bIsSticker;
- CMStringW wszDescr(pInfo["file_name"].as_mstring());
- if (!mir_wstrncmp(wszDescr, L"dnld", 4)) {
- bIsSticker = true;
-
- std::string szPreview = pData["previews"]["192"].as_string();
- if (!szPreview.empty())
- szUrl = szPreview;
- }
- else bIsSticker = false;
-
- mir_urlDecode(&*szUrl.begin());
-
- *res = new IcqFileInfo(szUrl, wszDescr, pInfo["file_size"].as_int());
- res[0]->bIsSticker = bIsSticker;
-}
-
-void CIcqProto::OnFileRecv(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
-{
- auto *ft = (IcqFileTransfer*)pReq->pUserInfo;
-
- if (pReply->resultCode != 200) {
-LBL_Error:
- FileCancel(pReq->hContact, ft);
- return;
- }
-
- ft->hWaitEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
- if (ProtoBroadcastAck(ft->pfts.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, ft, (LPARAM)&ft->pfts))
- WaitForSingleObject(ft->hWaitEvent, INFINITE);
- CloseHandle(ft->hWaitEvent);
-
- debugLogW(L"Saving to [%s]", ft->pfts.szCurrentFile.w);
- int fileId = _wopen(ft->pfts.szCurrentFile.w, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
- if (fileId == -1) {
- debugLogW(L"Cannot open [%s] for writing", ft->pfts.szCurrentFile.w);
- goto LBL_Error;
- }
-
- int result = _write(fileId, pReply->pData, pReply->dataLength);
- _close(fileId);
- if (result != pReply->dataLength) {
- debugLogW(L"Error writing data into [%s]", ft->pfts.szCurrentFile.w);
- goto LBL_Error;
- }
-
- ft->pfts.totalProgress += pReply->dataLength;
- ft->pfts.currentFileProgress += pReply->dataLength;
- ProtoBroadcastAck(ft->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
-
- ProtoBroadcastAck(ft->pfts.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft);
- delete ft;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
void CIcqProto::OnGenToken(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
{
diff --git a/src/core/stdfile/src/file.cpp b/src/core/stdfile/src/file.cpp
index 5368a9a1dc..5efa3f7027 100644
--- a/src/core/stdfile/src/file.cpp
+++ b/src/core/stdfile/src/file.cpp
@@ -340,6 +340,7 @@ static INT_PTR Proto_RecvFileT(WPARAM, LPARAM lParam)
}
DB::FILE_BLOB blob(wszFiles, pre->descr.w);
+ CallProtoService(dbei.szModule, PS_PRECREATE_OFFLINEFILE, WPARAM(&blob), pre->lParam);
blob.write(dbei);
}
else {