From c76cb483df20f8058deedcf5500b20ea5af98cf6 Mon Sep 17 00:00:00 2001 From: Sergey Bolhovskoy Date: Mon, 7 Sep 2015 15:30:02 +0000 Subject: VKontakte: code refactoring fix memory leaks and corruption fix for support MessageState version bump git-svn-id: http://svn.miranda-ng.org/main/trunk@15294 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/VKontakte/src/misc.cpp | 125 +++-------------- protocols/VKontakte/src/stdafx.h | 1 + protocols/VKontakte/src/version.h | 2 +- protocols/VKontakte/src/vk.h | 14 +- protocols/VKontakte/src/vk_avatars.cpp | 17 ++- protocols/VKontakte/src/vk_chats.cpp | 6 - protocols/VKontakte/src/vk_files.cpp | 151 +++++++++----------- protocols/VKontakte/src/vk_history.cpp | 18 ++- protocols/VKontakte/src/vk_messages.cpp | 28 ++-- protocols/VKontakte/src/vk_pollserver.cpp | 6 +- protocols/VKontakte/src/vk_proto.cpp | 9 +- protocols/VKontakte/src/vk_proto.h | 215 +--------------------------- protocols/VKontakte/src/vk_search.cpp | 32 ++--- protocols/VKontakte/src/vk_struct.cpp | 156 +++++++++++++++++++++ protocols/VKontakte/src/vk_struct.h | 225 ++++++++++++++++++++++++++++++ protocols/VKontakte/src/vk_thread.cpp | 8 +- 16 files changed, 561 insertions(+), 452 deletions(-) create mode 100644 protocols/VKontakte/src/vk_struct.cpp create mode 100644 protocols/VKontakte/src/vk_struct.h (limited to 'protocols') diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index b5c3238027..4f24f82615 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -131,84 +131,6 @@ char* ExpUrlEncode(const char *szUrl, bool strict) return szOutput; } -///////////////////////////////////////////////////////////////////////////////////////// - -ULONG AsyncHttpRequest::m_reqCount = 0; - -AsyncHttpRequest::AsyncHttpRequest() -{ - cbSize = sizeof(NETLIBHTTPREQUEST); - m_bApiReq = true; - AddHeader("Connection", "keep-alive"); - AddHeader("Accept-Encoding", "booo"); - pUserInfo = NULL; - m_iRetry = MAX_RETRIES; - bNeedsRestart = false; - bIsMainConn = false; - m_pFunc = NULL; - bExpUrlEncode = false; - m_reqNum = ::InterlockedIncrement(&m_reqCount); - m_priority = rpLow; -} - -AsyncHttpRequest::AsyncHttpRequest(CVkProto *ppro, int iRequestType, LPCSTR _url, bool bSecure, VK_REQUEST_HANDLER pFunc, RequestPriority rpPriority) -{ - cbSize = sizeof(NETLIBHTTPREQUEST); - m_bApiReq = true; - bIsMainConn = false; - bExpUrlEncode = ppro->m_bUseNonStandardUrlEncode; - AddHeader("Connection", "keep-alive"); - AddHeader("Accept-Encoding", "booo"); - - flags = VK_NODUMPHEADERS | NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT; - if (bSecure) - flags |= NLHRF_SSL; - - if (*_url == '/') { // relative url leads to a site - m_szUrl = ((bSecure) ? "https://" : "http://") + CMStringA("api.vk.com"); - m_szUrl += _url; - bIsMainConn = true; - } - else m_szUrl = _url; - - if (bSecure) - this << CHAR_PARAM("access_token", ppro->m_szAccessToken); - - requestType = iRequestType; - m_pFunc = pFunc; - pUserInfo = NULL; - m_iRetry = MAX_RETRIES; - bNeedsRestart = false; - m_reqNum = ::InterlockedIncrement(&m_reqCount); - m_priority = rpPriority; -} - -AsyncHttpRequest::~AsyncHttpRequest() -{ - for (int i = 0; i < headersCount; i++) { - mir_free(headers[i].szName); - mir_free(headers[i].szValue); - } - mir_free(headers); - mir_free(pData); -} - -void AsyncHttpRequest::AddHeader(LPCSTR szName, LPCSTR szValue) -{ - headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1)); - headers[headersCount].szName = mir_strdup(szName); - headers[headersCount].szValue = mir_strdup(szValue); - headersCount++; -} - -void AsyncHttpRequest::Redirect(NETLIBHTTPREQUEST *nhr) -{ - for (int i = 0; i < nhr->headersCount; i++) { - LPCSTR szValue = nhr->headers[i].szValue; - if (!_stricmp(nhr->headers[i].szName, "Location")) - m_szUrl = szValue; - } -} ///////////////////////////////////////////////////////////////////////////////////////// @@ -307,8 +229,10 @@ JSONNode& CVkProto::CheckJsonResponse(AsyncHttpRequest *pReq, NETLIBHTTPREQUEST bool CVkProto::CheckJsonResult(AsyncHttpRequest *pReq, const JSONNode &jnNode) { debugLogA("CVkProto::CheckJsonResult"); - if (!jnNode) + if (!jnNode) { + pReq->m_iErrorCode = VKERR_NO_JSONNODE; return false; + } const JSONNode &jnError = jnNode["error"]; const JSONNode &jnErrorCode = jnError["error_code"]; @@ -316,11 +240,9 @@ bool CVkProto::CheckJsonResult(AsyncHttpRequest *pReq, const JSONNode &jnNode) if (!jnError || !jnErrorCode) return true; - int iErrorCode = jnErrorCode.as_int(); - debugLogA("CVkProto::CheckJsonResult %d", iErrorCode); - CVkFileUploadParam * fup = (CVkFileUploadParam *)pReq->pUserInfo; - CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; - switch (iErrorCode) { + pReq->m_iErrorCode = jnErrorCode.as_int(); + debugLogA("CVkProto::CheckJsonResult %d", pReq->m_iErrorCode); + switch (pReq->m_iErrorCode) { case VKERR_AUTHORIZATION_FAILED: ConnectionFailed(LOGINERR_WRONGPASSWORD); break; @@ -338,17 +260,6 @@ bool CVkProto::CheckJsonResult(AsyncHttpRequest *pReq, const JSONNode &jnNode) case VKERR_CAPTCHA_NEEDED: ApplyCaptcha(pReq, jnError); break; - case VKERR_COULD_NOT_SAVE_FILE: - case VKERR_INVALID_ALBUM_ID: - case VKERR_INVALID_SERVER: - case VKERR_INVALID_HASH: - case VKERR_INVALID_AUDIO: - case VKERR_AUDIO_DEL_COPYRIGHT: - case VKERR_INVALID_FILENAME: - case VKERR_INVALID_FILESIZE: - if (fup) - fup->iErrorCode = iErrorCode; - break; case VKERR_FLOOD_CONTROL: pReq->m_iRetry = 0; // fall through @@ -362,26 +273,34 @@ bool CVkProto::CheckJsonResult(AsyncHttpRequest *pReq, const JSONNode &jnNode) pReq->m_iRetry--; } else { - CMString msg(FORMAT, TranslateT("Error %d. Data will not be sent or received."), iErrorCode); + CMString msg(FORMAT, TranslateT("Error %d. Data will not be sent or received."), pReq->m_iErrorCode); MsgPopup(NULL, msg, TranslateT("Error"), true); debugLogA("CVkProto::CheckJsonResult SendError"); } break; - case VKERR_HIMSELF_AS_FRIEND: - case VKERR_YOU_ON_BLACKLIST: - case VKERR_USER_ON_BLACKLIST: - if (param) - param->iCount = iErrorCode; - break; + case VKERR_INVALID_PARAMETERS: MsgPopup(NULL, TranslateT("One of the parameters specified was missing or invalid"), TranslateT("Error"), true); break; case VKERR_ACC_WALL_POST_DENIED: MsgPopup(NULL, TranslateT("Access to adding post denied"), TranslateT("Error"), true); break; + case VKERR_COULD_NOT_SAVE_FILE: + case VKERR_INVALID_ALBUM_ID: + case VKERR_INVALID_SERVER: + case VKERR_INVALID_HASH: + case VKERR_INVALID_AUDIO: + case VKERR_AUDIO_DEL_COPYRIGHT: + case VKERR_INVALID_FILENAME: + case VKERR_INVALID_FILESIZE: + case VKERR_HIMSELF_AS_FRIEND: + case VKERR_YOU_ON_BLACKLIST: + case VKERR_USER_ON_BLACKLIST: + // See CVkProto::SendFileFiled + break; } - return iErrorCode == 0; + return pReq->m_iErrorCode == 0; } void CVkProto::OnReceiveSmth(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) diff --git a/protocols/VKontakte/src/stdafx.h b/protocols/VKontakte/src/stdafx.h index 8aaa81e389..b70f946812 100644 --- a/protocols/VKontakte/src/stdafx.h +++ b/protocols/VKontakte/src/stdafx.h @@ -66,4 +66,5 @@ along with this program. If not, see . #include "resource.h" #include "vk.h" +#include "vk_struct.h" #include "vk_proto.h" diff --git a/protocols/VKontakte/src/version.h b/protocols/VKontakte/src/version.h index d3926c8e38..590fb86f7c 100644 --- a/protocols/VKontakte/src/version.h +++ b/protocols/VKontakte/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 1 #define __RELEASE_NUM 1 -#define __BUILD_NUM 13 +#define __BUILD_NUM 14 #include diff --git a/protocols/VKontakte/src/vk.h b/protocols/VKontakte/src/vk.h index f131ca8b35..83e9d0eb7e 100644 --- a/protocols/VKontakte/src/vk.h +++ b/protocols/VKontakte/src/vk.h @@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#pragma once + #define VK_APP_ID 3917910 // LongPool servers events @@ -45,6 +47,8 @@ along with this program. If not, see . #define VKFLAG_MSGMEDIA 512 // сообщение содержит медиаконтент // Errors +#define VKERR_NO_JSONNODE -2 // No JSON Node in server reply +#define VKERR_OFFLINE -1 // Proto is offline #define VKERR_NOERRORS 0 // No error #define VKERR_UNKNOWN 1 // Unknown error occurred #define VKERR_TOO_MANY_REQ_PER_SEC 6 // Too many requests per second @@ -66,6 +70,14 @@ along with this program. If not, see . #define VKERR_AUDIO_DEL_COPYRIGHT 270 // The audio file was removed by the copyright holder and cannot be reuploaded. #define VKERR_INVALID_FILENAME 301 // Invalid filename #define VKERR_INVALID_FILESIZE 302 // Invalid filesize +// File upload custom error +#define VKERR_FILE_NOT_EXIST 10100 // File not exist +#define VKERR_FTYPE_NOT_SUPPORTED 10101 // File type not supported +#define VKERR_ERR_OPEN_FILE 10103 // Error open file +#define VKERR_ERR_READ_FILE 10104 // Error read file +#define VKERR_FILE_NOT_UPLOADED 10105 // Error upload file +#define VKERR_INVALID_URL 10106 // Upload server return empty url +#define VKERR_INVALID_USER 10107 // Invalid or unknow recepient user ID #define VK_API_VER "5.37" #define VER_API CHAR_PARAM("v", VK_API_VER) @@ -92,4 +104,4 @@ HANDLE GetIconHandle(int iCommand); char* ExpUrlEncode(const char *szUrl, bool strict = false); bool IsEmpty(LPCTSTR str); -bool IsEmpty(LPCSTR str); \ No newline at end of file +bool IsEmpty(LPCSTR str); diff --git a/protocols/VKontakte/src/vk_avatars.cpp b/protocols/VKontakte/src/vk_avatars.cpp index 9ce6447f36..11386736ce 100644 --- a/protocols/VKontakte/src/vk_avatars.cpp +++ b/protocols/VKontakte/src/vk_avatars.cpp @@ -19,23 +19,28 @@ along with this program. If not, see . void CVkProto::OnReceiveAvatar(NETLIBHTTPREQUEST *reply, AsyncHttpRequest* pReq) { - if (reply->resultCode != 200) + if (reply->resultCode != 200 || !pReq->pUserInfo) return; PROTO_AVATAR_INFORMATION ai = { 0 }; - GetAvatarFileName((UINT_PTR)pReq->pUserInfo, ai.filename, _countof(ai.filename)); + CVkSendMsgParam * param = (CVkSendMsgParam *)pReq->pUserInfo; + GetAvatarFileName(param->hContact, ai.filename, _countof(ai.filename)); ai.format = ProtoGetBufferFormat(reply->pData); FILE *out = _tfopen(ai.filename, _T("wb")); if (out == NULL) { - ProtoBroadcastAck((UINT_PTR)pReq->pUserInfo, ACKTYPE_AVATAR, ACKRESULT_FAILED, &ai); + ProtoBroadcastAck(param->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, &ai); + delete param; + pReq->pUserInfo = NULL; return; } fwrite(reply->pData, 1, reply->dataLength, out); fclose(out); - setByte((UINT_PTR)pReq->pUserInfo, "NeedNewAvatar", 0); - ProtoBroadcastAck((UINT_PTR)pReq->pUserInfo, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &ai); + setByte(param->hContact, "NeedNewAvatar", 0); + ProtoBroadcastAck(param->hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, &ai); + delete param; + pReq->pUserInfo = NULL; } INT_PTR CVkProto::SvcGetAvatarCaps(WPARAM wParam, LPARAM lParam) @@ -93,7 +98,7 @@ INT_PTR CVkProto::SvcGetAvatarInfo(WPARAM, LPARAM lParam) AsyncHttpRequest *pReq = new AsyncHttpRequest(); pReq->flags = NLHRF_NODUMP | NLHRF_REDIRECT; pReq->m_szUrl = szUrl; - pReq->pUserInfo = (char*)pai->hContact; + pReq->pUserInfo = new CVkSendMsgParam(pai->hContact); pReq->m_pFunc = &CVkProto::OnReceiveAvatar; pReq->requestType = REQUEST_GET; pReq->m_bApiReq = false; diff --git a/protocols/VKontakte/src/vk_chats.cpp b/protocols/VKontakte/src/vk_chats.cpp index f4408c3ea4..1d3c56d273 100644 --- a/protocols/VKontakte/src/vk_chats.cpp +++ b/protocols/VKontakte/src/vk_chats.cpp @@ -441,12 +441,6 @@ CVkChatInfo* CVkProto::GetChatById(LPCTSTR ptszId) return NULL; } -CVkChatUser* CVkChatInfo::GetUserById(LPCTSTR ptszId) -{ - int user_id = _ttoi(ptszId); - return m_users.find((CVkChatUser*)&user_id); -} - ///////////////////////////////////////////////////////////////////////////////////////// void CVkProto::SetChatStatus(MCONTACT hContact, int iStatus) diff --git a/protocols/VKontakte/src/vk_files.cpp b/protocols/VKontakte/src/vk_files.cpp index aa32117e61..7b39fb8dea 100644 --- a/protocols/VKontakte/src/vk_files.cpp +++ b/protocols/VKontakte/src/vk_files.cpp @@ -17,56 +17,6 @@ along with this program. If not, see . #include "stdafx.h" -CVkFileUploadParam::CVkFileUploadParam(MCONTACT _hContact, const TCHAR* _desc, TCHAR** _files) : - hContact(_hContact), - filetype(typeInvalid), - atr(NULL), - fname(NULL), - iErrorCode(0) -{ - Desc = mir_tstrdup(_desc); - FileName = mir_tstrdup(_files[0]); -} - -CVkFileUploadParam::~CVkFileUploadParam() -{ - mir_free(Desc); - mir_free(FileName); - mir_free(atr); - mir_free(fname); -} - -CVkFileUploadParam::VKFileType CVkFileUploadParam::GetType() -{ - if (filetype != typeInvalid) - return filetype; - - TCHAR img[] = _T(".jpg .jpeg .png .bmp"); - TCHAR audio[] = _T(".mp3"); - - TCHAR DRIVE[3], DIR[256], FNAME[256], EXT[256]; - _tsplitpath(FileName, DRIVE, DIR, FNAME, EXT); - - T2Utf pszFNAME(FNAME), pszEXT(EXT); - CMStringA fn(FORMAT, "%s%s", pszFNAME, pszEXT); - fname = mir_strdup(fn); - - if (tlstrstr(img, EXT)) { - filetype = CVkFileUploadParam::typeImg; - atr = mir_strdup("photo"); - } - else if (tlstrstr(audio, EXT)) { - filetype = CVkFileUploadParam::typeAudio; - atr = mir_strdup("file"); - } - else { - filetype = CVkFileUploadParam::typeDoc; - atr = mir_strdup("file"); - } - - return filetype; -} - HANDLE CVkProto::SendFile(MCONTACT hContact, const TCHAR *desc, TCHAR **files) { debugLogA("CVkProto::SendFile"); @@ -79,12 +29,37 @@ HANDLE CVkProto::SendFile(MCONTACT hContact, const TCHAR *desc, TCHAR **files) return (HANDLE)fup; } -void CVkProto::SendFileFiled(CVkFileUploadParam *fup, TCHAR *reason) +void CVkProto::SendFileFiled(CVkFileUploadParam *fup, int ErrorCode) { - debugLog(_T("CVkProto::SendFileFiled <%s> Error code <%d>"), reason, fup->iErrorCode); CMString tszError; - int iResult = ACKRESULT_FAILED; - switch (fup->iErrorCode) { + switch (ErrorCode) { + case VKERR_OFFLINE: + tszError = TranslateT("Protocol is offline"); + break; + case VKERR_FILE_NOT_EXIST: + tszError = TranslateT("File not exist"); + break; + case VKERR_FTYPE_NOT_SUPPORTED: + tszError = TranslateT("File type not supported"); + break; + case VKERR_ERR_OPEN_FILE: + tszError = TranslateT("Error open file"); + break; + case VKERR_ERR_READ_FILE: + tszError = TranslateT("Error read file"); + break; + case VKERR_FILE_NOT_UPLOADED: + tszError = TranslateT("Error upload file"); + break; + case VKERR_INVALID_URL: + tszError = TranslateT("Upload server return empty url"); + break; + case VKERR_INVALID_USER: + tszError = TranslateT("Invalid or unknow recepient user ID"); + break; + case VKERR_INVALID_PARAMETERS: + tszError = TranslateT("One of the parameters specified was missing or invalid"); + break; case VKERR_COULD_NOT_SAVE_FILE: tszError = TranslateT("Couldn't save file"); break; @@ -101,8 +76,7 @@ void CVkProto::SendFileFiled(CVkFileUploadParam *fup, TCHAR *reason) tszError = TranslateT("Invalid audio"); break; case VKERR_AUDIO_DEL_COPYRIGHT: - tszError = TranslateT("The audio file was removed by the copyright holder and cannot be reuploaded"); - iResult = ACKRESULT_DENIED; + tszError = TranslateT("The audio file was removed by the copyright holder and cannot be reuploaded"); break; case VKERR_INVALID_FILENAME: tszError = TranslateT("Invalid filename"); @@ -113,7 +87,8 @@ void CVkProto::SendFileFiled(CVkFileUploadParam *fup, TCHAR *reason) default: tszError = TranslateT("Unknown error occurred"); } - ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, iResult, (HANDLE)fup); + ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ErrorCode== VKERR_AUDIO_DEL_COPYRIGHT ? ACKRESULT_DENIED : ACKRESULT_FAILED, (HANDLE)fup); + debugLog(_T("CVkProto::SendFileFiled error code = %d (%s)"), ErrorCode, tszError); MsgPopup(NULL, tszError, TranslateT("File upload error"), true); delete fup; } @@ -123,11 +98,11 @@ void CVkProto::SendFileThread(void *p) CVkFileUploadParam *fup = (CVkFileUploadParam *)p; debugLog(_T("CVkProto::SendFileThread %d %s"), fup->GetType(), fup->fileName()); if (!IsOnline()) { - SendFileFiled(fup, _T("NotOnline")); + SendFileFiled(fup, VKERR_OFFLINE); return; } if (!fup->IsAccess()) { - SendFileFiled(fup, _T("FileIsNotAccess")); + SendFileFiled(fup, VKERR_FILE_NOT_EXIST); return; } @@ -148,7 +123,7 @@ void CVkProto::SendFileThread(void *p) << VER_API; break; default: - SendFileFiled(fup, _T("FileTypeNotSupported")); + SendFileFiled(fup, VKERR_FTYPE_NOT_SUPPORTED); return; } pReq->pUserInfo = p; @@ -159,32 +134,32 @@ void CVkProto::OnReciveUploadServer(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * { CVkFileUploadParam *fup = (CVkFileUploadParam *)pReq->pUserInfo; if (!IsOnline()) { - SendFileFiled(fup, _T("NotOnline")); + SendFileFiled(fup, VKERR_OFFLINE); return; } debugLogA("CVkProto::OnReciveUploadServer %d", reply->resultCode); if (reply->resultCode != 200) { - SendFileFiled(fup, _T("NotUploadServer")); + SendFileFiled(fup, VKERR_INVALID_SERVER); return; } JSONNode jnRoot; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); - if (!jnResponse) { - SendFileFiled(fup); + if (!jnResponse || pReq->m_iErrorCode) { + SendFileFiled(fup, pReq->m_iErrorCode); return; } - CMStringA uri = jnResponse["upload_url"].as_mstring(); + CMStringA uri(jnResponse["upload_url"].as_mstring()); if (uri.IsEmpty()) { - SendFileFiled(fup); + SendFileFiled(fup, VKERR_INVALID_URL); return; } FILE *pFile = _tfopen(fup->FileName, _T("rb")); if (pFile == NULL) { - SendFileFiled(fup, _T("ErrorOpenFile")); + SendFileFiled(fup, VKERR_ERR_OPEN_FILE); return; } @@ -192,7 +167,7 @@ void CVkProto::OnReciveUploadServer(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * long iFileLen = ftell(pFile); //FileSize if (iFileLen < 1) { fclose(pFile); - SendFileFiled(fup, _T("ErrorReadFile")); + SendFileFiled(fup, VKERR_ERR_READ_FILE); return; } fseek(pFile, 0, SEEK_SET); @@ -238,7 +213,7 @@ void CVkProto::OnReciveUploadServer(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * fclose(pFile); if (lBytes != iFileLen) { - SendFileFiled(fup, _T("ErrorReadFile")); + SendFileFiled(fup, VKERR_ERR_READ_FILE); mir_free(pUploadReq->pData); delete pUploadReq; return; @@ -257,19 +232,29 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { CVkFileUploadParam *fup = (CVkFileUploadParam *)pReq->pUserInfo; if (!IsOnline()) { - SendFileFiled(fup, _T("NotOnline")); + SendFileFiled(fup, VKERR_OFFLINE); return; } debugLogA("CVkProto::OnReciveUploadServer %d", reply->resultCode); if (reply->resultCode != 200) { - SendFileFiled(fup); + SendFileFiled(fup, VKERR_FILE_NOT_UPLOADED); return; } JSONNode jnRoot; CheckJsonResponse(pReq, reply, jnRoot); + if (pReq->m_iErrorCode) { + SendFileFiled(fup, pReq->m_iErrorCode); + return; + } + + if (!jnRoot["server"] || !jnRoot["hash"]) { + SendFileFiled(fup, VKERR_INVALID_PARAMETERS); + return; + } + CMString server(jnRoot["server"].as_mstring()); CMString hash(jnRoot["hash"].as_mstring()); CMString upload; @@ -282,7 +267,7 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) case CVkFileUploadParam::typeImg: upload = jnRoot["photo"].as_mstring(); if (upload == _T("[]")) { - SendFileFiled(fup, _T("NotUpload Photo")); + SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/photos.saveMessagesPhoto.json", true, &CVkProto::OnReciveUploadFile) @@ -294,7 +279,7 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) case CVkFileUploadParam::typeAudio: upload = jnRoot["audio"].as_mstring(); if (upload == _T("[]")) { - SendFileFiled(fup, _T("NotUpload Audio")); + SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/audio.save.json", true, &CVkProto::OnReciveUploadFile) @@ -306,7 +291,7 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) case CVkFileUploadParam::typeDoc: upload = jnRoot["file"].as_mstring(); if (upload.IsEmpty()) { - SendFileFiled(fup, _T("NotUpload Doc")); + SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/docs.save.json", true, &CVkProto::OnReciveUploadFile) @@ -315,7 +300,7 @@ void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) << VER_API; break; default: - SendFileFiled(fup); + SendFileFiled(fup, VKERR_FTYPE_NOT_SUPPORTED); return; } @@ -327,27 +312,27 @@ void CVkProto::OnReciveUploadFile(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pR { CVkFileUploadParam *fup = (CVkFileUploadParam *)pReq->pUserInfo; if (!IsOnline()) { - SendFileFiled(fup, _T("NotOnline")); + SendFileFiled(fup, VKERR_OFFLINE); return; } debugLogA("CVkProto::OnReciveUploadFile %d", reply->resultCode); if (reply->resultCode != 200) { - SendFileFiled(fup); + SendFileFiled(fup, VKERR_FILE_NOT_UPLOADED); return; } JSONNode jnRoot; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); - if (!jnResponse) { - SendFileFiled(fup); + if (!jnResponse || pReq->m_iErrorCode) { + SendFileFiled(fup, pReq->m_iErrorCode); return; } int id = fup->GetType() == CVkFileUploadParam::typeAudio ? jnResponse["id"].as_int() : (*jnResponse.begin())["id"].as_int(); int owner_id = fup->GetType() == CVkFileUploadParam::typeAudio ? jnResponse["owner_id"].as_int() : (*jnResponse.begin())["owner_id"].as_int(); if ((id == 0) || (owner_id == 0)) { - SendFileFiled(fup); + SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } @@ -364,13 +349,13 @@ void CVkProto::OnReciveUploadFile(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pR Attachment.AppendFormat(_T("doc%d_%d"), owner_id, id); break; default: - SendFileFiled(fup); + SendFileFiled(fup, VKERR_FTYPE_NOT_SUPPORTED); return; } LONG userID = getDword(fup->hContact, "ID", -1); if (userID == -1 || userID == VK_FEED_USER) { - SendFileFiled(fup); + SendFileFiled(fup, VKERR_INVALID_USER); return; } @@ -380,7 +365,7 @@ void CVkProto::OnReciveUploadFile(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pR << TCHAR_PARAM("attachment", Attachment) << VER_API; pMsgReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); - pMsgReq->pUserInfo = new CVkSendMsgParam(fup->hContact, -1, (INT_PTR)pReq->pUserInfo); + pMsgReq->pUserInfo = new CVkSendMsgParam(fup->hContact, fup); Push(pMsgReq); } \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_history.cpp b/protocols/VKontakte/src/vk_history.cpp index b0fd49772b..1e6e1736ad 100644 --- a/protocols/VKontakte/src/vk_history.cpp +++ b/protocols/VKontakte/src/vk_history.cpp @@ -169,15 +169,20 @@ void CVkProto::GetHistoryDlg(MCONTACT hContact, int iLastMsg) void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { debugLogA("CVkProto::OnReceiveHistoryMessages %d", reply->resultCode); - if (reply->resultCode != 200) + if (reply->resultCode != 200 || !pReq->pUserInfo) return; JSONNode jnRoot; + CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); - if (!jnResponse) + if (!jnResponse) { + if (!pReq->bNeedsRestart || m_bTerminated) { + delete param; + pReq->pUserInfo = NULL; + } return; - - CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; + } + int iTime = jnResponse["datetime"].as_int(); const JSONNode &jnMsgs = jnResponse["items"]; const JSONNode &jnFUsers = jnResponse["fwd_users"]; @@ -249,5 +254,8 @@ void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpReque if (count == iRCount && once == 0) GetServerHistory(param->hContact, param->iCount + count, iRCount, iTime, param->iMsgID); - delete param; + if (!pReq->bNeedsRestart || m_bTerminated) { + delete param; + pReq->pUserInfo = NULL; + } } \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_messages.cpp b/protocols/VKontakte/src/vk_messages.cpp index 39c1d07f23..3e26356f61 100644 --- a/protocols/VKontakte/src/vk_messages.cpp +++ b/protocols/VKontakte/src/vk_messages.cpp @@ -31,9 +31,9 @@ int CVkProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre) void CVkProto::SendMsgAck(void *param) { debugLogA("CVkProto::SendMsgAck"); - TFakeAckParams *ack = (TFakeAckParams*)param; + CVkSendMsgParam *ack = (CVkSendMsgParam *)param; Sleep(100); - ProtoBroadcastAck(ack->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ack->msgid); + ProtoBroadcastAck(ack->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ack->iMsgID); delete ack; } @@ -44,7 +44,7 @@ int CVkProto::SendMsg(MCONTACT hContact, int, const char *szMsg) return 0; LONG userID = getDword(hContact, "ID", -1); if (userID == -1 || userID == VK_FEED_USER) { - ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, 0)); + ForkThread(&CVkProto::SendMsgAck, new CVkSendMsgParam(hContact)); return 0; } @@ -67,7 +67,7 @@ int CVkProto::SendMsg(MCONTACT hContact, int, const char *szMsg) Push(pReq); if (!m_bServerDelivery) - ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, msgId)); + ForkThread(&CVkProto::SendMsgAck, new CVkSendMsgParam(hContact, msgId)); if (retMsg) { Sleep(330); @@ -83,7 +83,7 @@ void CVkProto::OnSendMessage(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) debugLogA("CVkProto::OnSendMessage failed! (pUserInfo == NULL)"); return; } - CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; + CVkSendMsgParam *param = (CVkSendMsgParam *)pReq->pUserInfo; debugLogA("CVkProto::OnSendMessage %d", reply->resultCode); if (reply->resultCode == 200) { @@ -98,24 +98,26 @@ void CVkProto::OnSendMessage(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) if (param->iMsgID != -1) m_sendIds.insert((HANDLE)mid); + if (mid > getDword(param->hContact, "lastmsgid")) setDword(param->hContact, "lastmsgid", mid); + if (m_iMarkMessageReadOn >= markOnReply) MarkMessagesRead(param->hContact); + iResult = ACKRESULT_SUCCESS; } } - if (param->iMsgID == -1) { - CVkFileUploadParam *fup = (CVkFileUploadParam *)param->iCount; - ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, iResult, (HANDLE)fup); - if (!pReq->bNeedsRestart) - delete fup; - return; + if (param->pFUP) { + ProtoBroadcastAck(param->hContact, ACKTYPE_FILE, iResult, (HANDLE)(param->pFUP)); + if (!pReq->bNeedsRestart || m_bTerminated) + delete param->pFUP; } else if (m_bServerDelivery) - ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, iResult, HANDLE(param->iMsgID)); - if (!pReq->bNeedsRestart) { + ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, iResult, (HANDLE)(param->iMsgID)); + + if (!pReq->bNeedsRestart || m_bTerminated) { delete param; pReq->pUserInfo = NULL; } diff --git a/protocols/VKontakte/src/vk_pollserver.cpp b/protocols/VKontakte/src/vk_pollserver.cpp index e10d36c296..fa0617f874 100644 --- a/protocols/VKontakte/src/vk_pollserver.cpp +++ b/protocols/VKontakte/src/vk_pollserver.cpp @@ -116,7 +116,11 @@ void CVkProto::PollUpdates(const JSONNode &jnUpdates) hContact = FindUser(uid); if (hContact != NULL) { setDword(hContact, "LastMsgReadTime", time(NULL)); - if (!ServiceExists("MessageState/DummyService")) + if (ServiceExists(MS_MESSAGESTATE_UPDATE)) { + MessageReadData data(time(NULL), MRD_TYPE_READTIME); + CallService(MS_MESSAGESTATE_UPDATE, hContact, (LPARAM)&data); + } + else SetSrmmReadStatus(hContact); if (m_bUserForceOnlineOnActivity) SetInvisible(hContact); diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index f8d555a907..d334c71cbc 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -544,7 +544,7 @@ void CVkProto::OnReceiveAuthRequest(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * { debugLogA("CVkProto::OnReceiveAuthRequest %d", reply->resultCode); CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; - if (reply->resultCode == 200) { + if (reply->resultCode == 200 && param) { JSONNode jnRoot; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); if (jnResponse) { @@ -560,7 +560,7 @@ void CVkProto::OnReceiveAuthRequest(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * } } else { - switch (param->iCount) { + switch (pReq->m_iErrorCode) { case VKERR_HIMSELF_AS_FRIEND: MsgPopup(param->hContact, TranslateT("You cannot add yourself as friend"), TranslateT("Error"), true); break; @@ -573,8 +573,11 @@ void CVkProto::OnReceiveAuthRequest(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * } } } - if (!pReq->bNeedsRestart) + + if (param && (!pReq->bNeedsRestart || m_bTerminated)) { delete param; + pReq->pUserInfo = NULL; + } } int CVkProto::Authorize(MEVENT hDbEvent) diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index e646312f2f..84fccf2644 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -15,6 +15,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#include "stdafx.h" +#pragma once + #define PS_CREATECHAT "/CreateNewChat" #define PS_LOADVKNEWS "/LoadVKNews" #define PS_GETSERVERHISTORY "/SyncHistory" @@ -36,215 +39,6 @@ along with this program. If not, see . #define MAXHISTORYMIDSPERONE 175 #define MAX_RETRIES 10 -struct CVkProto; -typedef void (CVkProto::*VK_REQUEST_HANDLER)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); - -struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject -{ - enum RequestPriority { rpLow, rpMedium, rpHigh }; - - AsyncHttpRequest(); - AsyncHttpRequest(CVkProto*, int iRequestType, LPCSTR szUrl, bool bSecure, VK_REQUEST_HANDLER pFunc, RequestPriority rpPriority = rpMedium); - ~AsyncHttpRequest(); - - void AddHeader(LPCSTR, LPCSTR); - void Redirect(NETLIBHTTPREQUEST*); - - CMStringA m_szUrl; - CMStringA m_szParam; - VK_REQUEST_HANDLER m_pFunc; - void *pUserInfo; - int m_iRetry; - RequestPriority m_priority; - static ULONG m_reqCount; - ULONG m_reqNum; - bool m_bApiReq; - bool bExpUrlEncode; - bool bNeedsRestart, bIsMainConn; -}; - -struct PARAM -{ - LPCSTR szName; - __forceinline PARAM(LPCSTR _name) : szName(_name) - {} -}; - -struct INT_PARAM : public PARAM -{ - int iValue; - __forceinline INT_PARAM(LPCSTR _name, int _value) : - PARAM(_name), iValue(_value) - {} -}; -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT_PARAM&); - -struct CHAR_PARAM : public PARAM -{ - LPCSTR szValue; - __forceinline CHAR_PARAM(LPCSTR _name, LPCSTR _value) : - PARAM(_name), szValue(_value) - {} -}; -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const CHAR_PARAM&); - -struct TCHAR_PARAM : public PARAM -{ - LPCTSTR tszValue; - __forceinline TCHAR_PARAM(LPCSTR _name, LPCTSTR _value) : - PARAM(_name), tszValue(_value) - {} -}; -AsyncHttpRequest* operator<<(AsyncHttpRequest*, const TCHAR_PARAM&); - -struct CVkSendMsgParam -{ - CVkSendMsgParam(MCONTACT _p1, int _p2 = 0, int _p3 = 0) : - hContact(_p1), - iMsgID(_p2), - iCount(_p3) - {} - - MCONTACT hContact; - int iMsgID; - int iCount; -}; - -struct CVkChatMessage : public MZeroedObject -{ - CVkChatMessage(int _id) : - m_mid(_id), - m_uid(0), - m_date(0), - m_bHistory(false), - m_bIsAction(false) - {} - - int m_mid, m_uid, m_date; - bool m_bHistory, m_bIsAction; - ptrT m_tszBody; -}; - -struct CVkChatUser : public MZeroedObject -{ - CVkChatUser(int _id) : - m_uid(_id), - m_bDel(false), - m_bUnknown(false) - {} - - int m_uid; - bool m_bDel, m_bUnknown; - ptrT m_tszNick; -}; - -struct CVkChatInfo : public MZeroedObject -{ - CVkChatInfo(int _id) : - m_users(10, NumericKeySortT), - m_msgs(10, NumericKeySortT), - m_chatid(_id), - m_admin_id(0), - m_bHistoryRead(0), - m_hContact(INVALID_CONTACT_ID) - {} - - int m_chatid, m_admin_id; - bool m_bHistoryRead; - ptrT m_tszTopic, m_tszId; - MCONTACT m_hContact; - OBJLIST m_users; - OBJLIST m_msgs; - - CVkChatUser* GetUserById(LPCTSTR); -}; - -struct CVkFileUploadParam { - enum VKFileType {typeInvalid, typeImg, typeAudio, typeDoc, typeNotSupported}; - TCHAR* FileName; - TCHAR* Desc; - char* atr; - char* fname; - MCONTACT hContact; - VKFileType filetype; - int iErrorCode; - - CVkFileUploadParam(MCONTACT _hContact, const TCHAR* _desc, TCHAR** _files); - ~CVkFileUploadParam(); - VKFileType GetType(); - __forceinline bool IsAccess() { return ::_taccess(FileName, 0) == 0; } - __forceinline char* atrName() { return atr; } - __forceinline char* fileName() { return fname; } -}; - -struct CVkUserInfo : public MZeroedObject { - CVkUserInfo(LONG _UserId) : - m_UserId(_UserId), - m_bIsGroup(false) - {} - - CVkUserInfo(LONG _UserId, bool _bIsGroup, CMString& _tszUserNick, CMString& _tszLink, MCONTACT _hContact = NULL) : - m_UserId(_UserId), - m_bIsGroup(_bIsGroup), - m_tszUserNick(_tszUserNick), - m_tszLink(_tszLink), - m_hContact(_hContact) - {} - - LONG m_UserId; - MCONTACT m_hContact; - CMString m_tszUserNick; - CMString m_tszLink; - bool m_bIsGroup; -}; - -enum VKObjType { vkNull, vkPost, vkPhoto, vkVideo, vkComment, vkTopic, vkUsers, vkCopy, vkInvite }; - -struct CVKNotification { - TCHAR *ptszType; - VKObjType vkParent, vkFeedback; - TCHAR *ptszTranslate; -}; - -struct CVKNewsItem : public MZeroedObject { - CVKNewsItem() : - tDate(NULL), - vkUser(NULL), - bIsGroup(false), - bIsRepost(false), - vkFeedbackType(vkNull), - vkParentType(vkNull) - {} - - CMString tszId; - time_t tDate; - CVkUserInfo *vkUser; - CMString tszText; - CMString tszLink; - CMString tszType; - VKObjType vkFeedbackType, vkParentType; - bool bIsGroup; - bool bIsRepost; -}; - -enum VKBBCType { vkbbcB, vkbbcI, vkbbcS, vkbbcU, vkbbcImg, vkbbcUrl, vkbbcSize, vkbbcColor }; -enum BBCSupport { bbcNo, bbcBasic, bbcAdvanced }; - -struct CVKBBCItem { - VKBBCType vkBBCType; - BBCSupport vkBBCSettings; - TCHAR *ptszTempate; -}; - -struct TFakeAckParams -{ - __inline TFakeAckParams(MCONTACT _hContact, int _msgid) : - hContact(_hContact), msgid(_msgid) - {} - - MCONTACT hContact; - int msgid; -}; struct CVkProto : public PROTO { @@ -336,13 +130,14 @@ struct CVkProto : public PROTO void __cdecl SearchBasicThread(void* id); void __cdecl SearchByMailThread(void* email); void __cdecl SearchThread(void* p); + void FreeProtoShearchStruct(PROTOSEARCHBYNAME *pParam); void OnSearch(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnSearchByMail(NETLIBHTTPREQUEST *, AsyncHttpRequest *); //==== Files Upload ================================================================== void __cdecl SendFileThread(void *p); - void SendFileFiled(CVkFileUploadParam *fup, TCHAR* reason = NULL); + void SendFileFiled(CVkFileUploadParam *fup, int ErrorCode); void OnReciveUploadServer(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnReciveUpload(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnReciveUploadFile(NETLIBHTTPREQUEST*, AsyncHttpRequest*); diff --git a/protocols/VKontakte/src/vk_search.cpp b/protocols/VKontakte/src/vk_search.cpp index dbd6ff57b9..9180ca6c1c 100644 --- a/protocols/VKontakte/src/vk_search.cpp +++ b/protocols/VKontakte/src/vk_search.cpp @@ -85,17 +85,23 @@ void __cdecl CVkProto::SearchThread(void* p) Push(pReq); } +void CVkProto::FreeProtoShearchStruct(PROTOSEARCHBYNAME *pParam) +{ + if (!pParam) + return; + + mir_free(pParam->pszFirstName); + mir_free(pParam->pszLastName); + mir_free(pParam->pszNick); + delete pParam; +} + void CVkProto::OnSearch(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { PROTOSEARCHBYNAME *pParam = (PROTOSEARCHBYNAME *)pReq->pUserInfo; debugLogA("CVkProto::OnSearch %d", reply->resultCode); if (reply->resultCode != 200) { - if (pParam) { - mir_free(pParam->pszFirstName); - mir_free(pParam->pszLastName); - mir_free(pParam->pszNick); - delete pParam; - } + FreeProtoShearchStruct(pParam); ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1); return; } @@ -103,12 +109,7 @@ void CVkProto::OnSearch(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) JSONNode jnRoot; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); if (!jnResponse) { - if (pParam) { - mir_free(pParam->pszFirstName); - mir_free(pParam->pszLastName); - mir_free(pParam->pszNick); - delete pParam; - } + FreeProtoShearchStruct(pParam); ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1); return; } @@ -148,12 +149,7 @@ void CVkProto::OnSearch(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) } ProtoBroadcastAck(0, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1); - if (pParam) { - mir_free(pParam->pszFirstName); - mir_free(pParam->pszLastName); - mir_free(pParam->pszNick); - delete pParam; - } + FreeProtoShearchStruct(pParam); } void CVkProto::OnSearchByMail(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) diff --git a/protocols/VKontakte/src/vk_struct.cpp b/protocols/VKontakte/src/vk_struct.cpp new file mode 100644 index 0000000000..ee3163de4c --- /dev/null +++ b/protocols/VKontakte/src/vk_struct.cpp @@ -0,0 +1,156 @@ +/* +Copyright (c) 2013-15 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" + +///////////////////////////////////////////////////////////////////////////////////////// + +ULONG AsyncHttpRequest::m_reqCount = 0; + +AsyncHttpRequest::AsyncHttpRequest() +{ + cbSize = sizeof(NETLIBHTTPREQUEST); + m_bApiReq = true; + AddHeader("Connection", "keep-alive"); + AddHeader("Accept-Encoding", "booo"); + pUserInfo = NULL; + m_iRetry = MAX_RETRIES; + m_iErrorCode = 0; + bNeedsRestart = false; + bIsMainConn = false; + m_pFunc = NULL; + bExpUrlEncode = false; + m_reqNum = ::InterlockedIncrement(&m_reqCount); + m_priority = rpLow; +} + +AsyncHttpRequest::AsyncHttpRequest(CVkProto *ppro, int iRequestType, LPCSTR _url, bool bSecure, VK_REQUEST_HANDLER pFunc, RequestPriority rpPriority) +{ + cbSize = sizeof(NETLIBHTTPREQUEST); + m_bApiReq = true; + bIsMainConn = false; + bExpUrlEncode = ppro->m_bUseNonStandardUrlEncode; + AddHeader("Connection", "keep-alive"); + AddHeader("Accept-Encoding", "booo"); + + flags = VK_NODUMPHEADERS | NLHRF_DUMPASTEXT | NLHRF_HTTP11 | NLHRF_REDIRECT; + if (bSecure) + flags |= NLHRF_SSL; + + if (*_url == '/') { // relative url leads to a site + m_szUrl = ((bSecure) ? "https://" : "http://") + CMStringA("api.vk.com"); + m_szUrl += _url; + bIsMainConn = true; + } + else m_szUrl = _url; + + if (bSecure) + this << CHAR_PARAM("access_token", ppro->m_szAccessToken); + + requestType = iRequestType; + m_pFunc = pFunc; + pUserInfo = NULL; + m_iRetry = MAX_RETRIES; + m_iErrorCode = 0; + bNeedsRestart = false; + m_reqNum = ::InterlockedIncrement(&m_reqCount); + m_priority = rpPriority; +} + +AsyncHttpRequest::~AsyncHttpRequest() +{ + for (int i = 0; i < headersCount; i++) { + mir_free(headers[i].szName); + mir_free(headers[i].szValue); + } + mir_free(headers); + mir_free(pData); +} + +void AsyncHttpRequest::AddHeader(LPCSTR szName, LPCSTR szValue) +{ + headers = (NETLIBHTTPHEADER*)mir_realloc(headers, sizeof(NETLIBHTTPHEADER)*(headersCount + 1)); + headers[headersCount].szName = mir_strdup(szName); + headers[headersCount].szValue = mir_strdup(szValue); + headersCount++; +} + +void AsyncHttpRequest::Redirect(NETLIBHTTPREQUEST *nhr) +{ + for (int i = 0; i < nhr->headersCount; i++) { + LPCSTR szValue = nhr->headers[i].szValue; + if (!_stricmp(nhr->headers[i].szName, "Location")) + m_szUrl = szValue; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +CVkFileUploadParam::CVkFileUploadParam(MCONTACT _hContact, const TCHAR* _desc, TCHAR** _files) : + hContact(_hContact), + Desc(mir_tstrdup(_desc)), + FileName(mir_tstrdup(_files[0])) +{} + +CVkFileUploadParam::~CVkFileUploadParam() +{ + mir_free(Desc); + mir_free(FileName); + mir_free(atr); + mir_free(fname); +} + +CVkFileUploadParam::VKFileType CVkFileUploadParam::GetType() +{ + if (filetype != typeInvalid) + return filetype; + + TCHAR img[] = _T(".jpg .jpeg .png .bmp"); + TCHAR audio[] = _T(".mp3"); + + TCHAR DRIVE[3], DIR[256], FNAME[256], EXT[256]; + _tsplitpath(FileName, DRIVE, DIR, FNAME, EXT); + + T2Utf pszFNAME(FNAME), pszEXT(EXT); + CMStringA fn(FORMAT, "%s%s", pszFNAME, pszEXT); + fname = mir_strdup(fn); + + if (tlstrstr(img, EXT)) { + filetype = CVkFileUploadParam::typeImg; + atr = mir_strdup("photo"); + } + else if (tlstrstr(audio, EXT)) { + filetype = CVkFileUploadParam::typeAudio; + atr = mir_strdup("file"); + } + else { + filetype = CVkFileUploadParam::typeDoc; + atr = mir_strdup("file"); + } + + return filetype; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +CVkChatUser* CVkChatInfo::GetUserById(LPCTSTR ptszId) +{ + int user_id = _ttoi(ptszId); + return m_users.find((CVkChatUser*)&user_id); +} + +///////////////////////////////////////////////////////////////////////////////////////// \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_struct.h b/protocols/VKontakte/src/vk_struct.h new file mode 100644 index 0000000000..ea93b42d02 --- /dev/null +++ b/protocols/VKontakte/src/vk_struct.h @@ -0,0 +1,225 @@ +/* +Copyright (c) 2013-15 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" +#pragma once + +typedef void (CVkProto::*VK_REQUEST_HANDLER)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); + +struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject +{ + enum RequestPriority { rpLow, rpMedium, rpHigh }; + + AsyncHttpRequest(); + AsyncHttpRequest(CVkProto*, int iRequestType, LPCSTR szUrl, bool bSecure, VK_REQUEST_HANDLER pFunc, RequestPriority rpPriority = rpMedium); + ~AsyncHttpRequest(); + + void AddHeader(LPCSTR, LPCSTR); + void Redirect(NETLIBHTTPREQUEST*); + + CMStringA m_szUrl; + CMStringA m_szParam; + VK_REQUEST_HANDLER m_pFunc; + void *pUserInfo; + int m_iRetry; + int m_iErrorCode; + RequestPriority m_priority; + static ULONG m_reqCount; + ULONG m_reqNum; + bool m_bApiReq; + bool bExpUrlEncode; + bool bNeedsRestart, bIsMainConn; +}; + +struct PARAM +{ + LPCSTR szName; + __forceinline PARAM(LPCSTR _name) : szName(_name) + {} +}; + +struct INT_PARAM : public PARAM +{ + int iValue; + __forceinline INT_PARAM(LPCSTR _name, int _value) : + PARAM(_name), iValue(_value) + {} +}; +AsyncHttpRequest* operator<<(AsyncHttpRequest*, const INT_PARAM&); + +struct CHAR_PARAM : public PARAM +{ + LPCSTR szValue; + __forceinline CHAR_PARAM(LPCSTR _name, LPCSTR _value) : + PARAM(_name), szValue(_value) + {} +}; +AsyncHttpRequest* operator<<(AsyncHttpRequest*, const CHAR_PARAM&); + +struct TCHAR_PARAM : public PARAM +{ + LPCTSTR tszValue; + __forceinline TCHAR_PARAM(LPCSTR _name, LPCTSTR _value) : + PARAM(_name), tszValue(_value) + {} +}; +AsyncHttpRequest* operator<<(AsyncHttpRequest*, const TCHAR_PARAM&); + +struct CVkFileUploadParam : public MZeroedObject { + enum VKFileType { typeInvalid, typeImg, typeAudio, typeDoc, typeNotSupported }; + TCHAR* FileName; + TCHAR* Desc; + char* atr; + char* fname; + MCONTACT hContact; + VKFileType filetype; + + CVkFileUploadParam(MCONTACT _hContact, const TCHAR* _desc, TCHAR** _files); + ~CVkFileUploadParam(); + VKFileType GetType(); + __forceinline bool IsAccess() { return ::_taccess(FileName, 0) == 0; } + __forceinline char* atrName() { return atr; } + __forceinline char* fileName() { return fname; } +}; + +struct CVkSendMsgParam : public MZeroedObject +{ + CVkSendMsgParam(MCONTACT _hContact, int _iMsgID = 0, int _iCount = 0) : + hContact(_hContact), + iMsgID(_iMsgID), + iCount(_iCount) + {} + + CVkSendMsgParam(MCONTACT _hContact, CVkFileUploadParam *_pFUP) : + hContact(_hContact), + iMsgID(-1), + pFUP(_pFUP) + {} + + MCONTACT hContact; + int iMsgID; + int iCount; + CVkFileUploadParam *pFUP; +}; + +struct CVkChatMessage : public MZeroedObject +{ + CVkChatMessage(int _id) : + m_mid(_id), + m_uid(0), + m_date(0), + m_bHistory(false), + m_bIsAction(false) + {} + + int m_mid, m_uid, m_date; + bool m_bHistory, m_bIsAction; + ptrT m_tszBody; +}; + +struct CVkChatUser : public MZeroedObject +{ + CVkChatUser(int _id) : + m_uid(_id), + m_bDel(false), + m_bUnknown(false) + {} + + int m_uid; + bool m_bDel, m_bUnknown; + ptrT m_tszNick; +}; + +struct CVkChatInfo : public MZeroedObject +{ + CVkChatInfo(int _id) : + m_users(10, NumericKeySortT), + m_msgs(10, NumericKeySortT), + m_chatid(_id), + m_admin_id(0), + m_bHistoryRead(0), + m_hContact(INVALID_CONTACT_ID) + {} + + int m_chatid, m_admin_id; + bool m_bHistoryRead; + ptrT m_tszTopic, m_tszId; + MCONTACT m_hContact; + OBJLIST m_users; + OBJLIST m_msgs; + + CVkChatUser* GetUserById(LPCTSTR); +}; + +struct CVkUserInfo : public MZeroedObject { + CVkUserInfo(LONG _UserId) : + m_UserId(_UserId), + m_bIsGroup(false) + {} + + CVkUserInfo(LONG _UserId, bool _bIsGroup, CMString& _tszUserNick, CMString& _tszLink, MCONTACT _hContact = NULL) : + m_UserId(_UserId), + m_bIsGroup(_bIsGroup), + m_tszUserNick(_tszUserNick), + m_tszLink(_tszLink), + m_hContact(_hContact) + {} + + LONG m_UserId; + MCONTACT m_hContact; + CMString m_tszUserNick; + CMString m_tszLink; + bool m_bIsGroup; +}; + +enum VKObjType { vkNull, vkPost, vkPhoto, vkVideo, vkComment, vkTopic, vkUsers, vkCopy, vkInvite }; + +struct CVKNotification { + TCHAR *ptszType; + VKObjType vkParent, vkFeedback; + TCHAR *ptszTranslate; +}; + +struct CVKNewsItem : public MZeroedObject { + CVKNewsItem() : + tDate(NULL), + vkUser(NULL), + bIsGroup(false), + bIsRepost(false), + vkFeedbackType(vkNull), + vkParentType(vkNull) + {} + + CMString tszId; + time_t tDate; + CVkUserInfo *vkUser; + CMString tszText; + CMString tszLink; + CMString tszType; + VKObjType vkFeedbackType, vkParentType; + bool bIsGroup; + bool bIsRepost; +}; + +enum VKBBCType { vkbbcB, vkbbcI, vkbbcS, vkbbcU, vkbbcImg, vkbbcUrl, vkbbcSize, vkbbcColor }; +enum BBCSupport { bbcNo, bbcBasic, bbcAdvanced }; + +struct CVKBBCItem { + VKBBCType vkBBCType; + BBCSupport vkBBCSettings; + TCHAR *ptszTempate; +}; \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp index 726551d3fe..7b257053f4 100644 --- a/protocols/VKontakte/src/vk_thread.cpp +++ b/protocols/VKontakte/src/vk_thread.cpp @@ -592,7 +592,7 @@ void CVkProto::OnReceiveDeleteFriend(NETLIBHTTPREQUEST* reply, AsyncHttpRequest* { debugLogA("CVkProto::OnReceiveDeleteFriend %d", reply->resultCode); CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; - if (reply->resultCode == 200) { + if (reply->resultCode == 200 && param) { JSONNode jnRoot; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); if (jnResponse) { @@ -621,7 +621,11 @@ void CVkProto::OnReceiveDeleteFriend(NETLIBHTTPREQUEST* reply, AsyncHttpRequest* } } } - delete param; + + if (param && (!pReq->bNeedsRestart || m_bTerminated)) { + delete param; + pReq->pUserInfo = NULL; + } } INT_PTR __cdecl CVkProto::SvcBanUser(WPARAM hContact, LPARAM) -- cgit v1.2.3