/* Copyright (C) 2012-25 Miranda NG team (https://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 CSteamProto::SendGetChatsRequest() { CChatRoomGetMyChatRoomGroupsRequest request; WSSendService(GetMyChatRoomGroups, request); } void CSteamProto::OnGetMyChats(const CChatRoomGetMyChatRoomGroupsResponse &reply, const CMsgProtoBufHeader &hdr) { if (hdr.failed()) return; for (int i = 0; i < reply.n_chat_room_groups; i++) { auto *pGroup = reply.chat_room_groups[i]->group_summary; CMStringW wszGrpName; if (pGroup->n_chat_rooms > 1 && pGroup->chat_group_name) { wszGrpName = CMStringW(m_wszGroupName) + L"\\" + Utf2T(pGroup->chat_group_name); if (!Clist_GroupExists(wszGrpName)) Clist_GroupCreate(0, wszGrpName); } SESSION_INFO *pOwner = 0; for (int k = 0; k < pGroup->n_chat_rooms; k++) { std::vector ids; auto *pChat = pGroup->chat_rooms[k]; CMStringW wszId(FORMAT, L"%lld_%lld", pGroup->chat_group_id, pChat->chat_id); CMStringW wszTitle(Utf2T(pChat->chat_name)); if (wszTitle.IsEmpty()) wszTitle = Utf2T(pGroup->chat_group_name); auto *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszId, wszTitle); if (!si->pStatuses) { Chat_AddGroup(si, TranslateT("Owner")); Chat_AddGroup(si, TranslateT("Participant")); if (pOwner == 0) { for (int j = 0; j < pGroup->n_top_members; j++) { uint64_t iSteamId = AccountIdToSteamId(pGroup->top_members[j]); CMStringW wszUserId(FORMAT, L"%lld", iSteamId), wszNick; GCEVENT gce = { si, GC_EVENT_JOIN }; gce.pszUID.w = wszUserId; if (iSteamId == m_iSteamId) { gce.bIsMe = true; wszNick = getMStringW("Nick"); } else if (MCONTACT hContact = GetContact(iSteamId)) wszNick = Clist_GetContactDisplayName(hContact); else { ids.push_back(iSteamId); { mir_cslock lck(m_csChats); m_chatContactInfo[iSteamId] = si; } wszNick = L"@" + wszUserId; } gce.pszNick.w = wszNick; gce.pszStatus.w = (pGroup->top_members[j] == pGroup->accountid_owner) ? TranslateT("Owner") : TranslateT("Participant"); Chat_Event(&gce); } } else si->pParent = pOwner; } setDword(si->hContact, "ChatId", pChat->chat_id); if (!wszGrpName.IsEmpty()) Clist_SetGroup(si->hContact, wszGrpName); if (mir_strlen(pGroup->chat_group_tagline)) { Utf2T wszTopic(pGroup->chat_group_tagline); Chat_SetStatusbarText(si, wszTopic); GCEVENT gce = { si, GC_EVENT_TOPIC }; gce.pszText.w = wszTopic; gce.time = time(0); Chat_Event(&gce); } Chat_Control(si, WINDOW_HIDDEN); Chat_Control(si, SESSION_ONLINE); if (!ids.empty()) SendUserInfoRequest(ids); uint32_t dwLastMsgId = getDword(si->hContact, DBKEY_LASTMSG); if (pChat->time_last_message > dwLastMsgId) SendGetChatHistory(si->hContact, dwLastMsgId); } } } ///////////////////////////////////////////////////////////////////////////////////////// void CSteamProto::SendGetChatHistory(MCONTACT hContact, uint32_t iLastMsgId) { CChatRoomGetMessageHistoryRequest request; request.chat_group_id = GetId(hContact, DBKEY_STEAM_ID); request.has_chat_group_id = true; request.chat_id = getDword(hContact, "ChatId"); request.has_chat_id = true; request.start_time = iLastMsgId; request.has_start_time = true; WSSendService(GetChatHistory, request, (void*)hContact); } void CSteamProto::OnGetChatHistory(const CChatRoomGetMessageHistoryResponse &reply, const CMsgProtoBufHeader &hdr) { if (hdr.failed()) return; if (auto *si = Chat_Find(UINT_PTR(GetRequestInfo(hdr.jobid_target)), m_szModuleName)) { uint32_t iLastMsg = getDword(si->hContact, DBKEY_LASTMSG); uint32_t iChatId = getDword(si->hContact, "ChatId"); for (int i = (int)reply.n_messages - 1; i >= 0; i--) { auto *pMsg = reply.messages[i]; if (pMsg->server_timestamp > iLastMsg) iLastMsg = pMsg->server_timestamp; // some slack, skip it if (pMsg->server_message) continue; char szMsgId[100], szUserId[100]; mir_snprintf(szMsgId, "%d_%d", iChatId, pMsg->server_timestamp); _i64toa(AccountIdToSteamId(pMsg->sender), szUserId, 10); CMStringA szText(pMsg->message); DecodeBbcodes(si, szText); DB::EventInfo dbei(db_event_getById(m_szModuleName, szMsgId)); dbei.flags |= DBEF_UTF; dbei.eventType = EVENTTYPE_MESSAGE; dbei.szModule = m_szModuleName; dbei.cbBlob = szText.GetLength(); replaceStr(dbei.pBlob, szText.Detach()); dbei.iTimestamp = pMsg->server_timestamp; dbei.szId = szMsgId; dbei.szUserId = szUserId; if (dbei.getEvent()) db_event_edit(dbei.getEvent(), &dbei, true); else db_event_add(si->hContact, &dbei); } setDword(si->hContact, DBKEY_LASTMSG, iLastMsg); } } ///////////////////////////////////////////////////////////////////////////////////////// void CSteamProto::OnGetChatMessage(const CChatRoomIncomingChatMessageNotification &reply, const CMsgProtoBufHeader &hdr) { if (hdr.failed()) return; CMStringW wszId(FORMAT, L"%lld_%lld", reply.chat_group_id, reply.chat_id); if (auto *si = Chat_Find(wszId, m_szModuleName)) { char szMsgId[100], szUserId[100]; mir_snprintf(szMsgId, "%lld_%d", reply.chat_id, reply.timestamp); _i64toa(reply.steamid_sender, szUserId, 10); CMStringA szText(reply.message); DecodeBbcodes(si, szText); DB::EventInfo dbei(db_event_getById(m_szModuleName, szMsgId)); dbei.flags |= DBEF_UTF; dbei.eventType = EVENTTYPE_MESSAGE; dbei.szModule = m_szModuleName; dbei.cbBlob = szText.GetLength(); replaceStr(dbei.pBlob, szText.Detach()); dbei.iTimestamp = reply.timestamp; dbei.szId = szMsgId; dbei.szUserId = szUserId; if (dbei.getEvent()) db_event_edit(dbei.getEvent(), &dbei, true); else db_event_add(si->hContact, &dbei); } } ///////////////////////////////////////////////////////////////////////////////////////// INT_PTR CSteamProto::SvcLeaveChat(WPARAM hContact, LPARAM) { CChatRoomLeaveChatRoomGroupRequest request; request.chat_group_id = GetId(hContact, DBKEY_STEAM_ID); request.has_chat_group_id = true; WSSendService(LeaveChatGroup, request, new uint64_t(request.chat_group_id)); return 0; } void CSteamProto::OnLeftChat(const CChatRoomLeaveChatRoomGroupResponse&, const CMsgProtoBufHeader &hdr) { if (auto *pGroupId = (int64_t *)GetRequestInfo(hdr.jobid_target)) { for (auto &cc : AccContacts()) { if (!Contact::IsGroupChat(cc) || GetId(cc, DBKEY_STEAM_ID) != *pGroupId) continue; CMStringW wszId(FORMAT, L"%lld_%lld", *pGroupId, GetId(cc, "ChatId")); if (auto *si = Chat_Find(wszId, m_szModuleName)) Chat_Terminate(si); db_delete_contact(cc); } delete pGroupId; } } ///////////////////////////////////////////////////////////////////////////////////////// enum { IDM_LEAVE = 1, }; int CSteamProto::GcEventHook(WPARAM, LPARAM lParam) { GCHOOK *gch = (GCHOOK *)lParam; if (gch == nullptr) return 0; auto *si = gch->si; if (mir_strcmpi(si->pszModule, m_szModuleName)) return 0; switch (gch->iType) { case GC_USER_MESSAGE: if (gch->ptszText && mir_wstrlen(gch->ptszText) > 0) { CMStringW wszText(gch->ptszText); wszText.TrimRight(); EncodeBbcodes(si, wszText); T2Utf szText(wszText); CChatRoomSendChatMessageRequest request; request.chat_group_id = _wtoi64(si->ptszID); request.has_chat_group_id = true; request.chat_id = getDword(si->hContact, "ChatId"); request.has_chat_id = true; request.echo_to_sender = request.has_echo_to_sender = true; request.message = szText; WSSendService(SendChatMessage, request); } break; case GC_USER_PRIVMESS: Chat_SendPrivateMessage(gch); break; case GC_USER_LOGMENU: Chat_LogMenu(gch); break; case GC_USER_NICKLISTMENU: break; } return 0; } void CSteamProto::Chat_SendPrivateMessage(GCHOOK *gch) { uint64_t iSteamId = _wtoi64(gch->ptszUID); MCONTACT hContact = GetContact(iSteamId); if (!hContact) { PROTOSEARCHRESULT psr = { sizeof(psr) }; psr.id.w = (wchar_t *)gch->ptszUID; psr.firstName.w = (wchar_t *)gch->ptszNick; hContact = AddToList(PALF_TEMPORARY, &psr); if (hContact == 0) return; setWString(hContact, "Nick", gch->ptszNick); Contact::Hide(hContact); db_set_dw(hContact, "Ignore", "Mask1", 0); } CallService(MS_MSG_SENDMESSAGE, hContact, 0); } void CSteamProto::Chat_LogMenu(GCHOOK *gch) { switch (gch->dwData) { case IDM_LEAVE: SvcLeaveChat(gch->si->hContact, 0); break; } } ///////////////////////////////////////////////////////////////////////////////////////// static gc_item sttLogListItems[] = { { LPGENW("&Leave chat session"), IDM_LEAVE, MENU_ITEM } }; int CSteamProto::GcMenuHook(WPARAM, LPARAM lParam) { GCMENUITEMS *gcmi = (GCMENUITEMS *)lParam; if (gcmi == nullptr) return 0; if (mir_strcmpi(gcmi->pszModule, m_szModuleName)) return 0; if (gcmi->Type == MENU_ON_LOG) { Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin); } else if (gcmi->Type == MENU_ON_NICKLIST) { } return 0; }