summaryrefslogtreecommitdiff
path: root/protocols/ICQ-WIM/src/utils.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-01-16 18:06:52 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-01-16 18:06:52 +0300
commitaa514a9f95c8cd95c01952250f7cdb670a66af9a (patch)
treeecb84e10fc3af008e1a8ac9027f1b526634c8d65 /protocols/ICQ-WIM/src/utils.cpp
parent4f0a4ae4724fdfe65f63ee41dc1790ccbb0668f7 (diff)
fixes #1761 (Rename Icq10 folder and ICQ/2018 in version.h to ICQ-WIM)
Diffstat (limited to 'protocols/ICQ-WIM/src/utils.cpp')
-rw-r--r--protocols/ICQ-WIM/src/utils.cpp239
1 files changed, 239 insertions, 0 deletions
diff --git a/protocols/ICQ-WIM/src/utils.cpp b/protocols/ICQ-WIM/src/utils.cpp
new file mode 100644
index 0000000000..6cf6219322
--- /dev/null
+++ b/protocols/ICQ-WIM/src/utils.cpp
@@ -0,0 +1,239 @@
+// -----------------------------------------------------------------------------
+// ICQ plugin for Miranda NG
+// -----------------------------------------------------------------------------
+// Copyright © 2018-19 Miranda NG team
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+// -----------------------------------------------------------------------------
+
+#include "stdafx.h"
+
+void CIcqProto::InitContactCache()
+{
+ mir_cslock l(m_csCache);
+ for (auto &it : AccContacts())
+ if (!isChatRoom(it))
+ m_arCache.insert(new IcqCacheItem(getDword(it, DB_KEY_UIN), it));
+}
+
+IcqCacheItem* CIcqProto::FindContactByUIN(DWORD dwUin)
+{
+ mir_cslock l(m_csCache);
+ return m_arCache.find((IcqCacheItem*)&dwUin);
+}
+
+MCONTACT CIcqProto::CreateContact(DWORD dwUin, bool bTemporary)
+{
+ auto *pCache = FindContactByUIN(dwUin);
+ if (pCache != nullptr)
+ return pCache->m_hContact;
+
+ MCONTACT hContact = db_add_contact();
+ Proto_AddToContact(hContact, m_szModuleName);
+ setDword(hContact, DB_KEY_UIN, dwUin);
+ pCache = new IcqCacheItem(dwUin, hContact);
+ {
+ mir_cslock l(m_csCache);
+ m_arCache.insert(pCache);
+ }
+ RetrieveUserInfo(hContact);
+
+ if (bTemporary)
+ db_set_b(hContact, "CList", "NotOnList", 1);
+
+ return hContact;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CIcqProto::CalcHash(AsyncHttpRequest *pReq)
+{
+ CMStringA hashData(FORMAT, "POST&%s&%s", ptrA(mir_urlEncode(pReq->m_szUrl)), ptrA(mir_urlEncode(pReq->m_szParam)));
+ unsigned int len;
+ BYTE hashOut[MIR_SHA256_HASH_SIZE];
+ HMAC(EVP_sha256(), m_szSessionKey, m_szSessionKey.GetLength(), (BYTE*)hashData.c_str(), hashData.GetLength(), hashOut, &len);
+ pReq << CHAR_PARAM("sig_sha256", ptrA(mir_base64_encode(hashOut, sizeof(hashOut))));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Avatars
+
+void CIcqProto::GetAvatarFileName(MCONTACT hContact, wchar_t* pszDest, size_t cbLen)
+{
+ int tPathLen = mir_snwprintf(pszDest, cbLen, L"%s\\%S", VARSW(L"%miranda_avatarcache%"), m_szModuleName);
+
+ DWORD dwAttributes = GetFileAttributes(pszDest);
+ if (dwAttributes == 0xffffffff || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
+ CreateDirectoryTreeW(pszDest);
+
+ pszDest[tPathLen++] = '\\';
+
+ CMStringW wszFileName(getMStringW(hContact, "IconId"));
+ const wchar_t* szFileType = ProtoGetAvatarExtension(getByte(hContact, "AvatarType", PA_FORMAT_PNG));
+ mir_snwprintf(pszDest + tPathLen, MAX_PATH - tPathLen, L"%s%s", wszFileName.c_str(), szFileType);
+}
+
+INT_PTR __cdecl CIcqProto::GetAvatar(WPARAM wParam, LPARAM lParam)
+{
+ wchar_t *buf = (wchar_t*)wParam;
+ int size = (int)lParam;
+ if (buf == nullptr || size <= 0)
+ return -1;
+
+ GetAvatarFileName(0, buf, size);
+ return 0;
+}
+
+INT_PTR __cdecl CIcqProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam)
+{
+ switch (wParam) {
+ case AF_MAXSIZE:
+ ((POINT*)lParam)->x = -1;
+ ((POINT*)lParam)->y = -1;
+ return 0;
+
+ case AF_FORMATSUPPORTED: // nobody
+ return 1;
+
+ case AF_DELAYAFTERFAIL:
+ return 10 * 60 * 1000;
+
+ case AF_ENABLED:
+ case AF_FETCHIFPROTONOTVISIBLE:
+ case AF_FETCHIFCONTACTOFFLINE:
+ return 1;
+ }
+ return 0;
+}
+
+INT_PTR __cdecl CIcqProto::GetAvatarInfo(WPARAM, LPARAM lParam)
+{
+ PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*)lParam;
+
+ ptrW szIconId(getWStringA(pai->hContact, "IconId"));
+ if (szIconId == nullptr) {
+ debugLogA("No avatar");
+ return GAIR_NOAVATAR;
+ }
+
+ GetAvatarFileName(pai->hContact, pai->filename, _countof(pai->filename));
+ pai->format = getByte(pai->hContact, "AvatarType", 0);
+
+ if (::_waccess(pai->filename, 0) == 0)
+ return GAIR_SUCCESS;
+
+ debugLogA("No avatar");
+ return GAIR_NOAVATAR;
+}
+
+INT_PTR __cdecl CIcqProto::SetAvatar(WPARAM, LPARAM lParam)
+{
+ wchar_t* pwszFileName = (wchar_t*)lParam;
+
+ wchar_t wszOldName[MAX_PATH];
+ GetAvatarFileName(0, wszOldName, _countof(wszOldName));
+ _wremove(wszOldName);
+
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/expressions/upload");
+ pReq->m_szUrl.AppendFormat("?f=json&aimsid=%s&r=%s&type=largeBuddyIcon", ptrA(mir_urlEncode(m_aimsid.c_str())), pReq->m_reqId);
+
+ if (pwszFileName == nullptr)
+ delSetting("AvatarHash");
+ else {
+ int fileId = _wopen(pwszFileName, _O_RDONLY | _O_BINARY, _S_IREAD);
+ if (fileId < 0) {
+ delete pReq;
+ return 1;
+ }
+
+ unsigned dwSize = (unsigned)_filelengthi64(fileId);
+ char* pData = (char*)mir_alloc(dwSize);
+ if (pData == nullptr) {
+ _close(fileId);
+ delete pReq;
+ return 2;
+ }
+
+ _read(fileId, pData, dwSize);
+ _close(fileId);
+
+ pReq->pData = pData;
+ pReq->dataLength = dwSize;
+
+ int iAvatarType = ProtoGetBufferFormat(pData);
+ if (iAvatarType == PA_FORMAT_UNKNOWN) {
+ delete pReq;
+ delete pData;
+ return 3;
+ }
+
+ pReq->AddHeader("Content-Type", _T2A(ProtoGetAvatarMimeType(iAvatarType)));
+ }
+ Push(pReq);
+
+ return 0; // TODO
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CMStringA CIcqProto::GetUserId(MCONTACT hContact)
+{
+ if (isChatRoom(hContact))
+ return getMStringA(hContact, "ChatRoomID");
+
+ return CMStringA(FORMAT, "%d", getDword(hContact, DB_KEY_UIN));
+}
+
+bool IsChat(const CMStringW &aimid)
+{
+ return aimid.Right(11) == "@chat.agent";
+}
+
+int StatusFromString(const CMStringW &wszStatus)
+{
+ if (wszStatus == "online")
+ return ID_STATUS_ONLINE;
+ if (wszStatus == "n/a")
+ return ID_STATUS_NA;
+ if (wszStatus == "away")
+ return ID_STATUS_AWAY;
+ if (wszStatus == "occupied")
+ return ID_STATUS_OCCUPIED;
+ if (wszStatus == "dnd")
+ return ID_STATUS_DND;
+
+ return ID_STATUS_OFFLINE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+__int64 CIcqProto::getId(MCONTACT hContact, const char *szSetting)
+{
+ DBVARIANT dbv;
+ dbv.type = DBVT_BLOB;
+ if (db_get(hContact, m_szModuleName, szSetting, &dbv))
+ return 0;
+
+ __int64 result = (dbv.cpbVal == sizeof(__int64)) ? *(__int64*)dbv.pbVal : 0;
+ db_free(&dbv);
+ return result;
+}
+
+void CIcqProto::setId(MCONTACT hContact, const char *szSetting, __int64 iValue)
+{
+ __int64 oldVal = getId(hContact, szSetting);
+ if (oldVal != iValue)
+ db_set_blob(hContact, m_szModuleName, szSetting, &iValue, sizeof(iValue));
+}