From 1979fd80424d16b2e489f9b57d01d9c7811d25a2 Mon Sep 17 00:00:00 2001 From: dartraiden Date: Mon, 2 Jan 2023 21:10:29 +0300 Subject: Update copyrights --- plugins/FingerprintNG/src/fingerprint.cpp | 1826 ++++++++++++++--------------- plugins/FingerprintNG/src/main.cpp | 2 +- plugins/FingerprintNG/src/masks.cpp | 2 +- plugins/FingerprintNG/src/options.cpp | 2 +- plugins/FingerprintNG/src/stdafx.cxx | 2 +- plugins/FingerprintNG/src/stdafx.h | 2 +- plugins/FingerprintNG/src/version.h | 4 +- 7 files changed, 920 insertions(+), 920 deletions(-) (limited to 'plugins/FingerprintNG/src') diff --git a/plugins/FingerprintNG/src/fingerprint.cpp b/plugins/FingerprintNG/src/fingerprint.cpp index 0842cc1007..e15f77536d 100644 --- a/plugins/FingerprintNG/src/fingerprint.cpp +++ b/plugins/FingerprintNG/src/fingerprint.cpp @@ -1,913 +1,913 @@ -fv/* -Fingerprint NG (client version) icons module for Miranda NG -Copyright © 2006-22 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. - -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; either version 2 -of the License, or (at your option) any later version. - -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, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -//Start of header -#include "stdafx.h" - -static UINT g_LPCodePage; -static wchar_t g_szSkinLib[MAX_PATH]; -static HANDLE hExtraIcon = nullptr; -static HANDLE hFolderChanged = nullptr, hIconFolder = nullptr; - -static int CompareFI(const FOUNDINFO *p1, const FOUNDINFO *p2) -{ - if (p1->iBase != p2->iBase) - return p1->iBase - p2->iBase; - return p1->iOverlay - p2->iOverlay; -} - -static OBJLIST arFI(50, CompareFI); - -static LIST arMonitoredWindows(3, PtrKeySortT); - -static INT_PTR ServiceGetClientIconW(WPARAM wParam, LPARAM lParam); - -/* -* Prepare -* prepares upperstring masks and registers them in IcoLib -*/ - -static wchar_t* getSectionName(int flag) -{ - switch (flag) - { -#include "finger_groups.h" - } - return nullptr; -} - -void __fastcall Prepare(KN_FP_MASK* mask, bool bEnable) -{ - mask->szMaskUpper = nullptr; - - if (mask->hIcolibItem) - IcoLib_RemoveIcon(mask->szIconName); - mask->hIcolibItem = nullptr; - - if (!mask->szMask || !bEnable) - return; - - size_t iMaskLen = mir_wstrlen(mask->szMask) + 1; - LPTSTR pszNewMask = (LPTSTR)HeapAlloc(hHeap, HEAP_NO_SERIALIZE, iMaskLen * sizeof(wchar_t)); - wcscpy_s(pszNewMask, iMaskLen, mask->szMask); - _wcsupr_s(pszNewMask, iMaskLen); - mask->szMaskUpper = pszNewMask; - - wchar_t destfile[MAX_PATH]; - if (mask->iIconIndex == IDI_NOTFOUND || mask->iIconIndex == IDI_UNKNOWN || mask->iIconIndex == IDI_UNDETECTED) - GetModuleFileName(g_plugin.getInst(), destfile, MAX_PATH); - else { - wcsncpy_s(destfile, g_szSkinLib, _TRUNCATE); - - struct _stat64i32 stFileInfo; - if (_wstat(destfile, &stFileInfo) == -1) - return; - } - - LPTSTR SectName = getSectionName(mask->iSectionFlag); - if (SectName == nullptr) - return; - - SKINICONDESC sid = {}; - sid.flags = SIDF_ALL_UNICODE; - sid.section.w = SectName; - sid.pszName = mask->szIconName; - sid.description.w = mask->szClientDescription; - sid.defaultFile.w = destfile; - sid.iDefaultIndex = -mask->iIconIndex; - mask->hIcolibItem = g_plugin.addIcon(&sid); -} - -/* -* Register icons -*/ - -void RegisterIcons() -{ - // prepare masks - int i; - - if (hHeap) - HeapDestroy(hHeap); - hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0); - - for (i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) - Prepare(&def_kn_fp_mask[i], true); - - for (i = 0; i < DEFAULT_KN_FP_OVERLAYS_COUNT; i++) - Prepare(&def_kn_fp_overlays_mask[i], true); - - if (g_plugin.getByte("GroupMirandaVersion", 0)) { - for (i = 0; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) - Prepare(&def_kn_fp_overlays2_mask[i], true); - } - else { - for (i = 0; i < DEFAULT_KN_FP_OVERLAYS2_NO_VER_COUNT; i++) - Prepare(&def_kn_fp_overlays2_mask[i], true); - for (; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) - Prepare(&def_kn_fp_overlays2_mask[i], false); - } - - if (g_plugin.getByte("GroupOverlaysUnicode", 1)) { - for (i = 0; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) - Prepare(&def_kn_fp_overlays3_mask[i], true); - } - else { - for (i = 0; i < DEFAULT_KN_FP_OVERLAYS3_NO_UNICODE_COUNT; i++) - Prepare(&def_kn_fp_overlays3_mask[i], true); - for (; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) - Prepare(&def_kn_fp_overlays3_mask[i], false); - } - - for (i = 0; i < DEFAULT_KN_FP_OVERLAYS4_COUNT; i++) - Prepare(&def_kn_fp_overlays4_mask[i], true); -} - -/* ApplyFingerprintImage -* 1)Try to find appropriate mask -* 2)Register icon in extraimage list if not yet registered (EMPTY_EXTRA_ICON) -* 3)Set ExtraImage for contact -*/ - -static void SetSrmmIcon(MCONTACT hContact, LPTSTR ptszMirver) -{ - if (mir_wstrlen(ptszMirver)) - Srmm_ModifyIcon(hContact, MODULENAME, 1, (HICON)ServiceGetClientIconW((WPARAM)ptszMirver, TRUE), ptszMirver); - else - Srmm_SetIconFlags(hContact, MODULENAME, 1, MBF_HIDDEN); -} - -int __fastcall ApplyFingerprintImage(MCONTACT hContact, LPTSTR szMirVer) -{ - if (hContact == NULL) - return 0; - - HANDLE hImage = INVALID_HANDLE_VALUE; - if (szMirVer) - hImage = GetIconIndexFromFI(szMirVer); - - ExtraIcon_SetIcon(hExtraIcon, hContact, hImage); - - if (arMonitoredWindows.getIndex((HANDLE)hContact) != -1) - SetSrmmIcon(hContact, szMirVer); - - return 0; -} - -int OnExtraIconClick(WPARAM wParam, LPARAM, LPARAM) -{ - CallService(MS_USERINFO_SHOWDIALOG, wParam, NULL); - return 0; -} - - -/* -* WildCompare -* Compare 'name' string with 'mask' strings. -* Masks can contain '*' or '?' wild symbols -* Asterics '*' symbol covers 'empty' symbol too e.g WildCompare("Tst","T*st*"), returns TRUE -* In order to handle situation 'at least one any sybol' use "?*" combination: -* e.g WildCompare("Tst","T?*st*"), returns FALSE, but both WildCompare("Test","T?*st*") and -* WildCompare("Teeest","T?*st*") return TRUE. -* -* Function is case sensitive! so convert input or modify func to use _qtoupper() -* -* Mask can contain several submasks. In this case each submask (including first) -* should start from '|' e.g: "|first*submask|second*mask". -* -* Dec 25, 2006 by FYR: -* Added Exception to masks: the mask "|^mask3|mask2|mask1" means: -* if NOT according to mask 3 AND (mask1 OR mask2) -* EXCEPTION should be BEFORE main mask: -* IF Exception match - the comparing stops as FALSE -* IF Exception does not match - comparing continue -* IF Mask match - comparing stops as TRUE -* IF Mask does not not match comparing continue -*/ -BOOL __fastcall WildCompare(LPWSTR wszName, LPWSTR wszMask) -{ - if (wszMask == nullptr) - return NULL; - - if (*wszMask != L'|') - return wildcmpw(wszName, wszMask); - - size_t s = 1, e = 1; - LPWSTR wszTemp = (LPWSTR)_alloca(mir_wstrlen(wszMask) * sizeof(wchar_t) + sizeof(wchar_t)); - BOOL bExcept; - - while (wszMask[e] != L'\0') - { - s = e; - while (wszMask[e] != L'\0' && wszMask[e] != L'|') e++; - - // exception mask - bExcept = (*(wszMask + s) == L'^'); - if (bExcept) s++; - - memcpy(wszTemp, wszMask + s, (e - s) * sizeof(wchar_t)); - wszTemp[e - s] = L'\0'; - - if (wildcmpw(wszName, wszTemp)) - return !bExcept; - - if (wszMask[e] != L'\0') - e++; - else - return FALSE; - } - return FALSE; -} - -static void MatchMasks(wchar_t* szMirVer, int *base, int *overlay, int *overlay2, int *overlay3, int *overlay4) -{ - int i = 0, j = -1, k = -1, n = -1, m = -1; - - for (i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) { - KN_FP_MASK& p = def_kn_fp_mask[i]; - if (p.hIcolibItem == nullptr) - continue; - - if (!WildCompare(szMirVer, p.szMaskUpper)) - continue; - - if (p.iIconIndex != IDI_NOTFOUND && p.iIconIndex != IDI_UNKNOWN && p.iIconIndex != IDI_UNDETECTED) { - wchar_t destfile[MAX_PATH]; - wcsncpy_s(destfile, g_szSkinLib, _TRUNCATE); - - struct _stat64i32 stFileInfo; - if (_wstat(destfile, &stFileInfo) == -1) - i = NOTFOUND_MASK_NUMBER; - } - break; - } - if (i == DEFAULT_KN_FP_MASK_COUNT - 1) - i = -1; - - else if (!def_kn_fp_mask[i].fNotUseOverlay && i < DEFAULT_KN_FP_MASK_COUNT) { - for (j = 0; j < DEFAULT_KN_FP_OVERLAYS_COUNT; j++) { - KN_FP_MASK& p = def_kn_fp_overlays_mask[j]; - if (p.hIcolibItem == nullptr) - continue; - - if (!WildCompare(szMirVer, p.szMaskUpper)) - continue; - - struct _stat64i32 stFileInfo; - if (_wstat(g_szSkinLib, &stFileInfo) != -1) - break; - } - - for (k = 0; k < DEFAULT_KN_FP_OVERLAYS2_COUNT; k++) { - KN_FP_MASK& p = def_kn_fp_overlays2_mask[k]; - if (p.hIcolibItem == nullptr) - continue; - - if (WildCompare(szMirVer, p.szMaskUpper)) - break; - } - - for (n = 0; n < DEFAULT_KN_FP_OVERLAYS3_COUNT; n++) { - KN_FP_MASK& p = def_kn_fp_overlays3_mask[n]; - if (p.hIcolibItem == nullptr) - continue; - - if (WildCompare(szMirVer, p.szMaskUpper)) - break; - } - - for (m = 0; m < DEFAULT_KN_FP_OVERLAYS4_COUNT; m++) { - KN_FP_MASK& p = def_kn_fp_overlays4_mask[m]; - if (p.hIcolibItem == nullptr) - continue; - - if (WildCompare(szMirVer, p.szMaskUpper)) - break; - } - } - - *base = (i < DEFAULT_KN_FP_MASK_COUNT) ? i : -1; - *overlay = (j < DEFAULT_KN_FP_OVERLAYS_COUNT) ? j : -1; - *overlay2 = (k < DEFAULT_KN_FP_OVERLAYS2_COUNT) ? k : -1; - *overlay3 = (n < DEFAULT_KN_FP_OVERLAYS3_COUNT) ? n : -1; - *overlay4 = (m < DEFAULT_KN_FP_OVERLAYS4_COUNT) ? m : -1; -} - -/* GetIconsIndexes -* Retrieves Icons indexes by Mirver -*/ - -void __fastcall GetIconsIndexes(LPWSTR wszMirVer, int *base, int *overlay, int *overlay2, int *overlay3, int *overlay4) -{ - if (mir_wstrcmp(wszMirVer, L"?") == 0) { - *base = UNKNOWN_MASK_NUMBER; - *overlay = -1; - *overlay2 = -1; - *overlay3 = -1; - *overlay4 = -1; - return; - } - - LPWSTR wszMirVerUp = NEWWSTR_ALLOCA(wszMirVer); - _wcsupr(wszMirVerUp); - MatchMasks(wszMirVerUp, base, overlay, overlay2, overlay3, overlay4); -} - -/* -* CreateIconFromIndexes -* returns hIcon of joined icon by given indexes -*/ - -HICON __fastcall CreateIconFromIndexes(int base, int overlay, int overlay2, int overlay3, int overlay4) -{ - HICON hIcon = nullptr; // returned HICON - HICON hTmp = nullptr; - HICON icMain = nullptr; - HICON icOverlay = nullptr; - HICON icOverlay2 = nullptr; - HICON icOverlay3 = nullptr; - HICON icOverlay4 = nullptr; - - KN_FP_MASK* mainMask = &(def_kn_fp_mask[base]); - icMain = IcoLib_GetIconByHandle(mainMask->hIcolibItem); - - if (icMain) { - KN_FP_MASK* overlayMask = (overlay != -1) ? &(def_kn_fp_overlays_mask[overlay]) : nullptr; - KN_FP_MASK* overlay2Mask = (overlay2 != -1) ? &(def_kn_fp_overlays2_mask[overlay2]) : nullptr; - KN_FP_MASK* overlay3Mask = (overlay3 != -1) ? &(def_kn_fp_overlays3_mask[overlay3]) : nullptr; - KN_FP_MASK* overlay4Mask = (overlay4 != -1) ? &(def_kn_fp_overlays4_mask[overlay4]) : nullptr; - icOverlay = (overlayMask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlayMask->hIcolibItem); - icOverlay2 = (overlay2Mask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlay2Mask->hIcolibItem); - icOverlay3 = (overlay3Mask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlay3Mask->hIcolibItem); - icOverlay4 = (overlay4Mask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlay4Mask->hIcolibItem); - - hIcon = icMain; - - if (overlayMask) - hTmp = hIcon = CreateJoinedIcon(hIcon, icOverlay); - - if (overlay2Mask) { - hIcon = CreateJoinedIcon(hIcon, icOverlay2); - if (hTmp) DestroyIcon(hTmp); - hTmp = hIcon; - } - - if (overlay3Mask) { - hIcon = CreateJoinedIcon(hIcon, icOverlay3); - if (hTmp) DestroyIcon(hTmp); - hTmp = hIcon; - } - - if (overlay4Mask) { - hIcon = CreateJoinedIcon(hIcon, icOverlay4); - if (hTmp) DestroyIcon(hTmp); - } - } - - if (hIcon == icMain) - hIcon = CopyIcon(icMain); - - IcoLib_ReleaseIcon(icMain); - IcoLib_ReleaseIcon(icOverlay); - IcoLib_ReleaseIcon(icOverlay2); - IcoLib_ReleaseIcon(icOverlay3); - IcoLib_ReleaseIcon(icOverlay4); - return hIcon; -} - -/****************************************************************************** - * Futher routines is for creating joined 'overlay' icons. - ******************************************************************************/ - - /* - * CreateBitmap32 - Create DIB 32 bitmap with sizes cx*cy - */ - -HBITMAP __inline CreateBitmap32(int cx, int cy) -{ - return CreateBitmap32Point(cx, cy, nullptr); -} - -/* -* CreateBitmap32 - Create DIB 32 bitmap with sizes cx*cy and put reference -* to new bitmap pixel image memory area to void ** bits -*/ -HBITMAP __fastcall CreateBitmap32Point(int cx, int cy, LPVOID* bits) -{ - LPVOID ptPixels = nullptr; - - if (cx < 0 || cy < 0) return nullptr; - - BITMAPINFO bmpi = { 0 }; - bmpi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); - bmpi.bmiHeader.biWidth = cx; - bmpi.bmiHeader.biHeight = cy; - bmpi.bmiHeader.biPlanes = 1; - bmpi.bmiHeader.biBitCount = 32; - HBITMAP DirectBitmap = CreateDIBSection(nullptr, &bmpi, DIB_RGB_COLORS, &ptPixels, nullptr, 0); - - GdiFlush(); - if (ptPixels) memset(ptPixels, 0, cx * cy * 4); - if (bits != nullptr) *bits = ptPixels; - - return DirectBitmap; -} - -/* -* checkHasAlfa - checks if image has at least one uint8_t in alpha channel -* that is not a 0. (is image real 32 bit or just 24 bit) -*/ -BOOL __fastcall checkHasAlfa(LPBYTE from, int width, int height) -{ - LPDWORD pt = (LPDWORD)from; - LPDWORD lim = pt + width * height; - while (pt < lim) - { - if (*pt & 0xFF000000) - return TRUE; - pt++; - } - - return FALSE; -} - -/* -* checkMaskUsed - checks if mask image has at least one that is not a 0. -* Not sure is it required or not -*/ -BOOL __fastcall checkMaskUsed(LPBYTE from) -{ - int i; - for (i = 0; i < 16 * 16 / 8; i++) - { - if (from[i] != 0) return TRUE; - } - return FALSE; -} - -/* -* GetMaskBit - return value of apropriate mask bit in line at x position -*/ -BOOL __inline GetMaskBit(LPBYTE line, int x) -{ - return ((*(line + (x >> 3))) & (0x01 << (7 - (x & 0x07)))) != 0; -} - -/* -* blend - alpha blend ARGB values of 2 pixels. X1 - underlaying, -* X2 - overlaying points. -*/ -uint32_t __fastcall blend(uint32_t X1, uint32_t X2) -{ - RGBA* q1 = (RGBA*)&X1; - RGBA* q2 = (RGBA*)&X2; - uint8_t a_1 = ~q1->a; - uint8_t a_2 = ~q2->a; - uint16_t am = q1->a * a_2; - - uint16_t ar = q1->a + ((a_1 * q2->a) / 255); - // if a2 more than 0 than result should be more - // or equal (if a1==0) to a2, else in combination - // with mask we can get here black points - - ar = (q2->a > ar) ? q2->a : ar; - - if (ar == 0) return 0; - - { - uint16_t arm = ar * 255; - uint16_t rr = ((q1->r * am + q2->r * q2->a * 255)) / arm; - uint16_t gr = ((q1->g * am + q2->g * q2->a * 255)) / arm; - uint16_t br = ((q1->b * am + q2->b * q2->a * 255)) / arm; - return (ar << 24) | (rr << 16) | (gr << 8) | br; - } -} - -/* -* CreateJoinedIcon - creates new icon by drawing hTop over hBottom. -*/ -HICON __fastcall CreateJoinedIcon(HICON hBottom, HICON hTop) -{ - BOOL drawn = FALSE; - HDC tempDC, tempDC2, tempDC3; - HICON res = nullptr; - HBITMAP oImage, nImage; - HBITMAP nMask, hbm, obmp, obmp2; - LPBYTE ptPixels = nullptr; - ICONINFO iNew = { 0 }; - uint8_t p[32] = { 0 }; - - tempDC = CreateCompatibleDC(nullptr); - nImage = CreateBitmap32Point(16, 16, (LPVOID*)&ptPixels); - oImage = (HBITMAP)SelectObject(tempDC, nImage); - - ICONINFO iciBottom = { 0 }; - ICONINFO iciTop = { 0 }; - - BITMAP bmp_top = { 0 }; - BITMAP bmp_top_mask = { 0 }; - - BITMAP bmp_bottom = { 0 }; - BITMAP bmp_bottom_mask = { 0 }; - - GetIconInfo(hBottom, &iciBottom); - GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom); - GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask); - - GetIconInfo(hTop, &iciTop); - GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top); - GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask); - - if (bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) - { - LPBYTE BottomBuffer, TopBuffer, BottomMaskBuffer, TopMaskBuffer; - LPBYTE bb, tb, bmb, tmb; - LPBYTE db = ptPixels; - int vstep_d = 16 * 4; - int vstep_b = bmp_bottom.bmWidthBytes; - int vstep_t = bmp_top.bmWidthBytes; - int vstep_bm = bmp_bottom_mask.bmWidthBytes; - int vstep_tm = bmp_top_mask.bmWidthBytes; - - if (bmp_bottom.bmBits) - bb = BottomBuffer = (LPBYTE)bmp_bottom.bmBits; - else - { - BottomBuffer = (LPBYTE)_alloca(bmp_bottom.bmHeight * bmp_bottom.bmWidthBytes); - GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight * bmp_bottom.bmWidthBytes, BottomBuffer); - bb = BottomBuffer + vstep_b * (bmp_bottom.bmHeight - 1); - vstep_b = -vstep_b; - } - if (bmp_top.bmBits) - tb = TopBuffer = (LPBYTE)bmp_top.bmBits; - else - { - TopBuffer = (LPBYTE)_alloca(bmp_top.bmHeight * bmp_top.bmWidthBytes); - GetBitmapBits(iciTop.hbmColor, bmp_top.bmHeight * bmp_top.bmWidthBytes, TopBuffer); - tb = TopBuffer + vstep_t * (bmp_top.bmHeight - 1); - vstep_t = -vstep_t; - } - if (bmp_bottom_mask.bmBits) - bmb = BottomMaskBuffer = (LPBYTE)bmp_bottom_mask.bmBits; - else - { - BottomMaskBuffer = (LPBYTE)_alloca(bmp_bottom_mask.bmHeight * bmp_bottom_mask.bmWidthBytes); - GetBitmapBits(iciBottom.hbmMask, bmp_bottom_mask.bmHeight * bmp_bottom_mask.bmWidthBytes, BottomMaskBuffer); - bmb = BottomMaskBuffer + vstep_bm * (bmp_bottom_mask.bmHeight - 1); - vstep_bm = -vstep_bm; - } - if (bmp_top_mask.bmBits) - tmb = TopMaskBuffer = (LPBYTE)bmp_top_mask.bmBits; - else - { - TopMaskBuffer = (LPBYTE)_alloca(bmp_top_mask.bmHeight * bmp_top_mask.bmWidthBytes); - GetBitmapBits(iciTop.hbmMask, bmp_top_mask.bmHeight * bmp_top_mask.bmWidthBytes, TopMaskBuffer); - tmb = TopMaskBuffer + vstep_tm * (bmp_top_mask.bmHeight - 1); - vstep_tm = -vstep_tm; - } - { - int x; int y; - BOOL topHasAlpha = checkHasAlfa(TopBuffer, bmp_top.bmWidth, bmp_top.bmHeight); - BOOL bottomHasAlpha = checkHasAlfa(BottomBuffer, bmp_bottom.bmWidth, bmp_bottom.bmHeight); - BOOL topMaskUsed = !topHasAlpha && checkMaskUsed(TopMaskBuffer); - BOOL bottomMaskUsed = !bottomHasAlpha && checkMaskUsed(BottomMaskBuffer); - - for (y = 0; y < 16; y++) - { - for (x = 0; x < 16; x++) - { - uint32_t bottom_d = ((LPDWORD)bb)[x]; - uint32_t top_d = ((LPDWORD)tb)[x]; - - if (topMaskUsed) - { - if (GetMaskBit(tmb, x)) - top_d &= 0x00FFFFFF; - else - top_d |= 0xFF000000; - } - else if (!topHasAlpha) - top_d |= 0xFF000000; - - if (bottomMaskUsed) - { - if (GetMaskBit(bmb, x)) - bottom_d &= 0x00FFFFFF; - else - bottom_d |= 0xFF000000; - } - else if (!bottomHasAlpha) - bottom_d |= 0xFF000000; - - ((LPDWORD)db)[x] = blend(bottom_d, top_d); - } - bb += vstep_b; - tb += vstep_t; - bmb += vstep_bm; - tmb += vstep_tm; - db += vstep_d; - } - } - - drawn = TRUE; - } - - DeleteObject(iciBottom.hbmColor); - DeleteObject(iciTop.hbmColor); - DeleteObject(iciBottom.hbmMask); - DeleteObject(iciTop.hbmMask); - - if (!drawn) { - DrawIconEx(tempDC, 0, 0, hBottom, 16, 16, 0, nullptr, DI_NORMAL); - DrawIconEx(tempDC, 0, 0, hTop, 16, 16, 0, nullptr, DI_NORMAL); - } - - nMask = CreateBitmap(16, 16, 1, 1, p); - tempDC2 = CreateCompatibleDC(nullptr); - tempDC3 = CreateCompatibleDC(nullptr); - hbm = CreateCompatibleBitmap(tempDC3, 16, 16); - obmp = (HBITMAP)SelectObject(tempDC2, nMask); - obmp2 = (HBITMAP)SelectObject(tempDC3, hbm); - DrawIconEx(tempDC2, 0, 0, hBottom, 16, 16, 0, nullptr, DI_MASK); - DrawIconEx(tempDC3, 0, 0, hTop, 16, 16, 0, nullptr, DI_MASK); - BitBlt(tempDC2, 0, 0, 16, 16, tempDC3, 0, 0, SRCAND); - - GdiFlush(); - - SelectObject(tempDC2, obmp); - DeleteDC(tempDC2); - - SelectObject(tempDC3, obmp2); - DeleteDC(tempDC3); - - SelectObject(tempDC, oImage); - DeleteDC(tempDC); - - DeleteObject(hbm); - - iNew.fIcon = TRUE; - iNew.hbmColor = nImage; - iNew.hbmMask = nMask; - res = CreateIconIndirect(&iNew); - - DeleteObject(nImage); - DeleteObject(nMask); - - return res; -} - -HANDLE __fastcall GetIconIndexFromFI(LPTSTR szMirVer) -{ - int base, overlay, overlay2, overlay3, overlay4; - GetIconsIndexes(szMirVer, &base, &overlay, &overlay2, &overlay3, &overlay4); - if (base == -1) - return INVALID_HANDLE_VALUE; - - // MAX: 256 + 64 + 64 + 64 + 64 - FOUNDINFO tmp = { base, ((overlay & 0xFF) << 18) | ((overlay2 & 0x3F) << 12) | ((overlay3 & 0x3F) << 6) | (overlay4 & 0x3F) }; - auto *F = arFI.find(&tmp); - if (F != nullptr) - return F->hRegisteredImage; - - // not found - then add - F = new FOUNDINFO(tmp); - HICON hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3, overlay4); - if (hIcon != nullptr) { - F->hRegisteredImage = ExtraIcon_AddIcon(hIcon); - DestroyIcon(hIcon); - } - else F->hRegisteredImage = INVALID_HANDLE_VALUE; - - arFI.insert(F); - - return F->hRegisteredImage; -} - -VOID ClearFI() -{ - arFI.destroy(); -} - -/**************************************************************************************** -* ServiceGetClientIconW -* MS_FP_GETCLIENTICONW service implementation. -* wParam - LPWSTR MirVer value to get client for. -* lParam - int noCopy - if wParam is equal to "1" will return icon handler without copiing icon. -* ICON IS ALWAYS COPIED!!! -*/ - -static INT_PTR ServiceGetClientIconW(WPARAM wParam, LPARAM) -{ - LPWSTR wszMirVer = (LPWSTR)wParam; // MirVer value to get client for. - if (wszMirVer == nullptr) - return 0; - - int base, overlay, overlay2, overlay3, overlay4; - GetIconsIndexes(wszMirVer, &base, &overlay, &overlay2, &overlay3, &overlay4); - - HICON hIcon = nullptr; // returned HICON - if (base != -1) - hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3, overlay4); - - return (INT_PTR)hIcon; -} - -/**************************************************************************************** - * ServiceGetClientDescrW - * MS_FP_GETCLIENTDESCRW service implementation. - * wParam - LPCWSTR MirVer value - * lParam - (NULL) unused - * returns LPCWSTR: client description (do not destroy) or NULL - */ - -static INT_PTR ServiceGetClientDescrW(WPARAM wParam, LPARAM) -{ - LPWSTR wszMirVer = (LPWSTR)wParam; // MirVer value to get client for. - if (wszMirVer == nullptr) - return 0; - - LPWSTR wszMirVerUp = NEWWSTR_ALLOCA(wszMirVer); _wcsupr(wszMirVerUp); - if (mir_wstrcmp(wszMirVerUp, L"?") == 0) - return (INT_PTR)def_kn_fp_mask[UNKNOWN_MASK_NUMBER].szClientDescription; - - for (int index = 0; index < DEFAULT_KN_FP_MASK_COUNT; index++) - if (WildCompare(wszMirVerUp, def_kn_fp_mask[index].szMaskUpper)) - return (INT_PTR)def_kn_fp_mask[index].szClientDescription; - - return NULL; -} - -/**************************************************************************************** - * ServiceSameClientW - * MS_FP_SAMECLIENTSW service implementation. - * wParam - LPWSTR first MirVer value - * lParam - LPWSTR second MirVer value - * returns LPCWSTR: client description (do not destroy) if clients are same or NULL - */ - -static INT_PTR ServiceSameClientsW(WPARAM wParam, LPARAM lParam) -{ - if (!wParam || !lParam) - return NULL; //one of its is not null - - INT_PTR res1 = ServiceGetClientDescrW(wParam, 0); - INT_PTR res2 = ServiceGetClientDescrW(lParam, 0); - return (res1 == res2 && res1 != 0) ? res1 : NULL; -} - -/**************************************************************************************** -* OnExtraIconListRebuild -* Set all registered indexes in array to EMPTY_EXTRA_ICON (unregistered icon) -*/ - -static int OnExtraIconListRebuild(WPARAM, LPARAM) -{ - ClearFI(); - return 0; -} - -/**************************************************************************************** -* OnIconsChanged -*/ - -static int OnIconsChanged(WPARAM, LPARAM) -{ - ClearFI(); - return 0; -} - -/**************************************************************************************** -* OnExtraImageApply -* Try to get MirVer value from db for contact and if success calls ApplyFingerprintImage -*/ - -int OnExtraImageApply(WPARAM hContact, LPARAM) -{ - if (hContact == NULL) - return 0; - - ptrW tszMirver; - char *szProto = Proto_GetBaseAccountName(hContact); - if (szProto != nullptr) - tszMirver = db_get_wsa(hContact, szProto, "MirVer"); - - ApplyFingerprintImage(hContact, tszMirver); - return 0; -} - -/**************************************************************************************** -* OnContactSettingChanged -* if contact settings changed apply new image or remove it -*/ - -static int OnContactSettingChanged(WPARAM hContact, LPARAM lParam) -{ - if (hContact == NULL) - return 0; - - DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; - if (cws && cws->szSetting && !strcmp(cws->szSetting, "MirVer")) { - switch (cws->value.type) { - case DBVT_UTF8: - ApplyFingerprintImage(hContact, ptrW(mir_utf8decodeW(cws->value.pszVal))); - break; - case DBVT_ASCIIZ: - ApplyFingerprintImage(hContact, _A2T(cws->value.pszVal)); - break; - case DBVT_WCHAR: - ApplyFingerprintImage(hContact, cws->value.pwszVal); - break; - default: - ApplyFingerprintImage(hContact, nullptr); - } - } - return 0; -} - -/**************************************************************************************** -* OnSrmmWindowEvent -* Monitors SRMM window's creation to draw a statusbar icon -*/ - -static int OnSrmmWindowEvent(WPARAM, LPARAM lParam) -{ - if (!g_plugin.getByte("StatusBarIcon", 1)) - return 0; - - MessageWindowEventData *event = (MessageWindowEventData *)lParam; - if (event == nullptr) - return 0; - - if (event->uType == MSG_WINDOW_EVT_OPEN) { - ptrW ptszMirVer; - char *szProto = Proto_GetBaseAccountName(event->hContact); - if (szProto != nullptr) - ptszMirVer = db_get_wsa(event->hContact, szProto, "MirVer"); - SetSrmmIcon(event->hContact, ptszMirVer); - arMonitoredWindows.insert((HANDLE)event->hContact); - } - else if (event->uType == MSG_WINDOW_EVT_CLOSE) - arMonitoredWindows.remove((HANDLE)event->hContact); - - return 0; -} - -/**************************************************************************************** -* OnModulesLoaded -* Hook necessary events here -*/ - -int OnModulesLoaded(WPARAM, LPARAM) -{ - g_LPCodePage = Langpack_GetDefaultCodePage(); - - //Hook necessary events - HookEvent(ME_SKIN_ICONSCHANGED, OnIconsChanged); - HookEvent(ME_MSG_WINDOWEVENT, OnSrmmWindowEvent); - - HookEvent(ME_MC_DEFAULTTCHANGED, OnExtraImageApply); - - PathToAbsoluteW(DEFAULT_SKIN_FOLDER, g_szSkinLib); - - RegisterIcons(); - - hExtraIcon = ExtraIcon_RegisterCallback("Client", LPGEN("Fingerprint"), "client_Miranda_unknown", - OnExtraIconListRebuild, OnExtraImageApply, OnExtraIconClick); - - if (g_plugin.getByte("StatusBarIcon", 1)) { - StatusIconData sid = {}; - sid.szModule = MODULENAME; - sid.flags = MBF_HIDDEN; - sid.dwId = 1; - Srmm_AddIcon(&sid, &g_plugin); - } - - return 0; -} - -void InitFingerModule() -{ - HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); - HookEvent(ME_OPT_INITIALISE, OnOptInitialise); - HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged); - - CreateServiceFunction(MS_FP_SAMECLIENTSW, ServiceSameClientsW); - CreateServiceFunction(MS_FP_GETCLIENTDESCRW, ServiceGetClientDescrW); - CreateServiceFunction(MS_FP_GETCLIENTICONW, ServiceGetClientIconW); -} +fv/* +Fingerprint NG (client version) icons module for Miranda NG +Copyright © 2006-23 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. + +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; either version 2 +of the License, or (at your option) any later version. + +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, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +//Start of header +#include "stdafx.h" + +static UINT g_LPCodePage; +static wchar_t g_szSkinLib[MAX_PATH]; +static HANDLE hExtraIcon = nullptr; +static HANDLE hFolderChanged = nullptr, hIconFolder = nullptr; + +static int CompareFI(const FOUNDINFO *p1, const FOUNDINFO *p2) +{ + if (p1->iBase != p2->iBase) + return p1->iBase - p2->iBase; + return p1->iOverlay - p2->iOverlay; +} + +static OBJLIST arFI(50, CompareFI); + +static LIST arMonitoredWindows(3, PtrKeySortT); + +static INT_PTR ServiceGetClientIconW(WPARAM wParam, LPARAM lParam); + +/* +* Prepare +* prepares upperstring masks and registers them in IcoLib +*/ + +static wchar_t* getSectionName(int flag) +{ + switch (flag) + { +#include "finger_groups.h" + } + return nullptr; +} + +void __fastcall Prepare(KN_FP_MASK* mask, bool bEnable) +{ + mask->szMaskUpper = nullptr; + + if (mask->hIcolibItem) + IcoLib_RemoveIcon(mask->szIconName); + mask->hIcolibItem = nullptr; + + if (!mask->szMask || !bEnable) + return; + + size_t iMaskLen = mir_wstrlen(mask->szMask) + 1; + LPTSTR pszNewMask = (LPTSTR)HeapAlloc(hHeap, HEAP_NO_SERIALIZE, iMaskLen * sizeof(wchar_t)); + wcscpy_s(pszNewMask, iMaskLen, mask->szMask); + _wcsupr_s(pszNewMask, iMaskLen); + mask->szMaskUpper = pszNewMask; + + wchar_t destfile[MAX_PATH]; + if (mask->iIconIndex == IDI_NOTFOUND || mask->iIconIndex == IDI_UNKNOWN || mask->iIconIndex == IDI_UNDETECTED) + GetModuleFileName(g_plugin.getInst(), destfile, MAX_PATH); + else { + wcsncpy_s(destfile, g_szSkinLib, _TRUNCATE); + + struct _stat64i32 stFileInfo; + if (_wstat(destfile, &stFileInfo) == -1) + return; + } + + LPTSTR SectName = getSectionName(mask->iSectionFlag); + if (SectName == nullptr) + return; + + SKINICONDESC sid = {}; + sid.flags = SIDF_ALL_UNICODE; + sid.section.w = SectName; + sid.pszName = mask->szIconName; + sid.description.w = mask->szClientDescription; + sid.defaultFile.w = destfile; + sid.iDefaultIndex = -mask->iIconIndex; + mask->hIcolibItem = g_plugin.addIcon(&sid); +} + +/* +* Register icons +*/ + +void RegisterIcons() +{ + // prepare masks + int i; + + if (hHeap) + HeapDestroy(hHeap); + hHeap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0); + + for (i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) + Prepare(&def_kn_fp_mask[i], true); + + for (i = 0; i < DEFAULT_KN_FP_OVERLAYS_COUNT; i++) + Prepare(&def_kn_fp_overlays_mask[i], true); + + if (g_plugin.getByte("GroupMirandaVersion", 0)) { + for (i = 0; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) + Prepare(&def_kn_fp_overlays2_mask[i], true); + } + else { + for (i = 0; i < DEFAULT_KN_FP_OVERLAYS2_NO_VER_COUNT; i++) + Prepare(&def_kn_fp_overlays2_mask[i], true); + for (; i < DEFAULT_KN_FP_OVERLAYS2_COUNT; i++) + Prepare(&def_kn_fp_overlays2_mask[i], false); + } + + if (g_plugin.getByte("GroupOverlaysUnicode", 1)) { + for (i = 0; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) + Prepare(&def_kn_fp_overlays3_mask[i], true); + } + else { + for (i = 0; i < DEFAULT_KN_FP_OVERLAYS3_NO_UNICODE_COUNT; i++) + Prepare(&def_kn_fp_overlays3_mask[i], true); + for (; i < DEFAULT_KN_FP_OVERLAYS3_COUNT; i++) + Prepare(&def_kn_fp_overlays3_mask[i], false); + } + + for (i = 0; i < DEFAULT_KN_FP_OVERLAYS4_COUNT; i++) + Prepare(&def_kn_fp_overlays4_mask[i], true); +} + +/* ApplyFingerprintImage +* 1)Try to find appropriate mask +* 2)Register icon in extraimage list if not yet registered (EMPTY_EXTRA_ICON) +* 3)Set ExtraImage for contact +*/ + +static void SetSrmmIcon(MCONTACT hContact, LPTSTR ptszMirver) +{ + if (mir_wstrlen(ptszMirver)) + Srmm_ModifyIcon(hContact, MODULENAME, 1, (HICON)ServiceGetClientIconW((WPARAM)ptszMirver, TRUE), ptszMirver); + else + Srmm_SetIconFlags(hContact, MODULENAME, 1, MBF_HIDDEN); +} + +int __fastcall ApplyFingerprintImage(MCONTACT hContact, LPTSTR szMirVer) +{ + if (hContact == NULL) + return 0; + + HANDLE hImage = INVALID_HANDLE_VALUE; + if (szMirVer) + hImage = GetIconIndexFromFI(szMirVer); + + ExtraIcon_SetIcon(hExtraIcon, hContact, hImage); + + if (arMonitoredWindows.getIndex((HANDLE)hContact) != -1) + SetSrmmIcon(hContact, szMirVer); + + return 0; +} + +int OnExtraIconClick(WPARAM wParam, LPARAM, LPARAM) +{ + CallService(MS_USERINFO_SHOWDIALOG, wParam, NULL); + return 0; +} + + +/* +* WildCompare +* Compare 'name' string with 'mask' strings. +* Masks can contain '*' or '?' wild symbols +* Asterics '*' symbol covers 'empty' symbol too e.g WildCompare("Tst","T*st*"), returns TRUE +* In order to handle situation 'at least one any sybol' use "?*" combination: +* e.g WildCompare("Tst","T?*st*"), returns FALSE, but both WildCompare("Test","T?*st*") and +* WildCompare("Teeest","T?*st*") return TRUE. +* +* Function is case sensitive! so convert input or modify func to use _qtoupper() +* +* Mask can contain several submasks. In this case each submask (including first) +* should start from '|' e.g: "|first*submask|second*mask". +* +* Dec 25, 2006 by FYR: +* Added Exception to masks: the mask "|^mask3|mask2|mask1" means: +* if NOT according to mask 3 AND (mask1 OR mask2) +* EXCEPTION should be BEFORE main mask: +* IF Exception match - the comparing stops as FALSE +* IF Exception does not match - comparing continue +* IF Mask match - comparing stops as TRUE +* IF Mask does not not match comparing continue +*/ +BOOL __fastcall WildCompare(LPWSTR wszName, LPWSTR wszMask) +{ + if (wszMask == nullptr) + return NULL; + + if (*wszMask != L'|') + return wildcmpw(wszName, wszMask); + + size_t s = 1, e = 1; + LPWSTR wszTemp = (LPWSTR)_alloca(mir_wstrlen(wszMask) * sizeof(wchar_t) + sizeof(wchar_t)); + BOOL bExcept; + + while (wszMask[e] != L'\0') + { + s = e; + while (wszMask[e] != L'\0' && wszMask[e] != L'|') e++; + + // exception mask + bExcept = (*(wszMask + s) == L'^'); + if (bExcept) s++; + + memcpy(wszTemp, wszMask + s, (e - s) * sizeof(wchar_t)); + wszTemp[e - s] = L'\0'; + + if (wildcmpw(wszName, wszTemp)) + return !bExcept; + + if (wszMask[e] != L'\0') + e++; + else + return FALSE; + } + return FALSE; +} + +static void MatchMasks(wchar_t* szMirVer, int *base, int *overlay, int *overlay2, int *overlay3, int *overlay4) +{ + int i = 0, j = -1, k = -1, n = -1, m = -1; + + for (i = 0; i < DEFAULT_KN_FP_MASK_COUNT; i++) { + KN_FP_MASK& p = def_kn_fp_mask[i]; + if (p.hIcolibItem == nullptr) + continue; + + if (!WildCompare(szMirVer, p.szMaskUpper)) + continue; + + if (p.iIconIndex != IDI_NOTFOUND && p.iIconIndex != IDI_UNKNOWN && p.iIconIndex != IDI_UNDETECTED) { + wchar_t destfile[MAX_PATH]; + wcsncpy_s(destfile, g_szSkinLib, _TRUNCATE); + + struct _stat64i32 stFileInfo; + if (_wstat(destfile, &stFileInfo) == -1) + i = NOTFOUND_MASK_NUMBER; + } + break; + } + if (i == DEFAULT_KN_FP_MASK_COUNT - 1) + i = -1; + + else if (!def_kn_fp_mask[i].fNotUseOverlay && i < DEFAULT_KN_FP_MASK_COUNT) { + for (j = 0; j < DEFAULT_KN_FP_OVERLAYS_COUNT; j++) { + KN_FP_MASK& p = def_kn_fp_overlays_mask[j]; + if (p.hIcolibItem == nullptr) + continue; + + if (!WildCompare(szMirVer, p.szMaskUpper)) + continue; + + struct _stat64i32 stFileInfo; + if (_wstat(g_szSkinLib, &stFileInfo) != -1) + break; + } + + for (k = 0; k < DEFAULT_KN_FP_OVERLAYS2_COUNT; k++) { + KN_FP_MASK& p = def_kn_fp_overlays2_mask[k]; + if (p.hIcolibItem == nullptr) + continue; + + if (WildCompare(szMirVer, p.szMaskUpper)) + break; + } + + for (n = 0; n < DEFAULT_KN_FP_OVERLAYS3_COUNT; n++) { + KN_FP_MASK& p = def_kn_fp_overlays3_mask[n]; + if (p.hIcolibItem == nullptr) + continue; + + if (WildCompare(szMirVer, p.szMaskUpper)) + break; + } + + for (m = 0; m < DEFAULT_KN_FP_OVERLAYS4_COUNT; m++) { + KN_FP_MASK& p = def_kn_fp_overlays4_mask[m]; + if (p.hIcolibItem == nullptr) + continue; + + if (WildCompare(szMirVer, p.szMaskUpper)) + break; + } + } + + *base = (i < DEFAULT_KN_FP_MASK_COUNT) ? i : -1; + *overlay = (j < DEFAULT_KN_FP_OVERLAYS_COUNT) ? j : -1; + *overlay2 = (k < DEFAULT_KN_FP_OVERLAYS2_COUNT) ? k : -1; + *overlay3 = (n < DEFAULT_KN_FP_OVERLAYS3_COUNT) ? n : -1; + *overlay4 = (m < DEFAULT_KN_FP_OVERLAYS4_COUNT) ? m : -1; +} + +/* GetIconsIndexes +* Retrieves Icons indexes by Mirver +*/ + +void __fastcall GetIconsIndexes(LPWSTR wszMirVer, int *base, int *overlay, int *overlay2, int *overlay3, int *overlay4) +{ + if (mir_wstrcmp(wszMirVer, L"?") == 0) { + *base = UNKNOWN_MASK_NUMBER; + *overlay = -1; + *overlay2 = -1; + *overlay3 = -1; + *overlay4 = -1; + return; + } + + LPWSTR wszMirVerUp = NEWWSTR_ALLOCA(wszMirVer); + _wcsupr(wszMirVerUp); + MatchMasks(wszMirVerUp, base, overlay, overlay2, overlay3, overlay4); +} + +/* +* CreateIconFromIndexes +* returns hIcon of joined icon by given indexes +*/ + +HICON __fastcall CreateIconFromIndexes(int base, int overlay, int overlay2, int overlay3, int overlay4) +{ + HICON hIcon = nullptr; // returned HICON + HICON hTmp = nullptr; + HICON icMain = nullptr; + HICON icOverlay = nullptr; + HICON icOverlay2 = nullptr; + HICON icOverlay3 = nullptr; + HICON icOverlay4 = nullptr; + + KN_FP_MASK* mainMask = &(def_kn_fp_mask[base]); + icMain = IcoLib_GetIconByHandle(mainMask->hIcolibItem); + + if (icMain) { + KN_FP_MASK* overlayMask = (overlay != -1) ? &(def_kn_fp_overlays_mask[overlay]) : nullptr; + KN_FP_MASK* overlay2Mask = (overlay2 != -1) ? &(def_kn_fp_overlays2_mask[overlay2]) : nullptr; + KN_FP_MASK* overlay3Mask = (overlay3 != -1) ? &(def_kn_fp_overlays3_mask[overlay3]) : nullptr; + KN_FP_MASK* overlay4Mask = (overlay4 != -1) ? &(def_kn_fp_overlays4_mask[overlay4]) : nullptr; + icOverlay = (overlayMask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlayMask->hIcolibItem); + icOverlay2 = (overlay2Mask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlay2Mask->hIcolibItem); + icOverlay3 = (overlay3Mask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlay3Mask->hIcolibItem); + icOverlay4 = (overlay4Mask == nullptr) ? nullptr : IcoLib_GetIconByHandle(overlay4Mask->hIcolibItem); + + hIcon = icMain; + + if (overlayMask) + hTmp = hIcon = CreateJoinedIcon(hIcon, icOverlay); + + if (overlay2Mask) { + hIcon = CreateJoinedIcon(hIcon, icOverlay2); + if (hTmp) DestroyIcon(hTmp); + hTmp = hIcon; + } + + if (overlay3Mask) { + hIcon = CreateJoinedIcon(hIcon, icOverlay3); + if (hTmp) DestroyIcon(hTmp); + hTmp = hIcon; + } + + if (overlay4Mask) { + hIcon = CreateJoinedIcon(hIcon, icOverlay4); + if (hTmp) DestroyIcon(hTmp); + } + } + + if (hIcon == icMain) + hIcon = CopyIcon(icMain); + + IcoLib_ReleaseIcon(icMain); + IcoLib_ReleaseIcon(icOverlay); + IcoLib_ReleaseIcon(icOverlay2); + IcoLib_ReleaseIcon(icOverlay3); + IcoLib_ReleaseIcon(icOverlay4); + return hIcon; +} + +/****************************************************************************** + * Futher routines is for creating joined 'overlay' icons. + ******************************************************************************/ + + /* + * CreateBitmap32 - Create DIB 32 bitmap with sizes cx*cy + */ + +HBITMAP __inline CreateBitmap32(int cx, int cy) +{ + return CreateBitmap32Point(cx, cy, nullptr); +} + +/* +* CreateBitmap32 - Create DIB 32 bitmap with sizes cx*cy and put reference +* to new bitmap pixel image memory area to void ** bits +*/ +HBITMAP __fastcall CreateBitmap32Point(int cx, int cy, LPVOID* bits) +{ + LPVOID ptPixels = nullptr; + + if (cx < 0 || cy < 0) return nullptr; + + BITMAPINFO bmpi = { 0 }; + bmpi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmpi.bmiHeader.biWidth = cx; + bmpi.bmiHeader.biHeight = cy; + bmpi.bmiHeader.biPlanes = 1; + bmpi.bmiHeader.biBitCount = 32; + HBITMAP DirectBitmap = CreateDIBSection(nullptr, &bmpi, DIB_RGB_COLORS, &ptPixels, nullptr, 0); + + GdiFlush(); + if (ptPixels) memset(ptPixels, 0, cx * cy * 4); + if (bits != nullptr) *bits = ptPixels; + + return DirectBitmap; +} + +/* +* checkHasAlfa - checks if image has at least one uint8_t in alpha channel +* that is not a 0. (is image real 32 bit or just 24 bit) +*/ +BOOL __fastcall checkHasAlfa(LPBYTE from, int width, int height) +{ + LPDWORD pt = (LPDWORD)from; + LPDWORD lim = pt + width * height; + while (pt < lim) + { + if (*pt & 0xFF000000) + return TRUE; + pt++; + } + + return FALSE; +} + +/* +* checkMaskUsed - checks if mask image has at least one that is not a 0. +* Not sure is it required or not +*/ +BOOL __fastcall checkMaskUsed(LPBYTE from) +{ + int i; + for (i = 0; i < 16 * 16 / 8; i++) + { + if (from[i] != 0) return TRUE; + } + return FALSE; +} + +/* +* GetMaskBit - return value of apropriate mask bit in line at x position +*/ +BOOL __inline GetMaskBit(LPBYTE line, int x) +{ + return ((*(line + (x >> 3))) & (0x01 << (7 - (x & 0x07)))) != 0; +} + +/* +* blend - alpha blend ARGB values of 2 pixels. X1 - underlaying, +* X2 - overlaying points. +*/ +uint32_t __fastcall blend(uint32_t X1, uint32_t X2) +{ + RGBA* q1 = (RGBA*)&X1; + RGBA* q2 = (RGBA*)&X2; + uint8_t a_1 = ~q1->a; + uint8_t a_2 = ~q2->a; + uint16_t am = q1->a * a_2; + + uint16_t ar = q1->a + ((a_1 * q2->a) / 255); + // if a2 more than 0 than result should be more + // or equal (if a1==0) to a2, else in combination + // with mask we can get here black points + + ar = (q2->a > ar) ? q2->a : ar; + + if (ar == 0) return 0; + + { + uint16_t arm = ar * 255; + uint16_t rr = ((q1->r * am + q2->r * q2->a * 255)) / arm; + uint16_t gr = ((q1->g * am + q2->g * q2->a * 255)) / arm; + uint16_t br = ((q1->b * am + q2->b * q2->a * 255)) / arm; + return (ar << 24) | (rr << 16) | (gr << 8) | br; + } +} + +/* +* CreateJoinedIcon - creates new icon by drawing hTop over hBottom. +*/ +HICON __fastcall CreateJoinedIcon(HICON hBottom, HICON hTop) +{ + BOOL drawn = FALSE; + HDC tempDC, tempDC2, tempDC3; + HICON res = nullptr; + HBITMAP oImage, nImage; + HBITMAP nMask, hbm, obmp, obmp2; + LPBYTE ptPixels = nullptr; + ICONINFO iNew = { 0 }; + uint8_t p[32] = { 0 }; + + tempDC = CreateCompatibleDC(nullptr); + nImage = CreateBitmap32Point(16, 16, (LPVOID*)&ptPixels); + oImage = (HBITMAP)SelectObject(tempDC, nImage); + + ICONINFO iciBottom = { 0 }; + ICONINFO iciTop = { 0 }; + + BITMAP bmp_top = { 0 }; + BITMAP bmp_top_mask = { 0 }; + + BITMAP bmp_bottom = { 0 }; + BITMAP bmp_bottom_mask = { 0 }; + + GetIconInfo(hBottom, &iciBottom); + GetObject(iciBottom.hbmColor, sizeof(BITMAP), &bmp_bottom); + GetObject(iciBottom.hbmMask, sizeof(BITMAP), &bmp_bottom_mask); + + GetIconInfo(hTop, &iciTop); + GetObject(iciTop.hbmColor, sizeof(BITMAP), &bmp_top); + GetObject(iciTop.hbmMask, sizeof(BITMAP), &bmp_top_mask); + + if (bmp_bottom.bmBitsPixel == 32 && bmp_top.bmBitsPixel == 32) + { + LPBYTE BottomBuffer, TopBuffer, BottomMaskBuffer, TopMaskBuffer; + LPBYTE bb, tb, bmb, tmb; + LPBYTE db = ptPixels; + int vstep_d = 16 * 4; + int vstep_b = bmp_bottom.bmWidthBytes; + int vstep_t = bmp_top.bmWidthBytes; + int vstep_bm = bmp_bottom_mask.bmWidthBytes; + int vstep_tm = bmp_top_mask.bmWidthBytes; + + if (bmp_bottom.bmBits) + bb = BottomBuffer = (LPBYTE)bmp_bottom.bmBits; + else + { + BottomBuffer = (LPBYTE)_alloca(bmp_bottom.bmHeight * bmp_bottom.bmWidthBytes); + GetBitmapBits(iciBottom.hbmColor, bmp_bottom.bmHeight * bmp_bottom.bmWidthBytes, BottomBuffer); + bb = BottomBuffer + vstep_b * (bmp_bottom.bmHeight - 1); + vstep_b = -vstep_b; + } + if (bmp_top.bmBits) + tb = TopBuffer = (LPBYTE)bmp_top.bmBits; + else + { + TopBuffer = (LPBYTE)_alloca(bmp_top.bmHeight * bmp_top.bmWidthBytes); + GetBitmapBits(iciTop.hbmColor, bmp_top.bmHeight * bmp_top.bmWidthBytes, TopBuffer); + tb = TopBuffer + vstep_t * (bmp_top.bmHeight - 1); + vstep_t = -vstep_t; + } + if (bmp_bottom_mask.bmBits) + bmb = BottomMaskBuffer = (LPBYTE)bmp_bottom_mask.bmBits; + else + { + BottomMaskBuffer = (LPBYTE)_alloca(bmp_bottom_mask.bmHeight * bmp_bottom_mask.bmWidthBytes); + GetBitmapBits(iciBottom.hbmMask, bmp_bottom_mask.bmHeight * bmp_bottom_mask.bmWidthBytes, BottomMaskBuffer); + bmb = BottomMaskBuffer + vstep_bm * (bmp_bottom_mask.bmHeight - 1); + vstep_bm = -vstep_bm; + } + if (bmp_top_mask.bmBits) + tmb = TopMaskBuffer = (LPBYTE)bmp_top_mask.bmBits; + else + { + TopMaskBuffer = (LPBYTE)_alloca(bmp_top_mask.bmHeight * bmp_top_mask.bmWidthBytes); + GetBitmapBits(iciTop.hbmMask, bmp_top_mask.bmHeight * bmp_top_mask.bmWidthBytes, TopMaskBuffer); + tmb = TopMaskBuffer + vstep_tm * (bmp_top_mask.bmHeight - 1); + vstep_tm = -vstep_tm; + } + { + int x; int y; + BOOL topHasAlpha = checkHasAlfa(TopBuffer, bmp_top.bmWidth, bmp_top.bmHeight); + BOOL bottomHasAlpha = checkHasAlfa(BottomBuffer, bmp_bottom.bmWidth, bmp_bottom.bmHeight); + BOOL topMaskUsed = !topHasAlpha && checkMaskUsed(TopMaskBuffer); + BOOL bottomMaskUsed = !bottomHasAlpha && checkMaskUsed(BottomMaskBuffer); + + for (y = 0; y < 16; y++) + { + for (x = 0; x < 16; x++) + { + uint32_t bottom_d = ((LPDWORD)bb)[x]; + uint32_t top_d = ((LPDWORD)tb)[x]; + + if (topMaskUsed) + { + if (GetMaskBit(tmb, x)) + top_d &= 0x00FFFFFF; + else + top_d |= 0xFF000000; + } + else if (!topHasAlpha) + top_d |= 0xFF000000; + + if (bottomMaskUsed) + { + if (GetMaskBit(bmb, x)) + bottom_d &= 0x00FFFFFF; + else + bottom_d |= 0xFF000000; + } + else if (!bottomHasAlpha) + bottom_d |= 0xFF000000; + + ((LPDWORD)db)[x] = blend(bottom_d, top_d); + } + bb += vstep_b; + tb += vstep_t; + bmb += vstep_bm; + tmb += vstep_tm; + db += vstep_d; + } + } + + drawn = TRUE; + } + + DeleteObject(iciBottom.hbmColor); + DeleteObject(iciTop.hbmColor); + DeleteObject(iciBottom.hbmMask); + DeleteObject(iciTop.hbmMask); + + if (!drawn) { + DrawIconEx(tempDC, 0, 0, hBottom, 16, 16, 0, nullptr, DI_NORMAL); + DrawIconEx(tempDC, 0, 0, hTop, 16, 16, 0, nullptr, DI_NORMAL); + } + + nMask = CreateBitmap(16, 16, 1, 1, p); + tempDC2 = CreateCompatibleDC(nullptr); + tempDC3 = CreateCompatibleDC(nullptr); + hbm = CreateCompatibleBitmap(tempDC3, 16, 16); + obmp = (HBITMAP)SelectObject(tempDC2, nMask); + obmp2 = (HBITMAP)SelectObject(tempDC3, hbm); + DrawIconEx(tempDC2, 0, 0, hBottom, 16, 16, 0, nullptr, DI_MASK); + DrawIconEx(tempDC3, 0, 0, hTop, 16, 16, 0, nullptr, DI_MASK); + BitBlt(tempDC2, 0, 0, 16, 16, tempDC3, 0, 0, SRCAND); + + GdiFlush(); + + SelectObject(tempDC2, obmp); + DeleteDC(tempDC2); + + SelectObject(tempDC3, obmp2); + DeleteDC(tempDC3); + + SelectObject(tempDC, oImage); + DeleteDC(tempDC); + + DeleteObject(hbm); + + iNew.fIcon = TRUE; + iNew.hbmColor = nImage; + iNew.hbmMask = nMask; + res = CreateIconIndirect(&iNew); + + DeleteObject(nImage); + DeleteObject(nMask); + + return res; +} + +HANDLE __fastcall GetIconIndexFromFI(LPTSTR szMirVer) +{ + int base, overlay, overlay2, overlay3, overlay4; + GetIconsIndexes(szMirVer, &base, &overlay, &overlay2, &overlay3, &overlay4); + if (base == -1) + return INVALID_HANDLE_VALUE; + + // MAX: 256 + 64 + 64 + 64 + 64 + FOUNDINFO tmp = { base, ((overlay & 0xFF) << 18) | ((overlay2 & 0x3F) << 12) | ((overlay3 & 0x3F) << 6) | (overlay4 & 0x3F) }; + auto *F = arFI.find(&tmp); + if (F != nullptr) + return F->hRegisteredImage; + + // not found - then add + F = new FOUNDINFO(tmp); + HICON hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3, overlay4); + if (hIcon != nullptr) { + F->hRegisteredImage = ExtraIcon_AddIcon(hIcon); + DestroyIcon(hIcon); + } + else F->hRegisteredImage = INVALID_HANDLE_VALUE; + + arFI.insert(F); + + return F->hRegisteredImage; +} + +VOID ClearFI() +{ + arFI.destroy(); +} + +/**************************************************************************************** +* ServiceGetClientIconW +* MS_FP_GETCLIENTICONW service implementation. +* wParam - LPWSTR MirVer value to get client for. +* lParam - int noCopy - if wParam is equal to "1" will return icon handler without copiing icon. +* ICON IS ALWAYS COPIED!!! +*/ + +static INT_PTR ServiceGetClientIconW(WPARAM wParam, LPARAM) +{ + LPWSTR wszMirVer = (LPWSTR)wParam; // MirVer value to get client for. + if (wszMirVer == nullptr) + return 0; + + int base, overlay, overlay2, overlay3, overlay4; + GetIconsIndexes(wszMirVer, &base, &overlay, &overlay2, &overlay3, &overlay4); + + HICON hIcon = nullptr; // returned HICON + if (base != -1) + hIcon = CreateIconFromIndexes(base, overlay, overlay2, overlay3, overlay4); + + return (INT_PTR)hIcon; +} + +/**************************************************************************************** + * ServiceGetClientDescrW + * MS_FP_GETCLIENTDESCRW service implementation. + * wParam - LPCWSTR MirVer value + * lParam - (NULL) unused + * returns LPCWSTR: client description (do not destroy) or NULL + */ + +static INT_PTR ServiceGetClientDescrW(WPARAM wParam, LPARAM) +{ + LPWSTR wszMirVer = (LPWSTR)wParam; // MirVer value to get client for. + if (wszMirVer == nullptr) + return 0; + + LPWSTR wszMirVerUp = NEWWSTR_ALLOCA(wszMirVer); _wcsupr(wszMirVerUp); + if (mir_wstrcmp(wszMirVerUp, L"?") == 0) + return (INT_PTR)def_kn_fp_mask[UNKNOWN_MASK_NUMBER].szClientDescription; + + for (int index = 0; index < DEFAULT_KN_FP_MASK_COUNT; index++) + if (WildCompare(wszMirVerUp, def_kn_fp_mask[index].szMaskUpper)) + return (INT_PTR)def_kn_fp_mask[index].szClientDescription; + + return NULL; +} + +/**************************************************************************************** + * ServiceSameClientW + * MS_FP_SAMECLIENTSW service implementation. + * wParam - LPWSTR first MirVer value + * lParam - LPWSTR second MirVer value + * returns LPCWSTR: client description (do not destroy) if clients are same or NULL + */ + +static INT_PTR ServiceSameClientsW(WPARAM wParam, LPARAM lParam) +{ + if (!wParam || !lParam) + return NULL; //one of its is not null + + INT_PTR res1 = ServiceGetClientDescrW(wParam, 0); + INT_PTR res2 = ServiceGetClientDescrW(lParam, 0); + return (res1 == res2 && res1 != 0) ? res1 : NULL; +} + +/**************************************************************************************** +* OnExtraIconListRebuild +* Set all registered indexes in array to EMPTY_EXTRA_ICON (unregistered icon) +*/ + +static int OnExtraIconListRebuild(WPARAM, LPARAM) +{ + ClearFI(); + return 0; +} + +/**************************************************************************************** +* OnIconsChanged +*/ + +static int OnIconsChanged(WPARAM, LPARAM) +{ + ClearFI(); + return 0; +} + +/**************************************************************************************** +* OnExtraImageApply +* Try to get MirVer value from db for contact and if success calls ApplyFingerprintImage +*/ + +int OnExtraImageApply(WPARAM hContact, LPARAM) +{ + if (hContact == NULL) + return 0; + + ptrW tszMirver; + char *szProto = Proto_GetBaseAccountName(hContact); + if (szProto != nullptr) + tszMirver = db_get_wsa(hContact, szProto, "MirVer"); + + ApplyFingerprintImage(hContact, tszMirver); + return 0; +} + +/**************************************************************************************** +* OnContactSettingChanged +* if contact settings changed apply new image or remove it +*/ + +static int OnContactSettingChanged(WPARAM hContact, LPARAM lParam) +{ + if (hContact == NULL) + return 0; + + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; + if (cws && cws->szSetting && !strcmp(cws->szSetting, "MirVer")) { + switch (cws->value.type) { + case DBVT_UTF8: + ApplyFingerprintImage(hContact, ptrW(mir_utf8decodeW(cws->value.pszVal))); + break; + case DBVT_ASCIIZ: + ApplyFingerprintImage(hContact, _A2T(cws->value.pszVal)); + break; + case DBVT_WCHAR: + ApplyFingerprintImage(hContact, cws->value.pwszVal); + break; + default: + ApplyFingerprintImage(hContact, nullptr); + } + } + return 0; +} + +/**************************************************************************************** +* OnSrmmWindowEvent +* Monitors SRMM window's creation to draw a statusbar icon +*/ + +static int OnSrmmWindowEvent(WPARAM, LPARAM lParam) +{ + if (!g_plugin.getByte("StatusBarIcon", 1)) + return 0; + + MessageWindowEventData *event = (MessageWindowEventData *)lParam; + if (event == nullptr) + return 0; + + if (event->uType == MSG_WINDOW_EVT_OPEN) { + ptrW ptszMirVer; + char *szProto = Proto_GetBaseAccountName(event->hContact); + if (szProto != nullptr) + ptszMirVer = db_get_wsa(event->hContact, szProto, "MirVer"); + SetSrmmIcon(event->hContact, ptszMirVer); + arMonitoredWindows.insert((HANDLE)event->hContact); + } + else if (event->uType == MSG_WINDOW_EVT_CLOSE) + arMonitoredWindows.remove((HANDLE)event->hContact); + + return 0; +} + +/**************************************************************************************** +* OnModulesLoaded +* Hook necessary events here +*/ + +int OnModulesLoaded(WPARAM, LPARAM) +{ + g_LPCodePage = Langpack_GetDefaultCodePage(); + + //Hook necessary events + HookEvent(ME_SKIN_ICONSCHANGED, OnIconsChanged); + HookEvent(ME_MSG_WINDOWEVENT, OnSrmmWindowEvent); + + HookEvent(ME_MC_DEFAULTTCHANGED, OnExtraImageApply); + + PathToAbsoluteW(DEFAULT_SKIN_FOLDER, g_szSkinLib); + + RegisterIcons(); + + hExtraIcon = ExtraIcon_RegisterCallback("Client", LPGEN("Fingerprint"), "client_Miranda_unknown", + OnExtraIconListRebuild, OnExtraImageApply, OnExtraIconClick); + + if (g_plugin.getByte("StatusBarIcon", 1)) { + StatusIconData sid = {}; + sid.szModule = MODULENAME; + sid.flags = MBF_HIDDEN; + sid.dwId = 1; + Srmm_AddIcon(&sid, &g_plugin); + } + + return 0; +} + +void InitFingerModule() +{ + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + HookEvent(ME_OPT_INITIALISE, OnOptInitialise); + HookEvent(ME_DB_CONTACT_SETTINGCHANGED, OnContactSettingChanged); + + CreateServiceFunction(MS_FP_SAMECLIENTSW, ServiceSameClientsW); + CreateServiceFunction(MS_FP_GETCLIENTDESCRW, ServiceGetClientDescrW); + CreateServiceFunction(MS_FP_GETCLIENTICONW, ServiceGetClientIconW); +} diff --git a/plugins/FingerprintNG/src/main.cpp b/plugins/FingerprintNG/src/main.cpp index bc0b262031..aaabd2d796 100644 --- a/plugins/FingerprintNG/src/main.cpp +++ b/plugins/FingerprintNG/src/main.cpp @@ -1,6 +1,6 @@ /* Fingerprint NG (client version) icons module for Miranda NG -Copyright © 2006-22 FYR, Bio, nullbie, ghazan, mataes, HierOS, faith_healer and all respective contributors. +Copyright © 2006-23 FYR, Bio, nullbie, ghazan, mataes, HierOS, faith_healer and all respective contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/plugins/FingerprintNG/src/masks.cpp b/plugins/FingerprintNG/src/masks.cpp index 64439f0615..c87335b7c1 100644 --- a/plugins/FingerprintNG/src/masks.cpp +++ b/plugins/FingerprintNG/src/masks.cpp @@ -1,6 +1,6 @@ /* Fingerprint NG (client version) icons module for Miranda NG -Copyright © 2006-22 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. +Copyright © 2006-23 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/plugins/FingerprintNG/src/options.cpp b/plugins/FingerprintNG/src/options.cpp index f589db85da..60fc532249 100644 --- a/plugins/FingerprintNG/src/options.cpp +++ b/plugins/FingerprintNG/src/options.cpp @@ -1,7 +1,7 @@ /* Fingerprint NG (client version) icons module for Miranda NG -Copyright © 2006-22 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. +Copyright © 2006-23 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/plugins/FingerprintNG/src/stdafx.cxx b/plugins/FingerprintNG/src/stdafx.cxx index f64d25234b..ebbde0ade1 100644 --- a/plugins/FingerprintNG/src/stdafx.cxx +++ b/plugins/FingerprintNG/src/stdafx.cxx @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 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 diff --git a/plugins/FingerprintNG/src/stdafx.h b/plugins/FingerprintNG/src/stdafx.h index 6a62fb57e8..091716993f 100644 --- a/plugins/FingerprintNG/src/stdafx.h +++ b/plugins/FingerprintNG/src/stdafx.h @@ -1,7 +1,7 @@ /* Fingerprint NG (client version) icons module for Miranda NG -Copyright © 2006-22 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. +Copyright © 2006-23 ghazan, mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/plugins/FingerprintNG/src/version.h b/plugins/FingerprintNG/src/version.h index 1691434647..311340c4b9 100644 --- a/plugins/FingerprintNG/src/version.h +++ b/plugins/FingerprintNG/src/version.h @@ -1,6 +1,6 @@ /* Fingerprint NG (client version) icons module for Miranda NG -Copyright © 2006-22 ghazan, Mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. +Copyright © 2006-23 ghazan, Mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -29,4 +29,4 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define __DESCRIPTION "Fingerprint NG (client version) icons module for Miranda NG." #define __AUTHOR "faith_healer, ghazan, Mataes" #define __AUTHORWEB "https://miranda-ng.org/p/Fingerprint" -#define __COPYRIGHT "© 2006-22 ghazan, Mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors." +#define __COPYRIGHT "© 2006-23 ghazan, Mataes, HierOS, FYR, Bio, nullbie, faith_healer and all respective contributors." -- cgit v1.2.3