summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--protocols/ICQ-WIM/src/proto.cpp31
-rw-r--r--protocols/ICQ-WIM/src/proto.h22
-rw-r--r--protocols/ICQ-WIM/src/server.cpp90
3 files changed, 109 insertions, 34 deletions
diff --git a/protocols/ICQ-WIM/src/proto.cpp b/protocols/ICQ-WIM/src/proto.cpp
index e50442fd8b..0e5cb32fb0 100644
--- a/protocols/ICQ-WIM/src/proto.cpp
+++ b/protocols/ICQ-WIM/src/proto.cpp
@@ -393,6 +393,37 @@ 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();
+
+ 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, 0);
+
+ auto *ft = (IcqFileTransfer *)hTransfer;
+ delete ft;
+ 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 95ea7b72bb..28b54f202a 100644
--- a/protocols/ICQ-WIM/src/proto.h
+++ b/protocols/ICQ-WIM/src/proto.h
@@ -127,6 +127,21 @@ struct IcqConn
struct IcqFileTransfer : public MZeroedObject
{
+ // create an object for receiving
+ 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));
+ const wchar_t *p = wcsrchr(pwszFileName, '/');
+ m_wszFileName = (p == nullptr) ? pwszFileName : p + 1;
+ m_wszShortName = m_wszShortName;
+ }
+
+ // create an object for sending
IcqFileTransfer(MCONTACT hContact, const wchar_t *pwszFileName) :
m_wszFileName(pwszFileName)
{
@@ -229,7 +244,6 @@ class CIcqProto : public PROTO<CIcqProto>
void SetServerStatus(int iNewStatus);
void ShutdownSession(void);
void StartSession(void);
- void TryFetchFileInfo(CMStringW &wszText);
void CheckAvatarChange(MCONTACT hContact, const JSONNode&);
void CheckLastId(MCONTACT hContact, const JSONNode&);
@@ -258,6 +272,7 @@ class CIcqProto : public PROTO<CIcqProto>
void OnFileContinue(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
void OnFileInit(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
void OnFileInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
+ void OnFileRecv(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
void OnGenToken(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
void OnGetChatInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
void OnGetPermitDeny(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq);
@@ -387,7 +402,10 @@ class CIcqProto : public PROTO<CIcqProto>
int GetInfo(MCONTACT hContact, int infoType) override;
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;
+
HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override;
int SendMsg(MCONTACT hContact, int flags, const char *msg) override;
diff --git a/protocols/ICQ-WIM/src/server.cpp b/protocols/ICQ-WIM/src/server.cpp
index 265b6ba632..2f67f4b0d9 100644
--- a/protocols/ICQ-WIM/src/server.cpp
+++ b/protocols/ICQ-WIM/src/server.cpp
@@ -368,7 +368,7 @@ void CIcqProto::ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNo
}
else {
wszText = it["text"].as_mstring();
- TryFetchFileInfo(wszText);
+ wszText.TrimRight();
}
int iMsgTime = (bFromHistory) ? it["time"].as_int() : time(0);
@@ -401,6 +401,15 @@ void CIcqProto::ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNo
return;
bool bIsOutgoing = it["outgoing"].as_bool();
+ if (!bIsOutgoing && wszText.Left(26) == L"https://files.icq.net/get/") {
+ CMStringA szUrl(FORMAT, ICQ_FILE_SERVER "/info/%S/", wszText.Mid(26).c_str());
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, szUrl, &CIcqProto::OnFileInfo);
+ pReq->hContact = hContact;
+ pReq << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("previews", "600");
+ Push(pReq);
+ return;
+ }
+
ptrA szUtf(mir_utf8encodeW(wszText));
PROTORECVEVENT pre = {};
@@ -467,19 +476,6 @@ void CIcqProto::RetrieveUserInfo(MCONTACT hContact)
Push(pReq);
}
-void CIcqProto::TryFetchFileInfo(CMStringW &wszText)
-{
- wszText.TrimRight();
-
- if (wszText.Left(26) == L"https://files.icq.net/get/") {
- CMStringA szUrl(FORMAT, ICQ_FILE_SERVER "/info/%S/", wszText.Mid(26).c_str());
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, szUrl, &CIcqProto::OnFileInfo);
- pReq << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("previews", "600");
- pReq->pUserInfo = &wszText;
- ExecuteRequest(pReq);
- }
-}
-
AsyncHttpRequest* CIcqProto::UserInfoRequest(MCONTACT hContact)
{
auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/presence/get", &CIcqProto::OnGetUserInfo);
@@ -738,9 +734,6 @@ void CIcqProto::OnFileContinue(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pOld
<< CHAR_PARAM("offlineIM", "true") << WCHAR_PARAM("parts", wszParts) << WCHAR_PARAM("t", GetUserId(pTransfer->pfts.hContact)) << INT_PARAM("ts", TS());
Push(pReq);
- // Send the same message to myself
- TryFetchFileInfo(wszUrl);
-
T2Utf msgText(wszUrl);
PROTORECVEVENT recv = {};
recv.flags = PREF_CREATEREAD | PREF_SENT;
@@ -798,34 +791,67 @@ void CIcqProto::OnFileInit(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pOld)
ProtoBroadcastAck(pTransfer->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, pTransfer, (LPARAM)&pTransfer->pfts);
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CIcqProto::OnFileInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
{
- CMStringW *wszText = (CMStringW *)pReq->pUserInfo;
-
RobustReply root(pReply);
if (root.error() != 200)
return;
- wszText->Empty();
auto &data = root.result();
- CMStringW tmp(data["extra"]["file_type"].as_mstring());
- wszText->AppendFormat(L"%s\r\n", (tmp == "image") ? TranslateT("Image received:") : TranslateT("File received"));
+ std::string szUrl(data["info"]["dlink"].as_string());
+ if (szUrl.empty())
+ return;
- tmp = data["info"]["file_name"].as_mstring();
- if (!tmp.IsEmpty())
- wszText->AppendFormat(L"%s: %s\r\n", TranslateT("File name"), tmp.c_str());
+ mir_urlDecode(&*szUrl.begin());
+ auto *ft = new IcqFileTransfer(pReq->hContact, szUrl.c_str());
+ ft->pfts.totalBytes = ft->pfts.currentFileSize = 100;
+ ft->pfts.szCurrentFile.w = ft->m_wszFileName.GetBuffer();
+
+ PROTORECVFILE pre = { 0 };
+ pre.dwFlags = PRFF_UNICODE;
+ pre.fileCount = 1;
+ pre.timestamp = time(0);
+ pre.files.w = &ft->m_wszShortName;
+ pre.lParam = (LPARAM)ft;
+ ProtoChainRecvFile(pReq->hContact, &pre);
+}
+
+void CIcqProto::OnFileRecv(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ auto *ft = (IcqFileTransfer*)pReq->pUserInfo;
+
+ if (pReply->resultCode != 200) {
+LBL_Error:
+ FileCancel(pReq->hContact, ft);
+ return;
+ }
- tmp = data["info"]["dlink"].as_mstring();
- if (!tmp.IsEmpty())
- wszText->AppendFormat(L"%s: %s\r\n", TranslateT("URL"), tmp.c_str());
+ ft->pfts.totalProgress += 100;
+ ft->pfts.currentFileProgress += 100;
+ ProtoBroadcastAck(ft->pfts.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, (LPARAM)&ft->pfts);
- if (data["info"]["has_previews"].as_bool()) {
- tmp = data["previews"]["600"].as_mstring();
- if (!tmp.IsEmpty())
- wszText->AppendFormat(L"%s: %s\r\n", TranslateT("Preview"), tmp.c_str());
+ 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;
}
+
+ ProtoBroadcastAck(ft->pfts.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0);
+ delete ft;
}
+/////////////////////////////////////////////////////////////////////////////////////////
+
void CIcqProto::OnGenToken(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*)
{
RobustReply root(pReply);