From 78d71d2cad6f243c6ff31d41380b8c5b58407de5 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Thu, 17 May 2012 17:37:22 +0000 Subject: added some plugins git-svn-id: http://svn.miranda-ng.org/main/trunk@20 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/FavContacts/src/contact_cache.cpp | 231 ++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 plugins/FavContacts/src/contact_cache.cpp (limited to 'plugins/FavContacts/src/contact_cache.cpp') diff --git a/plugins/FavContacts/src/contact_cache.cpp b/plugins/FavContacts/src/contact_cache.cpp new file mode 100644 index 0000000000..c61635cc26 --- /dev/null +++ b/plugins/FavContacts/src/contact_cache.cpp @@ -0,0 +1,231 @@ +#include "headers.h" +#include +#include + +int __cdecl CContactCache::OnDbEventAdded(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + HANDLE hEvent = (HANDLE)lParam; + + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei); + if (dbei.eventType != EVENTTYPE_MESSAGE) return 0; + + float weight = GetEventWeight(time(NULL) - dbei.timestamp); + float q = GetTimeWeight(time(NULL) - m_lastUpdate); + m_lastUpdate = time(NULL); + if (!weight) return 0; + + Lock(); + bool found = false; + for (int i = 0; i < m_cache.getCount(); ++i) + { + m_cache[i].rate *= q; + if (m_cache[i].hContact == hContact) + { + found = true; + m_cache[i].rate += weight; + } + } + + if (!found) + { + TContactInfo *info = new TContactInfo; + info->hContact = hContact; + info->rate = weight; + m_cache.insert(info); + } else + { + qsort(m_cache.getArray(), m_cache.getCount(), sizeof(TContactInfo *), TContactInfo::cmp2); + } + + Unlock(); + return 0; +} + +float CContactCache::GetEventWeight(unsigned long age) +{ + const float ceil = 1000.f; + const float floor = 0.0001f; + const int depth = 60 * 60 * 24 * 30; + if (age > depth) return 0; + return exp(log(ceil) - age * (log(ceil) - log(floor)) / depth); +} + +float CContactCache::GetTimeWeight(unsigned long age) +{ + const float ceil = 1000.f; + const float floor = 0.0001f; + const int depth = 60 * 60 * 24 * 30; + if (age > depth) return 0; + return exp(age * (log(ceil) - log(floor)) / depth); +} + +CContactCache::CContactCache(): m_cache(50, TContactInfo::cmp) +{ + InitializeCriticalSection(&m_cs); + + int (__cdecl CContactCache::*pfn)(WPARAM, LPARAM); + pfn = &CContactCache::OnDbEventAdded; + m_hOnDbEventAdded = HookEventObj(ME_DB_EVENT_ADDED, *(MIRANDAHOOKOBJ *)&pfn, this); + + Rebuild(); +} + +CContactCache::~CContactCache() +{ + UnhookEvent(m_hOnDbEventAdded); + DeleteCriticalSection(&m_cs); +} + +void CContactCache::Rebuild() +{ + unsigned long timestamp = time(NULL); + m_lastUpdate = time(NULL); + + HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while (hContact) + { + TContactInfo *info = new TContactInfo; + info->hContact = hContact; + info->rate = 0; + + HANDLE hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDLAST, (WPARAM)hContact, 0); + while (hEvent) + { + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(dbei); + if (!CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&dbei)) + { + if (float weight = GetEventWeight(timestamp - dbei.timestamp)) + { + if (dbei.eventType == EVENTTYPE_MESSAGE) + info->rate += weight; + } else + { + break; + } + } + hEvent = (HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hEvent, 0); + } + + m_cache.insert(info); + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + } +} + +HANDLE CContactCache::get(int rate) +{ + if (rate >= 0 && rate < m_cache.getCount()) + return m_cache[rate].hContact; + return NULL; +} + +float CContactCache::getWeight(int rate) +{ + if (rate >= 0 && rate < m_cache.getCount()) + return m_cache[rate].rate; + return -1; +} + +static bool AppendInfo(TCHAR *buf, int size, HANDLE hContact, int info) +{ + CONTACTINFO ci = {0}; + ci.cbSize = sizeof(ci); + ci.hContact = hContact; + ci.dwFlag = info; +#if defined(UNICODE) || defined(_UNICODE) + ci.dwFlag |= CNF_UNICODE; +#endif + + bool ret = false; + + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci) && (ci.type == CNFT_ASCIIZ) && ci.pszVal) + { + if (*ci.pszVal && (lstrlen(ci.pszVal) < size-2)) + { + lstrcpy(buf, ci.pszVal); + ret = true; + } + mir_free(ci.pszVal); + } + + return ret; +} + +void CContactCache::TContactInfo::LoadInfo() +{ + if (infoLoaded) return; + TCHAR *p = info; + + p[0] = p[1] = 0; + + static const int items[] = { + CNF_FIRSTNAME, CNF_LASTNAME, CNF_NICK , CNF_CUSTOMNICK, CNF_EMAIL, CNF_CITY, CNF_STATE, + CNF_COUNTRY, CNF_PHONE, CNF_HOMEPAGE, CNF_ABOUT, CNF_UNIQUEID, CNF_MYNOTES, CNF_STREET, + CNF_CONAME, CNF_CODEPT, CNF_COCITY, CNF_COSTATE, CNF_COSTREET, CNF_COCOUNTRY + }; + + for (int i = 0; i < SIZEOF(items); ++i) + { + if (AppendInfo(p, SIZEOF(info) - (p - info), hContact, items[i])) + p += lstrlen(p) + 1; + } + *p = 0; + + infoLoaded = true; +} + +TCHAR *nb_stristr(TCHAR *str, TCHAR *substr) +{ + if (!substr || !*substr) return str; + if (!str || !*str) return NULL; + + TCHAR *str_up = NEWTSTR_ALLOCA(str); + TCHAR *substr_up = NEWTSTR_ALLOCA(substr); + + CharUpperBuff(str_up, lstrlen(str_up)); + CharUpperBuff(substr_up, lstrlen(substr_up)); + + TCHAR* p = _tcsstr(str_up, substr_up); + return p ? (str + (p - str_up)) : NULL; +} + +bool CContactCache::filter(int rate, TCHAR *str) +{ + if (!str || !*str) + return true; + m_cache[rate].LoadInfo(); + + HKL kbdLayoutActive = GetKeyboardLayout(GetCurrentThreadId()); + HKL kbdLayouts[10]; + int nKbdLayouts = GetKeyboardLayoutList(SIZEOF(kbdLayouts), kbdLayouts); + + TCHAR buf[256]; + BYTE keyState[256] = {0}; + + for (int iLayout = 0; iLayout < nKbdLayouts; ++iLayout) + { + if (kbdLayoutActive == kbdLayouts[iLayout]) + { + lstrcpy(buf, str); + } else + { + int i; + for (i = 0; str[i]; ++i) + { + UINT vk = VkKeyScanEx(str[i], kbdLayoutActive); + UINT scan = MapVirtualKeyEx(vk, 0, kbdLayoutActive); + ToUnicodeEx(vk, scan, keyState, buf+i, SIZEOF(buf)-i, 0, kbdLayouts[iLayout]); + } + buf[i] = 0; + } + + for (TCHAR *p = m_cache[rate].info; p && *p; p = p + lstrlen(p) + 1) + if (nb_stristr(p, buf)) + return true; + } + + return false; +} -- cgit v1.2.3