From f0173fd8343e7f1469b40ea8372f6b951846f63b Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 29 Feb 2020 21:32:45 +0300 Subject: MessageState: rewritten from scratch to work --- plugins/MessageState/src/clist_extra.cpp | 21 ----- plugins/MessageState/src/global.h | 39 ++++++---- plugins/MessageState/src/messagestate.cpp | 125 +++++++++++++++--------------- plugins/MessageState/src/services.cpp | 38 ++++++--- plugins/MessageState/src/stdafx.h | 1 - plugins/MessageState/src/utils.cpp | 28 ++++--- plugins/MessageState/src/version.h | 6 +- 7 files changed, 139 insertions(+), 119 deletions(-) delete mode 100644 plugins/MessageState/src/clist_extra.cpp (limited to 'plugins/MessageState/src') diff --git a/plugins/MessageState/src/clist_extra.cpp b/plugins/MessageState/src/clist_extra.cpp deleted file mode 100644 index 01a0f52739..0000000000 --- a/plugins/MessageState/src/clist_extra.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "stdafx.h" - -HANDLE hExtraIcon = nullptr; - -int ExtraIconsApply(WPARAM hContact, LPARAM force) -{ - if (hContact != NULL) { - if (HasUnread(hContact) || force) - ExtraIcon_SetIcon(hExtraIcon, hContact, Icons[ICON_EXTRA].hIcolib); - else - ExtraIcon_Clear(hExtraIcon, hContact); - } - - return 0; -} - -void InitClistExtraIcon() -{ - hExtraIcon = ExtraIcon_RegisterIcolib("messagestate_unread", LPGEN("MessageState unread extra icon"), "clist_unread_icon"); - HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, ExtraIconsApply); -} diff --git a/plugins/MessageState/src/global.h b/plugins/MessageState/src/global.h index 9260116846..0413f2535d 100644 --- a/plugins/MessageState/src/global.h +++ b/plugins/MessageState/src/global.h @@ -1,32 +1,43 @@ #ifndef _GLOBAL_H_ #define _GLOBAL_H_ -enum SRMM_ICON_TYPE +///////////////////////////////////////////////////////////////////////////////////////// + +struct ContactData { - ICON_HIDDEN = -1, - ICON_UNREAD, - ICON_READ, - ICON_FAILED, - ICON_NOSENT, - ICON_EXTRA, + ContactData(MCONTACT _p1) : + hContact(_p1) + {} + + MCONTACT hContact; + + int type = -1, bHidden = true; + __time64_t dwLastReadTime = 0, dwLastSentTime = 0; + + void __forceinline setSent(__time64_t _time) + { + dwLastSentTime = _time; + type = 0; + } }; -#define DBKEY_MESSAGE_READ_TIME "LastMsgReadTime" -#define DBKEY_MESSAGE_READ_TIME_TYPE "LastMsgReadTimeType" +extern OBJLIST g_arContacts; + +ContactData* FindContact(MCONTACT); + +///////////////////////////////////////////////////////////////////////////////////////// + __forceinline bool CheckProtoSupport(const char *szProto) { return (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_READNOTIFY) != 0; } void InitServices(); -INT_PTR UpdateService(WPARAM, LPARAM); -int IconsUpdate(MCONTACT); -void SetSRMMIcon(MCONTACT hContact, SRMM_ICON_TYPE type, time_t time = 0); +void IconsUpdate(MCONTACT); +void SetSRMMIcon(MCONTACT hContact, int type, time_t time = 0); time_t GetLastSentMessageTime(MCONTACT hContact); int OnModulesLoaded(WPARAM, LPARAM); bool HasUnread(MCONTACT hContact); -int ExtraIconsApply(WPARAM hContact, LPARAM); -void InitClistExtraIcon(); #endif //_GLOBAL_H_ \ No newline at end of file diff --git a/plugins/MessageState/src/messagestate.cpp b/plugins/MessageState/src/messagestate.cpp index 10735e977c..61a2885639 100644 --- a/plugins/MessageState/src/messagestate.cpp +++ b/plugins/MessageState/src/messagestate.cpp @@ -1,64 +1,66 @@ #include "stdafx.h" -IconItem Icons[] = -{ - { LPGEN("Unread message icon"), "unread_icon", IDI_UNREAD }, - { LPGEN("Read message icon"), "read_icon", IDI_READ }, - { LPGEN("Failed sending icon"), "fail_icon", IDI_FAIL }, - { LPGEN("Sending message icon"), "nosent_icon", IDI_NOSENT }, - { LPGEN("Unread clist extra icon"), "clist_unread_icon", IDI_EXTRA }, -}; - -const wchar_t* Tooltips[] = +static HANDLE hExtraIcon = nullptr; + +int ExtraIconsApply(WPARAM hContact, LPARAM force) { - LPGENW("Last message is not read"), - LPGENW("Last message read"), - LPGENW("Last message was not sent"), - LPGENW("Sending...") -}; + if (hContact != 0) { + if (HasUnread(hContact) || force) + ExtraIcon_SetIcon(hExtraIcon, hContact, g_plugin.getIconHandle(IDI_EXTRA)); + else + ExtraIcon_Clear(hExtraIcon, hContact); + } + + return 0; +} -void SetSRMMIcon(MCONTACT hContact, SRMM_ICON_TYPE type, time_t time) +///////////////////////////////////////////////////////////////////////////////////////// + +void SetSRMMIcon(MCONTACT hContact, int iconId, time_t time) { - MCONTACT hActualContact; - if (db_mc_isMeta(hContact)) - hActualContact = db_mc_getSrmmSub(hContact); - else - hActualContact = hContact; - - if (type != ICON_HIDDEN) { - const wchar_t *pwszToolTip; - if (type == ICON_READ) { - if (g_plugin.getDword(hActualContact, DBKEY_MESSAGE_READ_TIME_TYPE, -1) == MRD_TYPE_READTIME) { - wchar_t buf[100]; - wcsftime(buf, _countof(buf), TranslateT("Last message read at %X %x"), localtime(&time)); - pwszToolTip = buf; - } - else pwszToolTip = TranslateT("Last message read (unknown time)"); + auto *p = FindContact(hContact); + + const wchar_t *pwszToolTip; + switch (iconId) { + case IDI_READ: + // if that contact was never marked as read + if (p->type != -1) { + wchar_t buf[100]; + wcsftime(buf, _countof(buf), TranslateT("Last message read at %X %x"), localtime(&time)); + pwszToolTip = buf; } - else pwszToolTip = TranslateW(Tooltips[type]); - - Srmm_ModifyIcon(hContact, MODULENAME, 1, IcoLib_GetIconByHandle(Icons[type].hIcolib), pwszToolTip); + else pwszToolTip = TranslateT("Last message read"); + break; + + case IDI_UNREAD: pwszToolTip = TranslateT("Last message is not read"); break; + case IDI_FAIL: pwszToolTip = TranslateT("Last message was not sent"); break; + case IDI_NOSENT: pwszToolTip = TranslateT("Sending..."); break; + default: pwszToolTip = nullptr; } - else Srmm_SetIconFlags(hContact, MODULENAME, 1, MBF_HIDDEN); + + Srmm_ModifyIcon(hContact, MODULENAME, 1, g_plugin.getIcon(iconId), pwszToolTip); } -int IconsUpdate(MCONTACT hContact) +void IconsUpdate(MCONTACT hContact) { - MCONTACT hActualContact; - if (db_mc_isMeta(hContact)) - hActualContact = db_mc_getSrmmSub(hContact); - else - hActualContact = hContact; - - time_t readtime = g_plugin.getDword(hActualContact, DBKEY_MESSAGE_READ_TIME, 0); - time_t lasttime = GetLastSentMessageTime(hActualContact); - if (lasttime != -1 && readtime != 0) - SetSRMMIcon(hContact, HasUnread(hActualContact) ? ICON_UNREAD : ICON_READ, readtime); - else - SetSRMMIcon(hContact, ICON_HIDDEN); + auto *p = FindContact(hContact); + + // if we've did nothing with this contact, leave its icon hidden + if (p->type == -1) + return; + + // if that's the first time we show an icon, unhide it first + if (p->bHidden) { + p->bHidden = false; + Srmm_SetIconFlags(hContact, MODULENAME, 1, 0); + } + + SetSRMMIcon(hContact, p->type == MRD_TYPE_DELIVERED ? IDI_UNREAD : IDI_READ, p->dwLastReadTime); ExtraIconsApply(hContact, 0); - return 0; + + if (db_mc_isSub(hContact)) + IconsUpdate(db_mc_getMeta(hContact)); } static int OnProtoAck(WPARAM, LPARAM lParam) @@ -66,9 +68,9 @@ static int OnProtoAck(WPARAM, LPARAM lParam) ACKDATA *pAck = (ACKDATA *)lParam; if (pAck && (pAck->type == ACKTYPE_MESSAGE || pAck->type == ACKTYPE_FILE) && CheckProtoSupport(pAck->szModule)) { if (pAck->result == ACKRESULT_SUCCESS) - SetSRMMIcon(pAck->hContact, ICON_UNREAD); + SetSRMMIcon(pAck->hContact, IDI_NOSENT); else if (pAck->result == ACKRESULT_FAILED) - SetSRMMIcon(pAck->hContact, ICON_FAILED); + SetSRMMIcon(pAck->hContact, IDI_FAIL); ExtraIconsApply(pAck->hContact, 0); } @@ -78,8 +80,14 @@ static int OnProtoAck(WPARAM, LPARAM lParam) static int OnEventFilterAdd(WPARAM hContact, LPARAM lParam) { DBEVENTINFO *dbei = (DBEVENTINFO *)lParam; - if ((dbei->flags & DBEF_SENT) && CheckProtoSupport(dbei->szModule) && db_get_b(hContact, "Tab_SRMsg", "no_ack", 0)) - SetSRMMIcon(hContact, ICON_NOSENT); + if ((dbei->flags & DBEF_SENT) && CheckProtoSupport(dbei->szModule)) { + __time64_t dwTime = _time64(0); + FindContact(hContact)->setSent(dwTime); + if (db_mc_isSub(hContact)) + FindContact(db_mc_getMeta(hContact))->setSent(dwTime); + + SetSRMMIcon(hContact, IDI_NOSENT); + } return 0; } @@ -99,24 +107,19 @@ static int OnMetaChanged(WPARAM hContact, LPARAM) int OnModulesLoaded(WPARAM, LPARAM) { + hExtraIcon = ExtraIcon_RegisterIcolib("messagestate_unread", LPGEN("MessageState unread extra icon"), "clist_unread_icon"); + HookEvent(ME_PROTO_ACK, OnProtoAck); HookEvent(ME_DB_EVENT_FILTER_ADD, OnEventFilterAdd); HookEvent(ME_MC_DEFAULTTCHANGED, OnMetaChanged); HookEvent(ME_MC_SUBCONTACTSCHANGED, OnMetaChanged); HookEvent(ME_MSG_WINDOWEVENT, OnSrmmWindowOpened); - - g_plugin.registerIcon(MODULENAME, Icons); + HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, ExtraIconsApply); StatusIconData sid = {}; sid.szModule = MODULENAME; sid.flags = MBF_HIDDEN; sid.dwId = 1; Srmm_AddIcon(&sid, &g_plugin); - - InitClistExtraIcon(); - - for (auto &hContact : Contacts()) - IconsUpdate(hContact); - return 0; } diff --git a/plugins/MessageState/src/services.cpp b/plugins/MessageState/src/services.cpp index 4e2706d1e5..8e7b6dbe17 100644 --- a/plugins/MessageState/src/services.cpp +++ b/plugins/MessageState/src/services.cpp @@ -1,19 +1,37 @@ #include "stdafx.h" -HANDLE hUpdateService; - -void InitServices() +static IconItem Icons[] = { - hUpdateService = CreateServiceFunction(MS_MESSAGESTATE_UPDATE, UpdateService); -} + { LPGEN("Unread message icon"), "unread_icon", IDI_UNREAD }, + { LPGEN("Read message icon"), "read_icon", IDI_READ }, + { LPGEN("Failed sending icon"), "fail_icon", IDI_FAIL }, + { LPGEN("Sending message icon"), "nosent_icon", IDI_NOSENT }, + { LPGEN("Unread clist extra icon"), "clist_unread_icon", IDI_EXTRA }, +}; -INT_PTR UpdateService(WPARAM hContact, LPARAM lParam) +static INT_PTR UpdateService(WPARAM hContact, LPARAM lParam) { - MessageReadData *mrd = (MessageReadData*)lParam; - if (mrd->dw_lastTime > g_plugin.getDword(hContact, DBKEY_MESSAGE_READ_TIME, 0)) { - g_plugin.setDword(hContact, DBKEY_MESSAGE_READ_TIME, mrd->dw_lastTime); - g_plugin.setDword(hContact, DBKEY_MESSAGE_READ_TIME_TYPE, mrd->iTimeType); + auto *p = FindContact(hContact); + + __time64_t currTime = _time64(0); + if (currTime > p->dwLastReadTime) { + p->dwLastReadTime = currTime; + p->type = lParam; + + if (db_mc_isSub(hContact)) { + p = FindContact(db_mc_getMeta(hContact)); + p->dwLastReadTime = currTime; + p->type = lParam; + } + IconsUpdate(hContact); } return 0; } + +void InitServices() +{ + g_plugin.registerIcon(MODULENAME, Icons); + + CreateServiceFunction(MS_MESSAGESTATE_UPDATE, UpdateService); +} diff --git a/plugins/MessageState/src/stdafx.h b/plugins/MessageState/src/stdafx.h index ce6df98224..8a3d16d073 100644 --- a/plugins/MessageState/src/stdafx.h +++ b/plugins/MessageState/src/stdafx.h @@ -28,4 +28,3 @@ struct CMPlugin : public PLUGIN int Load() override; }; -extern IconItem Icons[]; diff --git a/plugins/MessageState/src/utils.cpp b/plugins/MessageState/src/utils.cpp index 9dd3110133..683e4f8a98 100644 --- a/plugins/MessageState/src/utils.cpp +++ b/plugins/MessageState/src/utils.cpp @@ -1,14 +1,23 @@ #include "stdafx.h" +static mir_cs csContacts; +OBJLIST g_arContacts(50, NumericKeySortT); + +// always returns an object, creates an empty one if missing +ContactData* FindContact(MCONTACT hContact) +{ + mir_cslock lck(csContacts); + + auto *p = g_arContacts.find((ContactData *)&hContact); + if (p == nullptr) + g_arContacts.insert(p = new ContactData(hContact)); + + return p; +} + time_t GetLastSentMessageTime(MCONTACT hContact) { - for (MEVENT hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) { - DBEVENTINFO dbei = {}; - db_event_get(hDbEvent, &dbei); - if (dbei.flags & DBEF_SENT) - return dbei.timestamp; - } - return -1; + return FindContact(hContact)->dwLastSentTime; } bool HasUnread(MCONTACT hContact) @@ -16,8 +25,9 @@ bool HasUnread(MCONTACT hContact) if (!CheckProtoSupport(Proto_GetBaseAccountName(hContact))) return false; - if (GetLastSentMessageTime(hContact) <= g_plugin.getDword(hContact, DBKEY_MESSAGE_READ_TIME, 0)) + auto *p = FindContact(hContact); + if (p->dwLastSentTime <= p->dwLastReadTime) return false; - return g_plugin.getDword(hContact, DBKEY_MESSAGE_READ_TIME, 0) != 0; + return p->dwLastReadTime != 0; } diff --git a/plugins/MessageState/src/version.h b/plugins/MessageState/src/version.h index fced149a92..489f6ab568 100644 --- a/plugins/MessageState/src/version.h +++ b/plugins/MessageState/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 -#define __MINOR_VERSION 0 -#define __RELEASE_NUM 1 -#define __BUILD_NUM 0 +#define __MINOR_VERSION 1 +#define __RELEASE_NUM 0 +#define __BUILD_NUM 1 #include -- cgit v1.2.3