From d91b68566522230f4daff25c8c2376fbd99ca640 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 7 Oct 2013 20:33:20 +0000 Subject: VK: avatars git-svn-id: http://svn.miranda-ng.org/main/trunk@6401 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/VKontakte/src/misc.cpp | 5 -- protocols/VKontakte/src/stdafx.h | 2 + protocols/VKontakte/src/vk_avatars.cpp | 99 +++++++++++++++++++++++++++++++ protocols/VKontakte/src/vk_proto.cpp | 3 +- protocols/VKontakte/src/vk_proto.h | 22 ++++--- protocols/VKontakte/src/vk_queue.cpp | 7 ++- protocols/VKontakte/src/vk_thread.cpp | 29 +++++++-- protocols/VKontakte/vk_10.vcxproj | 1 + protocols/VKontakte/vk_10.vcxproj.filters | 3 + protocols/VKontakte/vk_11.vcxproj | 1 + protocols/VKontakte/vk_11.vcxproj.filters | 3 + 11 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 protocols/VKontakte/src/vk_avatars.cpp diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index 6470a303ad..edb7739e6e 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -59,11 +59,6 @@ HANDLE CVkProto::FindUser(LPCSTR pUserid, bool bCreate) return hNewContact; } -int CVkProto::SetServerStatus(int iStatus) -{ - return 0; -} - LPCSTR findHeader(NETLIBHTTPREQUEST *pReq, LPCSTR szField) { for (int i=0; i < pReq->headersCount; i++) diff --git a/protocols/VKontakte/src/stdafx.h b/protocols/VKontakte/src/stdafx.h index 94469d2b79..5788e340a5 100644 --- a/protocols/VKontakte/src/stdafx.h +++ b/protocols/VKontakte/src/stdafx.h @@ -24,7 +24,9 @@ along with this program. If not, see . #include #include #include + #include +#include #include #include diff --git a/protocols/VKontakte/src/vk_avatars.cpp b/protocols/VKontakte/src/vk_avatars.cpp new file mode 100644 index 0000000000..6325516509 --- /dev/null +++ b/protocols/VKontakte/src/vk_avatars.cpp @@ -0,0 +1,99 @@ +/* +Copyright (C) 2013 Miranda NG Project (http://miranda-ng.org) + +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 version 2 +of the License. + +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, see . +*/ + +#include "stdafx.h" + +void CVkProto::OnReceiveAvatar(NETLIBHTTPREQUEST *reply, void* hContact) +{ + if (reply->resultCode != 200) + return; + + PROTO_AVATAR_INFORMATIONT AI = { sizeof(AI) }; + GetAvatarFileName(hContact, AI.filename, SIZEOF(AI.filename)); + AI.format = ProtoGetBufferFormat(reply->pData); + + FILE *out = _tfopen(AI.filename, _T("wb")); + if (out == NULL) { + ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, &AI, 0); + return; + } + + fwrite(reply->pData, 1, reply->dataLength, out); + fclose(out); + ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &AI, 0); +} + +INT_PTR CVkProto::SvcGetAvatarInfo(WPARAM wParam, LPARAM lParam) +{ + PROTO_AVATAR_INFORMATIONT* AI = (PROTO_AVATAR_INFORMATIONT*)lParam; + + ptrA szUrl( getStringA(AI->hContact, "AvatarUrl")); + if (szUrl == NULL) + return GAIR_NOAVATAR; + + TCHAR tszFileName[MAX_PATH]; + GetAvatarFileName(AI->hContact, tszFileName, SIZEOF(tszFileName)); + _tcsncpy(AI->filename, tszFileName, SIZEOF(AI->filename)); + + AI->format = ProtoGetAvatarFormat(AI->filename); + + if (::_taccess(AI->filename, 0) == 0) + return GAIR_SUCCESS; + + if ( IsOnline()) { + AsyncHttpRequest *pReq = new AsyncHttpRequest(); + pReq->szUrl = mir_strdup(szUrl); + pReq->pUserInfo = (char*)AI->hContact; + pReq->m_pFunc = &CVkProto::OnReceiveAvatar; + pReq->requestType = REQUEST_GET; + PushAsyncHttpRequest(pReq); + + Netlib_Logf(m_hNetlibUser, "Requested to read an avatar from '%s'", szUrl); + return GAIR_WAITFOR; + } + + Netlib_Logf(m_hNetlibUser, "No avatar"); + return GAIR_NOAVATAR; +} + +void CVkProto::GetAvatarFileName(HANDLE hContact, TCHAR* pszDest, size_t cbLen) +{ + size_t tPathLen; + TCHAR *path = (TCHAR*)_alloca(cbLen * sizeof(TCHAR)); + + if (m_hAvatarFolder == NULL || FoldersGetCustomPathT(m_hAvatarFolder, path, (int)cbLen, _T(""))) + tPathLen = mir_sntprintf(pszDest, cbLen, _T("%s\\%S"), (TCHAR*)VARST(_T("%miranda_avatarcache%")), m_szModuleName); + else + tPathLen = mir_sntprintf(pszDest, cbLen, _T("%s"), path); + + DWORD dwAttributes = GetFileAttributes(pszDest); + if (dwAttributes == 0xffffffff || (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) + CreateDirectoryTreeT(pszDest); + + pszDest[ tPathLen++ ] = '\\'; + + const TCHAR* szFileType = _T(".jpg"); + ptrT szUrl( getTStringA(hContact, "AvatarUrl")); + if (szUrl) { + TCHAR *p = _tcsrchr(szUrl, '.'); + if (p != NULL) + szFileType = p; + } + + ptrA id( getStringA(hContact, "ID")); + mir_sntprintf(pszDest + tPathLen, MAX_PATH - tPathLen, _T("%S%s"), id, szFileType); +} diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index a93c84d647..0b10090237 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -24,6 +24,7 @@ CVkProto::CVkProto(const char *szModuleName, const TCHAR *ptszUserName) : InitQueue(); CreateProtoService(PS_CREATEACCMGRUI, &CVkProto::SvcCreateAccMgrUI); + CreateProtoService(PS_GETAVATARINFOT, &CVkProto::SvcGetAvatarInfo); TCHAR descr[512]; mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName); @@ -36,7 +37,7 @@ CVkProto::CVkProto(const char *szModuleName, const TCHAR *ptszUserName) : m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); mir_sntprintf(descr, SIZEOF(descr), _T("%%miranda_avatarcache%%\\%s"), m_tszUserName); - hAvatarFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), m_szModuleName, descr, m_tszUserName); + m_hAvatarFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), m_szModuleName, descr, m_tszUserName); m_defaultGroup = getTStringA("ProtoGroup"); if (m_defaultGroup == NULL) diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index 71a9eecf1c..1f1db4c38b 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -16,7 +16,7 @@ along with this program. If not, see . */ struct CVkProto; -typedef void (CVkProto::*VK_REQUEST_HANDLER)(NETLIBHTTPREQUEST*); +typedef void (CVkProto::*VK_REQUEST_HANDLER)(NETLIBHTTPREQUEST*, void*); struct CVkProto : public PROTO { @@ -78,22 +78,26 @@ struct CVkProto : public PROTO int __cdecl OnOptionsInit(WPARAM, LPARAM); int __cdecl OnPreShutdown(WPARAM, LPARAM); - void OnOAuthAuthorize(NETLIBHTTPREQUEST*); - void OnReceiveMyInfo(NETLIBHTTPREQUEST*); + void OnOAuthAuthorize(NETLIBHTTPREQUEST*, void*); + void OnReceiveMyInfo(NETLIBHTTPREQUEST*, void*); + void OnReceiveAvatar(NETLIBHTTPREQUEST*, void*); //==== Services ====================================================================== INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); + INT_PTR __cdecl SvcGetAvatarInfo(WPARAM, LPARAM); //==== Misc ========================================================================== TCHAR* GetUserStoredPassword(void); void RetrieveUserInfo(LPCSTR szUserId); - void OnReceiveUserInfo(NETLIBHTTPREQUEST*); + void OnReceiveUserInfo(NETLIBHTTPREQUEST*, void*); void RetrieveFriends(); - void OnReceiveFriends(NETLIBHTTPREQUEST*); + void OnReceiveFriends(NETLIBHTTPREQUEST*, void*); + + int SetServerStatus(int); __forceinline bool IsOnline() const { return m_bOnline; } @@ -107,7 +111,7 @@ private: void Redirect(NETLIBHTTPREQUEST*); VK_REQUEST_HANDLER m_pFunc; - time_t m_expireTime; + void *pUserInfo; }; LIST m_arRequestsQueue; CRITICAL_SECTION m_csRequestsQueue; @@ -131,15 +135,17 @@ private: void OnLoggedOut(); void ShutdownSession(); + void GetAvatarFileName(HANDLE hContact, TCHAR* pszDest, size_t cbLen); + HANDLE FindUser(LPCSTR userid, bool bCreate = false); void SetAllContactStatuses(int status); - int SetServerStatus(int); bool m_bOnline; HANDLE m_hNetlibUser, m_hNetlibConn; - HANDLE hAvatarFolder; + HANDLE m_hAvatarFolder; ptrA m_szAccessToken, m_myUserId; ptrT m_defaultGroup; + UINT_PTR m_timer; }; diff --git a/protocols/VKontakte/src/vk_queue.cpp b/protocols/VKontakte/src/vk_queue.cpp index 47a146ffa9..e81bc61b0c 100644 --- a/protocols/VKontakte/src/vk_queue.cpp +++ b/protocols/VKontakte/src/vk_queue.cpp @@ -52,7 +52,8 @@ void CVkProto::ExecuteRequest(AsyncHttpRequest *pReq) { NETLIBHTTPREQUEST *reply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)pReq); if (reply != NULL) { - (this->*(pReq->m_pFunc))(reply); + if (pReq->m_pFunc != NULL) + (this->*(pReq->m_pFunc))(reply, pReq->pUserInfo); CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)reply); } delete pReq; @@ -80,6 +81,7 @@ bool CVkProto::PushAsyncHttpRequest(int iRequestType, LPCSTR szUrl, bool bSecure url.AppendChar('='); url += ptrA( mir_urlEncode(pParams[i].szValue)); } + pReq->nlc = m_hNetlibConn; } else { url = szUrl; @@ -94,8 +96,7 @@ bool CVkProto::PushAsyncHttpRequest(int iRequestType, LPCSTR szUrl, bool bSecure bool CVkProto::PushAsyncHttpRequest(AsyncHttpRequest *pReq, int iTimeout) { - pReq->nlc = m_hNetlibConn; - pReq->m_expireTime = time(0) + iTimeout; + pReq->timeout = iTimeout; { mir_cslock lck(m_csRequestsQueue); m_arRequestsQueue.insert(pReq); diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp index 92b0f4ce76..4ef6be5c89 100644 --- a/protocols/VKontakte/src/vk_thread.cpp +++ b/protocols/VKontakte/src/vk_thread.cpp @@ -36,6 +36,12 @@ void CVkProto::ConnectionFailed(int iReason) ShutdownSession(); } +static VOID CALLBACK TimerProc(HWND, UINT, UINT_PTR pObject, DWORD) +{ + CVkProto *ppro = (CVkProto*)pObject; + ppro->SetServerStatus(ppro->m_iStatus); +} + void CVkProto::OnLoggedIn() { m_bOnline = true; @@ -43,6 +49,10 @@ void CVkProto::OnLoggedIn() ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, m_iDesiredStatus); m_iStatus = m_iDesiredStatus; + // initialize online timer + SetServerStatus(m_iStatus); + m_timer = SetTimer(NULL, (UINT_PTR)this, 870000, TimerProc); + HttpParam param = { "access_token", m_szAccessToken }; PushAsyncHttpRequest(REQUEST_GET, "/method/getUserInfoEx.json", true, &CVkProto::OnReceiveMyInfo, 1, ¶m); @@ -56,6 +66,17 @@ void CVkProto::OnLoggedOut() ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)m_iStatus, ID_STATUS_OFFLINE); m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; + + KillTimer(NULL, m_timer); +} + +int CVkProto::SetServerStatus(int iStatus) +{ + if (iStatus != ID_STATUS_OFFLINE && iStatus != ID_STATUS_INVISIBLE) { + HttpParam param = { "access_token", m_szAccessToken }; + PushAsyncHttpRequest(REQUEST_GET, "/method/account.setOnline.json", true, NULL, 1, ¶m); + } + return 0; } ///////////////////////////////////////////////////////////////////////////////////////// @@ -64,7 +85,7 @@ extern CMStringA loginCookie; static char VK_TOKEN_BEG[] = "access_token="; -void CVkProto::OnOAuthAuthorize(NETLIBHTTPREQUEST *reply) +void CVkProto::OnOAuthAuthorize(NETLIBHTTPREQUEST *reply, void*) { if (reply->resultCode == 302) { // manual redirect LPCSTR pszLocation = findHeader(reply, "Location"); @@ -143,7 +164,7 @@ LBL_NoForm: ///////////////////////////////////////////////////////////////////////////////////////// -void CVkProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *reply) +void CVkProto::OnReceiveMyInfo(NETLIBHTTPREQUEST *reply, void*) { Netlib_Logf(m_hNetlibUser, "CVkProto::OnReceiveMyInfo %d", reply->resultCode); if (reply->resultCode != 200) { @@ -200,7 +221,7 @@ void CVkProto::RetrieveUserInfo(LPCSTR szUserId) PushAsyncHttpRequest(REQUEST_GET, "/method/getProfiles.json", true, &CVkProto::OnReceiveUserInfo, SIZEOF(params), params); } -void CVkProto::OnReceiveUserInfo(NETLIBHTTPREQUEST *reply) +void CVkProto::OnReceiveUserInfo(NETLIBHTTPREQUEST *reply, void*) { Netlib_Logf(m_hNetlibUser, "CVkProto::OnReceiveUserInfo %d", reply->resultCode); if (reply->resultCode != 200) @@ -257,7 +278,7 @@ void CVkProto::RetrieveFriends() PushAsyncHttpRequest(REQUEST_GET, "/method/friends.get.json", true, &CVkProto::OnReceiveFriends, SIZEOF(params), params); } -void CVkProto::OnReceiveFriends(NETLIBHTTPREQUEST *reply) +void CVkProto::OnReceiveFriends(NETLIBHTTPREQUEST *reply, void*) { Netlib_Logf(m_hNetlibUser, "CVkProto::OnReceiveFriends %d", reply->resultCode); if (reply->resultCode != 200) diff --git a/protocols/VKontakte/vk_10.vcxproj b/protocols/VKontakte/vk_10.vcxproj index 6d68d67a49..140b1141f1 100644 --- a/protocols/VKontakte/vk_10.vcxproj +++ b/protocols/VKontakte/vk_10.vcxproj @@ -180,6 +180,7 @@ Create Create + diff --git a/protocols/VKontakte/vk_10.vcxproj.filters b/protocols/VKontakte/vk_10.vcxproj.filters index 60d0e438ca..e7ac9a423b 100644 --- a/protocols/VKontakte/vk_10.vcxproj.filters +++ b/protocols/VKontakte/vk_10.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + diff --git a/protocols/VKontakte/vk_11.vcxproj b/protocols/VKontakte/vk_11.vcxproj index 1770c97512..3e30504c57 100644 --- a/protocols/VKontakte/vk_11.vcxproj +++ b/protocols/VKontakte/vk_11.vcxproj @@ -183,6 +183,7 @@ Create Create + diff --git a/protocols/VKontakte/vk_11.vcxproj.filters b/protocols/VKontakte/vk_11.vcxproj.filters index 408fc79322..6a23ec20c2 100644 --- a/protocols/VKontakte/vk_11.vcxproj.filters +++ b/protocols/VKontakte/vk_11.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + -- cgit v1.2.3