void CVkProto::RetrieveUnreadNews(time_t tLastNewsTime) { debugLogA("CVkProto::RetrieveUnreadNews"); if (!IsOnline()) return; time_t tLastNewsReqTime = getDword("LastNewsReqTime", time(NULL) - 24 * 60 * 60); if (time(NULL) - tLastNewsReqTime < 3 * 60) return; CMStringA szFilter; szFilter = m_bNewsFilterPosts ? "post" : ""; szFilter += szFilter.IsEmpty() ? "" : ","; szFilter += m_bNewsFilterPhotos ? "photo" : ""; szFilter += szFilter.IsEmpty() ? "" : ","; szFilter += m_bNewsFilterTags ? "photo_tag" : ""; szFilter += szFilter.IsEmpty() ? "" : ","; szFilter += m_bNewsFilterWallPhotos ? "wall_photo" : ""; if (szFilter.IsEmpty()) { debugLogA("CVkProto::RetrieveUnreadNews szFilter empty"); return; } CMStringA szSource; szSource = m_bNewsSourceFriends ? "friends" : ""; szSource += szSource.IsEmpty() ? "" : ","; szSource += m_bNewsSourceGroups ? "groups" : ""; szSource += szSource.IsEmpty() ? "" : ","; szSource += m_bNewsSourcePages ? "pages" : ""; szSource += szSource.IsEmpty() ? "" : ","; szSource += m_bNewsSourceFollowing ? "following" : ""; if (szSource.IsEmpty()) { debugLogA("CVkProto::RetrieveUnreadNews szSource empty"); return; } Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/newsfeed.get.json", true, &CVkProto::OnReceiveUnreadNews)) << INT_PARAM("count", 100) << INT_PARAM("return_banned", m_bNewsSourceIncludeBanned ? 1 : 0) << INT_PARAM("max_photos", m_iMaxLoadNewsPhoto) << INT_PARAM("start_time", tLastNewsTime + 1) << CHAR_PARAM("filters", szFilter) << CHAR_PARAM("source_ids", szSource) << VER_API; setDword("LastNewsReqTime", (DWORD)time(NULL)); }
int CVkProto::SendMsg(MCONTACT hContact, int, const char *szMsg) { debugLogA("CVkProto::SendMsg"); if (!IsOnline()) return 0; bool bIsChat = isChatRoom(hContact); LONG iUserID = getDword(hContact, bIsChat ? "vk_chat_id" : "ID" , -1); if (iUserID == -1 || iUserID == VK_FEED_USER) { ForkThread(&CVkProto::SendMsgAck, new CVkSendMsgParam(hContact)); return 0; } int StickerId = 0; ptrA pszRetMsg(GetStickerId(szMsg, StickerId)); ULONG uMsgId = ::InterlockedIncrement(&m_msgId); AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, bIsChat? &CVkProto::OnSendChatMsg : &CVkProto::OnSendMessage, AsyncHttpRequest::rpHigh) << INT_PARAM(bIsChat ? "chat_id" : "user_id", iUserID) << INT_PARAM("random_id", ((LONG) time(NULL)) * 100 + uMsgId % 100); pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); if (StickerId) pReq << INT_PARAM("sticker_id", StickerId); else { pReq << CHAR_PARAM("message", szMsg); if (m_vkOptions.bSendVKLinksAsAttachments) { CMStringA szAttachments = GetAttachmentsFromMessage(szMsg); if (!szAttachments.IsEmpty()) { debugLogA("CVkProto::SendMsg Attachments = %s", szAttachments); pReq << CHAR_PARAM("attachment", szAttachments); } } } if (!bIsChat) pReq->pUserInfo = new CVkSendMsgParam(hContact, uMsgId); Push(pReq); if (!m_bServerDelivery && !bIsChat) ForkThread(&CVkProto::SendMsgAck, new CVkSendMsgParam(hContact, uMsgId)); if (!IsEmpty(pszRetMsg)) SendMsg(hContact, 0, pszRetMsg); return uMsgId; }
int CVkProto::SendMsg(HANDLE hContact, int flags, const char *msg) { LONG userID = getDword(hContact, "ID", -1); if (userID == -1) return 0; ptrA szMsg; if (flags & PREF_UTF) szMsg = mir_strdup(msg); else if (flags & PREF_UNICODE) msg = mir_utf8encodeW((wchar_t*)&msg[strlen(msg)+1]); else msg = mir_utf8encode(msg); ULONG msgId = ::InterlockedIncrement(&m_msgId); AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.send.json", true, &CVkProto::OnSendMessage) << INT_PARAM("type", 0) << INT_PARAM("uid", userID) << CHAR_PARAM("message", msg); pReq->pData = (char*)hContact; pReq->pUserInfo = (void*)msgId; Push(pReq); if (!m_bServerDelivery) ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, msgId)); return msgId; }
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; }
void CVkProto::RetrieveUnreadMessages() { debugLogA("CVkProto::RetrieveMessages"); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveMessages) << CHAR_PARAM("code", "return { \"msgs\":API.messages.get({\"filters\":1}), \"dlgs\":API.messages.getDialogs() };")); }
void CVkProto::RetrieveFriends() { debugLogA("CVkProto::RetrieveFriends"); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/friends.get.json", true, &CVkProto::OnReceiveFriends) << INT_PARAM("count", 1000) << CHAR_PARAM("fields", "uid,first_name,last_name,photo_medium,sex,country,timezone,contacts")); }
void CVkProto::GetServerHistory(MCONTACT hContact, int iOffset, int iCount, int iTime, int iLastMsgId, bool once) { debugLogA("CVkProto::GetServerHistory %d %d %d %d %d", iOffset, iCount, iTime, iLastMsgId, (int)once); if (!IsOnline()) return; LONG userID = getDword(hContact, "ID", -1); if (-1 == userID || userID == VK_FEED_USER) return; CMStringA code(FORMAT, "var iOffset=%d;var iReqCount=%d;var userID=%d;var iTime=%d;var lastMid=%d;" "var Hist=API.messages.getHistory({\"user_id\":userID,\"count\":iReqCount,\"offset\":iOffset});" "var ext=Hist.items.length;var index=0;" "while(ext!=0){if(Hist.items[index].date>iTime){if(Hist.items[index].id>lastMid)" "{index=index+1;ext=ext-1;}else ext=0;}else ext=0;};" "var ret=Hist.items.slice(0,index);" "var [email protected]_messages;var Idx=0;var Uids=[];while(Idx<FMsgs.length){" "var Jdx=0;var CFMsgs=parseInt(FMsgs[Idx].length);while(Jdx<CFMsgs){" "Uids.unshift(FMsgs[Idx][Jdx].user_id);Jdx=Jdx+1;};Idx=Idx+1;};" "var FUsers=API.users.get({\"user_ids\":Uids,\"name_case\":\"gen\"});" "return{\"count\":index,\"datetime\":iTime,\"items\":ret,\"fwd_users\":FUsers,\"once\":%d,\"rcount\":iReqCount};", iOffset, iCount, userID, iTime, iLastMsgId, (int)once); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveHistoryMessages) << CHAR_PARAM("code", code) << VER_API)->pUserInfo = new CVkSendMsgParam(hContact, iLastMsgId, iOffset); }
void CVkProto::RetrieveMessagesByIds(const CMStringA &mids) { if (mids.IsEmpty()) return; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getById.json", true, &CVkProto::OnReceiveMessages) << CHAR_PARAM("mids", mids)); }
void CVkProto::MarkMessagesRead(const CMStringA &mids) { if (mids.IsEmpty()) return; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.markAsRead.json", true, &CVkProto::OnReceiveSmth) << CHAR_PARAM("mids", mids)); }
INT_PTR __cdecl CVkProto::SvcBanUser(WPARAM hContact, LPARAM) { debugLogA("CVkProto::SvcBanUser"); LONG userID = getDword(hContact, "ID", -1); if (!IsOnline() || userID == -1 || userID == VK_FEED_USER) return 1; CMStringA code(FORMAT, "var userID=\"%d\";API.account.banUser({\"user_id\":userID});", userID); CMString tszVarWarning; if (m_bReportAbuse) { debugLogA("CVkProto::SvcBanUser m_bReportAbuse = true"); code += "API.users.report({\"user_id\":userID,type:\"spam\"});"; tszVarWarning = TranslateT(" report abuse on him/her"); } if (m_bClearServerHistory) { debugLogA("CVkProto::SvcBanUser m_bClearServerHistory = true"); code += "API.messages.deleteDialog({\"user_id\":userID,count:10000});"; if (!tszVarWarning.IsEmpty()) tszVarWarning.AppendChar(L','); tszVarWarning += TranslateT(" clear server history with him/her"); } if (m_bRemoveFromFrendlist) { debugLogA("CVkProto::SvcBanUser m_bRemoveFromFrendlist = true"); code += "API.friends.delete({\"user_id\":userID});"; if (!tszVarWarning.IsEmpty()) tszVarWarning.AppendChar(L','); tszVarWarning += TranslateT(" remove him/her from your friend list"); } if (m_bRemoveFromClist) { debugLogA("CVkProto::SvcBanUser m_bRemoveFromClist = true"); if (!tszVarWarning.IsEmpty()) tszVarWarning.AppendChar(L','); tszVarWarning += TranslateT(" remove him/her from your contact list"); } if (!tszVarWarning.IsEmpty()) tszVarWarning += ".\n"; code += "return 1;"; ptrT ptszNick(db_get_tsa(hContact, m_szModuleName, "Nick")); CMString ptszMsg(FORMAT, TranslateT("Are you sure to ban %s? %s%sContinue?"), IsEmpty(ptszNick) ? TranslateT("(Unknown contact)") : ptszNick, tszVarWarning.IsEmpty() ? _T(" ") : TranslateT("\nIt will also"), tszVarWarning.IsEmpty() ? _T("\n") : tszVarWarning); if (IDNO == MessageBox(NULL, ptszMsg, TranslateT("Attention!"), MB_ICONWARNING | MB_YESNO)) return 1; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveSmth) << CHAR_PARAM("code", code) << VER_API); if (m_bRemoveFromClist) CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact); return 0; }
void CVkProto::MarkMessagesRead(const CMStringA &mids) { debugLogA("CVkProto::MarkMessagesRead (mids)"); if (!IsOnline() || mids.IsEmpty()) return; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.markAsRead.json", true, &CVkProto::OnReceiveSmth, AsyncHttpRequest::rpLow) << CHAR_PARAM("message_ids", mids)); }
void CVkProto::RetrieveFriends(bool bCleanNonFriendContacts) { debugLogA("CVkProto::RetrieveFriends"); if (!IsOnline()) return; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/friends.get.json", true, &CVkProto::OnReceiveFriends) << INT_PARAM("count", 1000) << CHAR_PARAM("fields", fieldsName) << VER_API)->pUserInfo = new CVkSendMsgParam(NULL, bCleanNonFriendContacts ? 1 : 0); }
void CVkProto::RetrieveFriends() { debugLogA("CVkProto::RetrieveFriends"); if (!IsOnline()) return; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/friends.get.json", true, &CVkProto::OnReceiveFriends) << INT_PARAM("count", 1000) << CHAR_PARAM("fields", fieldsName) <<VER_API); }
bool CVkProto::ApplyCaptcha(AsyncHttpRequest *pReq, const JSONNode &jnErrorNode) { debugLogA("CVkProto::ApplyCaptcha"); if (!IsOnline()) return false; CMStringA szUrl(jnErrorNode["captcha_img"].as_mstring()); CMStringA szSid(jnErrorNode["captcha_sid"].as_mstring()); if (szUrl.IsEmpty() || szSid.IsEmpty()) return false; CMStringA userReply; if (!RunCaptchaForm(szUrl, userReply)) return false; pReq << CHAR_PARAM("captcha_sid", szSid) << CHAR_PARAM("captcha_key", userReply.GetString()); pReq->bNeedsRestart = true; return true; }
int CVkProto::UserIsTyping(MCONTACT hContact, int type) { debugLogA("CVkProto::UserIsTyping"); if (PROTOTYPE_SELFTYPING_ON == type) { LONG userID = getDword(hContact, "ID", -1); if (userID == -1 || !IsOnline() || userID == VK_FEED_USER) return 1; if (m_iMarkMessageReadOn == markOnTyping) MarkMessagesRead(hContact); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.setActivity.json", true, &CVkProto::OnReceiveSmth, AsyncHttpRequest::rpLow) << INT_PARAM("user_id", userID) << CHAR_PARAM("type", "typing") << VER_API); return 0; } return 1; }
INT_PTR __cdecl CVkProto::SvcReportAbuse(WPARAM hContact, LPARAM) { debugLogA("CVkProto::SvcReportAbuse"); LONG userID = getDword(hContact, "ID", -1); if (!IsOnline() || userID == -1 || userID == VK_FEED_USER) return 1; CMString tszNick(ptrT(db_get_tsa(hContact, m_szModuleName, "Nick"))), ptszMsg(FORMAT, TranslateT("Are you sure to report abuse on %s?"), tszNick.IsEmpty() ? TranslateT("(Unknown contact)") : tszNick); if (IDNO == MessageBox(NULL, ptszMsg, TranslateT("Attention!"), MB_ICONWARNING | MB_YESNO)) return 1; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/users.report.json", true, &CVkProto::OnReceiveSmth) << INT_PARAM("user_id", userID) << CHAR_PARAM("type", "spam") << VER_API); return 0; }
void CVkProto::RetrieveChatInfo(CVkChatInfo *cc) { CMStringA szQuery("return { "); // retrieve title & owner id szQuery.AppendFormat("\"info\": API.messages.getChat({\"chat_id\":%d}),", cc->m_chatid); // retrieve users szQuery.AppendFormat("\"users\": API.messages.getChatUsers({\"chat_id\":%d, \"fields\":\"uid,first_name,last_name\"})", cc->m_chatid); if (!cc->m_bHistoryRead) szQuery.AppendFormat(",\"msgs\": API.messages.getHistory({\"chat_id\":%d, \"count\":\"20\", \"rev\":\"0\"})", cc->m_chatid); szQuery.Append("};"); debugLogA("CVkProto::RetrieveChantInfo(%d)", cc->m_chatid); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveChatInfo) << CHAR_PARAM("code", szQuery))->pUserInfo = cc; }
void CVkProto::RetrieveMessagesByIds(const CMStringA &mids) { debugLogA("CVkProto::RetrieveMessagesByIds"); if (!IsOnline() || mids.IsEmpty()) return; CMStringA code(FORMAT, "var Mids=\"%s\";" "var Msgs=API.messages.getById({\"message_ids\":Mids});" "var [email protected]_messages;" "var Idx=0;var Uids=[];" "while(Idx<FMsgs.length){" "var Jdx=0;var CFMsgs=parseInt(FMsgs[Idx].length);" "while(Jdx<CFMsgs){Uids.unshift(FMsgs[Idx][Jdx].user_id);" "Jdx=Jdx+1;};Idx=Idx+1;};" "var FUsers=API.users.get({\"user_ids\":Uids,\"name_case\":\"gen\"});" "return{\"Msgs\":Msgs,\"fwd_users\":FUsers};", mids ); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveMessages, AsyncHttpRequest::rpHigh) << CHAR_PARAM("code", code)); }
void CVkProto::CreateNewChat(LPCSTR uids, LPCTSTR ptszTitle) { Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.createChat.json", true, &CVkProto::OnCreateNewChat) << TCHAR_PARAM("title", ptszTitle) << CHAR_PARAM("uids", uids)); }
void CVkProto::OnReciveUpload(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { CVkFileUploadParam *fup = (CVkFileUploadParam *)pReq->pUserInfo; if (!IsOnline()) { SendFileFiled(fup, VKERR_OFFLINE); return; } debugLogA("CVkProto::OnReciveUploadServer %d", reply->resultCode); if (reply->resultCode != 200) { 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"]) && !jnRoot["file"]) { SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } CMString server(jnRoot["server"].as_mstring()); CMString hash(jnRoot["hash"].as_mstring()); CMString upload; AsyncHttpRequest *pUploadReq; ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)fup); switch (fup->GetType()) { case CVkFileUploadParam::typeImg: upload = jnRoot["photo"].as_mstring(); if (upload == _T("[]")) { SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/photos.saveMessagesPhoto.json", true, &CVkProto::OnReciveUploadFile) << TCHAR_PARAM("server", server) << TCHAR_PARAM("photo", upload) << TCHAR_PARAM("hash", hash) << VER_API; break; case CVkFileUploadParam::typeAudio: upload = jnRoot["audio"].as_mstring(); if (upload == _T("[]")) { SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/audio.save.json", true, &CVkProto::OnReciveUploadFile) << TCHAR_PARAM("server", server) << TCHAR_PARAM("audio", upload) << TCHAR_PARAM("hash", hash) << VER_API; break; case CVkFileUploadParam::typeDoc: upload = jnRoot["file"].as_mstring(); if (upload.IsEmpty()) { SendFileFiled(fup, VKERR_INVALID_PARAMETERS); return; } pUploadReq = new AsyncHttpRequest(this, REQUEST_GET, "/method/docs.save.json", true, &CVkProto::OnReciveUploadFile) << CHAR_PARAM("title", fup->fileName()) << TCHAR_PARAM("file", upload) << VER_API; break; default: SendFileFiled(fup, VKERR_FTYPE_NOT_SUPPORTED); return; } pUploadReq->pUserInfo = pReq->pUserInfo; Push(pUploadReq); }
void CVkProto::RetrieveUserInfo(LONG userID) { Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/getProfiles.json", true, &CVkProto::OnReceiveUserInfo) << INT_PARAM("uids", userID) << CHAR_PARAM("fields", "uid,first_name,last_name,photo_medium,sex,bdate,city,relation")); }
void CVkProto::WorkerThread(void*) { debugLogA("CVkProto::WorkerThread: entering"); m_bTerminated = m_prevError = false; m_szAccessToken = getStringA("AccessToken"); char Score[] = "friends,photos,audio,docs,video,wall,messages,offline,status,notifications,groups"; CMStringA szAccessScore(ptrA(getStringA("AccessScore"))); if (szAccessScore != Score) { setString("AccessScore", Score); delSetting("AccessToken"); m_szAccessToken = NULL; } if (m_szAccessToken != NULL) // try to receive a response from server RetrieveMyInfo(); else { // Initialize new OAuth session extern char szBlankUrl[]; AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_GET, "https://oauth.vk.com/authorize", false, &CVkProto::OnOAuthAuthorize) << INT_PARAM("client_id", VK_APP_ID) << CHAR_PARAM("scope", Score) << CHAR_PARAM("redirect_uri", szBlankUrl) << CHAR_PARAM("display", "mobile") << CHAR_PARAM("response_type", "token") << VER_API; pReq->m_bApiReq = false; pReq->bIsMainConn = true; Push(pReq); } m_hAPIConnection = NULL; while (true) { WaitForSingleObject(m_evRequestsQueue, 1000); if (m_bTerminated) break; AsyncHttpRequest *pReq; bool need_sleep = false; while (true) { { mir_cslock lck(m_csRequestsQueue); if (m_arRequestsQueue.getCount() == 0) break; pReq = m_arRequestsQueue[0]; m_arRequestsQueue.remove(0); need_sleep = (m_arRequestsQueue.getCount() > 1) && (pReq->m_bApiReq); // more than two to not gather } if (m_bTerminated) break; ExecuteRequest(pReq); if (need_sleep) { // There can be maximum 3 requests to API methods per second from a client Sleep(330); // (c) https://vk.com/dev/api_requests debugLogA("CVkProto::WorkerThread: need sleep"); } } } if (m_hAPIConnection) { debugLogA("CVkProto::WorkerThread: Netlib_CloseHandle(m_hAPIConnection) beg"); Netlib_CloseHandle(m_hAPIConnection); debugLogA("CVkProto::WorkerThread: Netlib_CloseHandle(m_hAPIConnection) end"); } m_hAPIConnection = NULL; m_hWorkerThread = 0; debugLogA("CVkProto::WorkerThread: leaving m_bTerminated = %d", m_bTerminated ? 1 : 0); }