From a1284729b31119dc50d95f73e2ffe7fed4a20ac8 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 23 Mar 2023 19:24:19 +0300 Subject: chat serialization --- src/mir_app/src/chat.h | 3 ++ src/mir_app/src/chat_svc.cpp | 64 ++++++++++++++++++++++++++++++++++-------- src/mir_app/src/chat_tools.cpp | 49 ++++++++++++++++++++++++++++++++ src/mir_app/src/chat_ui.cpp | 2 -- src/mir_app/src/stdafx.h | 5 ++-- 5 files changed, 108 insertions(+), 15 deletions(-) (limited to 'src/mir_app') diff --git a/src/mir_app/src/chat.h b/src/mir_app/src/chat.h index bf406fe434..c41c5344a8 100644 --- a/src/mir_app/src/chat.h +++ b/src/mir_app/src/chat.h @@ -130,4 +130,7 @@ CSrmmLogWindow *Srmm_GetLogWindow(CMsgDialog *pDlg); void Chat_RemoveContact(MCONTACT hContact); +CMStringW Chat_GetFolderName(SESSION_INFO *si = nullptr); +void Chat_Serialize(SESSION_INFO *si); + #pragma comment(lib,"comctl32.lib") diff --git a/src/mir_app/src/chat_svc.cpp b/src/mir_app/src/chat_svc.cpp index 0898e91402..9fd2d559ba 100644 --- a/src/mir_app/src/chat_svc.cpp +++ b/src/mir_app/src/chat_svc.cpp @@ -187,6 +187,7 @@ MIR_APP_DLL(int) Chat_Register(const GCREGISTER *gcr) mi->bAckMsg = (gcr->dwFlags & GC_ACKMSG) != 0; mi->bChanMgr = (gcr->dwFlags & GC_CHANMGR) != 0; mi->bDatabase = (gcr->dwFlags & GC_DATABASE) != 0; + mi->bPersistent = (gcr->dwFlags & GC_PERSISTENT) != 0; mi->iMaxText = gcr->iMaxText; mi->pszHeader = g_chatApi.Log_CreateRtfHeader(); @@ -418,22 +419,18 @@ MIR_APP_DLL(int) Chat_Terminate(SESSION_INFO *si) ///////////////////////////////////////////////////////////////////////////////////////// // handles chat event -static void AddUser(GCEVENT *gce) +static void AddUser(SESSION_INFO *si, GCEVENT &gce) { - SESSION_INFO *si = gce->si; - if (si == nullptr) - return; - - uint16_t status = TM_StringToWord(si->pStatuses, gce->pszStatus.w); + uint16_t status = TM_StringToWord(si->pStatuses, gce.pszStatus.w); - USERINFO *ui = g_chatApi.UM_AddUser(si, gce->pszUID.w, gce->pszNick.w, status); + USERINFO *ui = g_chatApi.UM_AddUser(si, gce.pszUID.w, gce.pszNick.w, status); if (ui == nullptr) return; if (g_chatApi.OnAddUser) g_chatApi.OnAddUser(si, ui); - if (gce->bIsMe) + if (gce.bIsMe) si->pMe = ui; ui->Status = status; ui->Status |= si->pStatuses->iStatus; @@ -465,6 +462,7 @@ static BOOL HandleChatEvent(GCEVENT &gce, int bManyFix) if (!mir_wstrcmp(si->ptszTopic, pwszNew)) // nothing changed? exiting return 0; + si->bIsDirty = true; replaceStrW(si->ptszTopic, pwszNew); if (pwszNew != nullptr) db_set_ws(si->hContact, si->pszModule, "Topic", si->ptszTopic); @@ -501,6 +499,7 @@ static BOOL HandleChatEvent(GCEVENT &gce, int bManyFix) break; case GC_EVENT_NICK: + si->bIsDirty = true; SM_ChangeNick(si, &gce); bIsHighlighted = g_chatApi.IsHighlighted(si, &gce); break; @@ -509,13 +508,15 @@ static BOOL HandleChatEvent(GCEVENT &gce, int bManyFix) return SM_UserTyping(&gce); case GC_EVENT_JOIN: - AddUser(&gce); + si->bIsDirty = true; + AddUser(si, gce); bIsHighlighted = g_chatApi.IsHighlighted(si, &gce); break; case GC_EVENT_PART: case GC_EVENT_QUIT: case GC_EVENT_KICK: + si->bIsDirty = true; bRemoveFlag = TRUE; bIsHighlighted = g_chatApi.IsHighlighted(si, &gce); break; @@ -617,8 +618,10 @@ MIR_APP_DLL(int) Chat_AddGroup(SESSION_INFO *si, const wchar_t *wszText) mir_cslock lck(csChat); STATUSINFO *ti = TM_AddStatus(&si->pStatuses, wszText, &si->iStatusCount); - if (ti) + if (ti) { si->iStatusCount++; + si->bIsDirty = true; + } if (g_chatApi.OnAddStatus) g_chatApi.OnAddStatus(si, ti); @@ -634,6 +637,7 @@ MIR_APP_DLL(int) Chat_ChangeSessionName(SESSION_INFO *si, const wchar_t *wszNewN if (!mir_wstrcmp(si->ptszName, wszNewName)) return 0; + si->bIsDirty = true; replaceStrW(si->ptszName, wszNewName); db_set_ws(si->hContact, si->pszModule, "Nick", wszNewName); if (si->pDlg) @@ -650,8 +654,10 @@ MIR_APP_DLL(int) Chat_ChangeUserId(const char *szModule, const wchar_t *wszOldId mir_cslock lck(csChat); for (auto &si : g_arSessions) - if (!mir_strcmpi(si->pszModule, szModule)) + if (!mir_strcmpi(si->pszModule, szModule)) { Chat_ChangeUserId(si, wszOldId, wszNewId); + si->bIsDirty = true; + } return 0; } @@ -665,6 +671,7 @@ MIR_APP_DLL(int) Chat_ChangeUserId(SESSION_INFO *si, const wchar_t *wszOldId, co if (ui) { replaceStrW(ui->pszUID, wszNewId); UM_SortKeys(si); + si->bIsDirty = true; } return 0; } @@ -723,6 +730,8 @@ MIR_APP_DLL(int) Chat_SetStatusEx(SESSION_INFO *si, int flags, const wchar_t *ws UM_SetStatusEx(si, wszText, flags); if (si->pDlg) RedrawWindow(GetDlgItem(si->pDlg->GetHwnd(), IDC_LIST), nullptr, nullptr, RDW_INVALIDATE); + + si->bIsDirty = true; return 0; } @@ -984,6 +993,34 @@ static IconItem iconList[] = static bool bInited = false; +class ChatGlobals +{ + CTimer timerChat; + + void onTimer(CTimer *) + { + mir_cslock lck(csChat); + + for (auto &it : g_arSessions) + if (it->bIsDirty) + Chat_Serialize(it); + } + +public: + ChatGlobals() : + timerChat(Miranda_GetSystemWindow(), (LPARAM)this) + { + timerChat.OnEvent = Callback(this, &ChatGlobals::onTimer); + timerChat.Start(10000); + } + + ~ChatGlobals() + { + timerChat.Stop(); + } +} +static *pChatGlobals = nullptr; + int LoadChatModule(void) { HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); @@ -992,6 +1029,9 @@ int LoadChatModule(void) HookEvent(ME_SKIN_ICONSCHANGED, IconsChanged); HookEvent(ME_FONT_RELOAD, FontsChanged); + pChatGlobals = new ChatGlobals(); + CreateDirectoryTreeW(Chat_GetFolderName()); + g_hWindowList = WindowList_Create(); hHookEvent = CreateHookableEvent(ME_GC_HOOK_EVENT); hevMuteChat = CreateHookableEvent(ME_GC_MUTE); @@ -1023,6 +1063,8 @@ void UnloadChatModule(void) if (!bInited) return; + delete pChatGlobals; + FreeMsgLogBitmaps(); OptionsUnInit(); diff --git a/src/mir_app/src/chat_tools.cpp b/src/mir_app/src/chat_tools.cpp index 4b101c4c66..744797f205 100644 --- a/src/mir_app/src/chat_tools.cpp +++ b/src/mir_app/src/chat_tools.cpp @@ -837,3 +837,52 @@ MIR_APP_DLL(int) Chat_GetTextPixelSize(const wchar_t *pszText, HFONT hFont, bool ReleaseDC(nullptr, hdc); return bWidth ? rc.right - rc.left : rc.bottom - rc.top; } + +///////////////////////////////////////////////////////////////////////////////////////// +// Chat serialization + +CMStringW Chat_GetFolderName(SESSION_INFO *si) +{ + CMStringW ret(VARSW(L"%miranda_userdata%\\ChatCache")); + if (si) + ret.AppendFormat(L"\\%d.json", si->hContact); + + return ret; +} + +void Chat_Serialize(SESSION_INFO *si) +{ + si->bIsDirty = false; + + if (!si->pMI->bPersistent) + return; + + JSONNode pRoleList(JSON_ARRAY); pRoleList.set_name("roles"); + for (auto *p = si->pStatuses; p; p = p->next) { + JSONNode role; + role << JSONNode("id", p->iStatus) << JSONNode("name", T2Utf(p->pszGroup).get()); + pRoleList << role; + } + + JSONNode pUserList(JSON_ARRAY); pUserList.set_name("users"); + for (auto &it : si->arUsers) { + JSONNode user; + user << JSONNode("id", T2Utf(it->pszUID).get()) << JSONNode("nick", T2Utf(it->pszNick).get()) << JSONNode("role", it->Status); + pUserList << user; + } + + JSONNode root; + root << pRoleList << pUserList; + if (si->ptszName) + root << JSONNode("name", T2Utf(si->ptszName).get()); + if (si->ptszTopic) + root << JSONNode("topic", T2Utf(si->ptszTopic).get()); + + ptrW wszText(json_write(&root)); + if (wszText) { + if (FILE *out = _wfopen(Chat_GetFolderName(si), L"w")) { + fputs(T2Utf(wszText), out); + fclose(out); + } + } +} diff --git a/src/mir_app/src/chat_ui.cpp b/src/mir_app/src/chat_ui.cpp index 8b08092f8a..aacb22bf8a 100644 --- a/src/mir_app/src/chat_ui.cpp +++ b/src/mir_app/src/chat_ui.cpp @@ -128,8 +128,6 @@ public: void onClick_Log(CCtrlButton *) { InvertColumn(IDC_L1); } }; -///////////////////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// // Popup options diff --git a/src/mir_app/src/stdafx.h b/src/mir_app/src/stdafx.h index cbb17fac19..caf3f20342 100644 --- a/src/mir_app/src/stdafx.h +++ b/src/mir_app/src/stdafx.h @@ -71,16 +71,17 @@ typedef struct SslHandle *HSSL; #include #include #include +#include #include #include +#include #include #include #include #include #include #include -#include -#include +#include #include #include #include -- cgit v1.2.3