summaryrefslogtreecommitdiff
path: root/plugins/TipperYM
diff options
context:
space:
mode:
authorRozhuk Ivan <rozhuk.im@gmail.com>2014-11-26 20:15:48 +0000
committerRozhuk Ivan <rozhuk.im@gmail.com>2014-11-26 20:15:48 +0000
commita15e5552aeeb16bc71ec8b98061a1dd3f7d6bd4a (patch)
treea1d8feb28a94478309a11866079989ec590a8f5f /plugins/TipperYM
parent69e96bdff6b6367341b360ee788babd7976c0b5f (diff)
Tipper: code cleanup
git-svn-id: http://svn.miranda-ng.org/main/trunk@11105 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/TipperYM')
-rw-r--r--plugins/TipperYM/src/popwin.cpp3369
-rw-r--r--plugins/TipperYM/src/subst.cpp1702
2 files changed, 2533 insertions, 2538 deletions
diff --git a/plugins/TipperYM/src/popwin.cpp b/plugins/TipperYM/src/popwin.cpp
index 192a451d0d..caea08e7fa 100644
--- a/plugins/TipperYM/src/popwin.cpp
+++ b/plugins/TipperYM/src/popwin.cpp
@@ -1,1687 +1,1682 @@
-/*
-Copyright (C) 2006-2007 Scott Ellis
-Copyright (C) 2007-2011 Jan Holub
-
-This is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-This 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
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with this file; see the file license.txt. If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
-*/
-
-#include "common.h"
-
-__inline void AddRow(PopupWindowData *pwd, TCHAR *swzLabel, TCHAR *swzValue, char *szProto, bool bParseSmileys, bool bNewline, bool bLineAbove, bool bIsTitle = false, HICON hIcon = NULL)
-{
- pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData) * (pwd->iRowCount + 1));
- pwd->rows[pwd->iRowCount].swzLabel = swzLabel ? mir_tstrdup(swzLabel) : NULL;
- pwd->rows[pwd->iRowCount].swzValue = swzValue ? mir_tstrdup(swzValue) : NULL;
- pwd->rows[pwd->iRowCount].spi = bParseSmileys ? Smileys_PreParse(swzValue, (int)_tcslen(swzValue), szProto) : NULL;
- pwd->rows[pwd->iRowCount].bValueNewline = bNewline;
- pwd->rows[pwd->iRowCount].bLineAbove = bLineAbove;
- pwd->rows[pwd->iRowCount].bIsTitle = bIsTitle;
- pwd->rows[pwd->iRowCount].hIcon = hIcon;
- pwd->iRowCount++;
-}
-
-LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- PopupWindowData *pwd = (PopupWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
-
- switch(uMsg) {
- case WM_CREATE:
- {
- CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
- pwd = (PopupWindowData *)mir_alloc(sizeof(PopupWindowData));
- memset(pwd, 0, sizeof(PopupWindowData));
- pwd->clcit = *(CLCINFOTIPEX *)cs->lpCreateParams;
- pwd->iIconIndex = -1;
- pwd->hpenBorder = CreatePen(PS_SOLID, 1, opt.bBorder ? opt.colBorder : opt.colBg);
- pwd->hpenDivider = CreatePen(PS_SOLID, 1, opt.colDivider);
- pwd->iTrans = (int)(opt.iOpacity / 100.0 * 255);
-
- // load icons order
- for (int i = 0; i < EXICONS_COUNT; i++)
- pwd->bIsIconVisible[opt.exIconsOrder[i]] = opt.exIconsVis[i] ? true : false;
-
- SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pwd);
-
- // work around bug hiding tips
- GetCursorPos(&pwd->ptCursorStartPos);
- SetTimer(hwnd, ID_TIMER_CHECKMOUSE, CHECKMOUSE_ELAPSE, 0);
-
- //Register copy menu hotkey (CTRL+C)
- pwd->iHotkeyId = GlobalAddAtom(_T("Tipper"));
- RegisterHotKey(hwnd, pwd->iHotkeyId, MOD_CONTROL, 0x43);
-
- if (pwd->clcit.szProto) {
- pwd->bIsTextTip = false;
- pwd->iIndent = opt.iTextIndent;
- pwd->iSidebarWidth = opt.iSidebarWidth;
-
- if (ServiceExists(MS_PROTO_GETACCOUNT)) {
- PROTOACCOUNT *pa = ProtoGetAccount(pwd->clcit.szProto);
- if (pa)
- _tcscpy(pwd->swzTitle, pa->tszAccountName);
- }
-
- if (_tcslen(pwd->swzTitle) == 0)
- a2t(pwd->clcit.szProto, pwd->swzTitle, TITLE_TEXT_LEN);
-
- if (CallService(MS_PROTO_ISACCOUNTLOCKED, 0, (LPARAM)pwd->clcit.szProto))
- mir_sntprintf(pwd->swzTitle, SIZEOF(pwd->swzTitle), TranslateT("%s (locked)"), pwd->swzTitle);
-
- // protocol status
- WORD wStatus = (WORD)CallProtoService(pwd->clcit.szProto, PS_GETSTATUS, 0, 0);
-
- // get status icon
- if (pwd->bIsIconVisible[0]) {
- pwd->extraIcons[0].hIcon = LoadSkinnedProtoIcon(pwd->clcit.szProto, wStatus);
- pwd->extraIcons[0].bDestroy = false;
- }
-
- // get activity icon
- if (pwd->bIsIconVisible[2]) {
- pwd->extraIcons[2].hIcon = GetJabberActivityIcon(0, pwd->clcit.szProto);
- pwd->extraIcons[2].bDestroy = false;
- }
-
- // uid info
- TCHAR swzUid[256], swzUidName[256];
- if (Uid(0, pwd->clcit.szProto, swzUid, 256) && UidName(pwd->clcit.szProto, swzUidName, 253)) {
- _tcscat(swzUidName, _T(": "));
- AddRow(pwd, swzUidName, swzUid, NULL, false, false, false);
- }
-
- // logon info
- TCHAR swzLogon[64];
- if (TimestampToTimeDifference(NULL, pwd->clcit.szProto, "LogonTS", swzLogon, 59)) {
- TCHAR ago[96];
- mir_sntprintf(ago, SIZEOF(ago), TranslateT("%s ago"), swzLogon);
- AddRow(pwd, TranslateT("Log on:"), ago, NULL, false, false, false);
- }
-
- // number of unread emails
- TCHAR swzEmailCount[64];
- if (ProtoServiceExists(pwd->clcit.szProto, PS_GETUNREADEMAILCOUNT)) {
- int iCount = (int)ProtoCallService(pwd->clcit.szProto, PS_GETUNREADEMAILCOUNT, 0, 0);
- if (iCount > 0) {
- _itot(iCount, swzEmailCount, 10);
- AddRow(pwd, TranslateT("Unread emails:"), swzEmailCount, NULL, false, false, false);
- }
- }
-
- TCHAR *swzText = pcli->pfnGetStatusModeDescription(wStatus, 0);
- if (swzText)
- AddRow(pwd, TranslateT("Status:"), swzText, NULL, false, false, false);
-
- if (wStatus >= ID_STATUS_ONLINE && wStatus <= ID_STATUS_OUTTOLUNCH) {
- // status message
- TCHAR *swzText = GetProtoStatusMessage(pwd->clcit.szProto, wStatus);
- if (swzText) {
- StripBBCodesInPlace(swzText);
- AddRow(pwd, TranslateT("Status message:"), swzText, pwd->clcit.szProto, true, true, true);
- mir_free(swzText);
- }
-
- // jabber mood or icq xstatus
- TCHAR *swzAdvTitle = GetJabberAdvStatusText(pwd->clcit.szProto, "mood", "title");
- if (swzAdvTitle) {
- StripBBCodesInPlace(swzAdvTitle);
- AddRow(pwd, TranslateT("Mood:"), swzAdvTitle, pwd->clcit.szProto, true, false, true);
-
- TCHAR *swzAdvText = GetJabberAdvStatusText(pwd->clcit.szProto, "mood", "text");
- if (swzAdvText) {
- StripBBCodesInPlace(swzAdvText);
- AddRow(pwd, _T(""), swzAdvText, pwd->clcit.szProto, true, true, false);
- mir_free(swzAdvText);
- }
- }
- else {
- if (db_get_b(0, pwd->clcit.szProto, "XStatusId", 0)) {
- // xstatus title
- swzAdvTitle = GetProtoExtraStatusTitle(pwd->clcit.szProto);
- if (swzAdvTitle) {
- StripBBCodesInPlace(swzAdvTitle);
- AddRow(pwd, TranslateT("xStatus:"), swzAdvTitle, pwd->clcit.szProto, true, false, true);
- }
-
- // xstatus message
- TCHAR *swzAdvText = GetProtoExtraStatusMessage(pwd->clcit.szProto);
- if (swzAdvText) {
- StripBBCodesInPlace(swzAdvText);
- AddRow(pwd, _T(""), swzAdvText, pwd->clcit.szProto, true, true, false);
- mir_free(swzAdvText);
- }
- }
- }
-
- if (swzAdvTitle) {
- mir_free(swzAdvTitle);
- // get advanced status icon
- if (pwd->bIsIconVisible[1]) {
- pwd->extraIcons[1].hIcon = (HICON)CallProtoService(pwd->clcit.szProto, PS_GETCUSTOMSTATUSICON, 0, LR_SHARED);
- pwd->extraIcons[1].bDestroy = false;
- }
- }
-
- // jabber activity
- TCHAR *swzActTitle = GetJabberAdvStatusText(pwd->clcit.szProto, "activity", "title");
- if (swzActTitle) {
- StripBBCodesInPlace(swzActTitle);
- AddRow(pwd, TranslateT("Activity:"), swzActTitle, pwd->clcit.szProto, true, false, true);
- mir_free(swzActTitle);
- }
-
- TCHAR *swzActText = GetJabberAdvStatusText(pwd->clcit.szProto, "activity", "text");
- if (swzActText) {
- StripBBCodesInPlace(swzActText);
- AddRow(pwd, _T(""), swzActText, pwd->clcit.szProto, true, true, false);
- mir_free(swzActText);
- }
-
- // listening to
- TCHAR *swzListening = GetListeningTo(pwd->clcit.szProto);
- if (swzListening) {
- StripBBCodesInPlace(swzListening);
- AddRow(pwd, TranslateT("Listening to:"), swzListening, NULL, false, true, true);
- mir_free(swzListening);
- }
- }
- }
- else if (pwd->clcit.swzText) {
- pwd->bIsTextTip = true;
- pwd->iIndent = 0;
- pwd->iSidebarWidth = 0;
-
- RECT rc = pwd->clcit.rcItem;
- bool mirandaTrayTip = ((rc.right - rc.left) == 20) && ((rc.bottom - rc.top) == 20) ? true : false;
-
- if (mirandaTrayTip && !opt.bTraytip) {
- MyDestroyWindow(hwnd);
- return 0;
- }
-
- if (mirandaTrayTip && opt.bHandleByTipper) { // extended tray tooltip
- pwd->bIsTrayTip = true;
- pwd->iIndent = opt.iTextIndent;
- pwd->iSidebarWidth = opt.iSidebarWidth;
-
- SendMessage(hwnd, PUM_REFRESHTRAYTIP, 0, 0);
-
- if (opt.bExpandTraytip)
- SetTimer(hwnd, ID_TIMER_TRAYTIP, opt.iExpandTime, 0);
- }
- else {
- TCHAR buff[2048], *swzText = pwd->clcit.swzText;
- size_t iBuffPos, i = 0, iSize = _tcslen(pwd->clcit.swzText);
- bool bTopMessage = false;
-
- while (i < iSize && swzText[i] != _T('<')) {
- iBuffPos = 0;
- while (swzText[i] != _T('\n') && swzText[i] != _T('\r') && i < iSize && iBuffPos < 2048) {
- if (swzText[i] != _T('\t'))
- buff[iBuffPos++] = swzText[i];
- i++;
- }
-
- buff[iBuffPos] = 0;
-
- if (iBuffPos) {
- AddRow(pwd, _T(""), buff, NULL, false, true, false);
- bTopMessage = true;
- }
-
- while (i < iSize && (swzText[i] == _T('\n') || swzText[i] == _T('\r')))
- i++;
- }
-
- // parse bold bits into labels and the rest into items
- while (i < iSize) {
- while (i + 2 < iSize && (swzText[i] != _T('<') || swzText[i + 1] != _T('b') || swzText[i + 2] != _T('>')))
- i++;
-
- i += 3;
-
- iBuffPos = 0;
- while (i + 3 < iSize && iBuffPos < 2048 && (swzText[i] != _T('<')
- || swzText[i + 1] != _T('/') || swzText[i + 2] != _T('b') || swzText[i + 3] != _T('>'))) {
- if (swzText[i] != _T('\t'))
- buff[iBuffPos++] = swzText[i];
- i++;
- }
-
- i += 4;
-
- buff[iBuffPos] = 0;
-
- if (iBuffPos) {
- pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData)* (pwd->iRowCount + 1));
- pwd->rows[pwd->iRowCount].bValueNewline = false;
- pwd->rows[pwd->iRowCount].swzLabel = mir_tstrdup(buff);
- if (pwd->iRowCount == 1 && bTopMessage)
- pwd->rows[pwd->iRowCount].bLineAbove = true;
- else
- pwd->rows[pwd->iRowCount].bLineAbove = false;
-
- iBuffPos = 0;
- while (i < iSize && iBuffPos < 2048 && swzText[i] != _T('\n')) {
- if (swzText[i] != _T('\t') && swzText[i] != _T('\r'))
- buff[iBuffPos++] = swzText[i];
- i++;
- }
- buff[iBuffPos] = 0;
-
- pwd->rows[pwd->iRowCount].swzValue = mir_tstrdup(buff);
- pwd->rows[pwd->iRowCount].spi = NULL;
- pwd->iRowCount++;
- }
-
- i++;
- }
-
- if (pwd->iRowCount == 0) {
- // single item
- pwd->iRowCount = 1;
- pwd->rows = (RowData *)mir_alloc(sizeof(RowData));
- pwd->rows[0].bLineAbove = pwd->rows[0].bValueNewline = false;
- pwd->rows[0].swzLabel = 0;
- pwd->rows[0].swzValue = swzText;
- pwd->rows[0].spi = NULL;
- }
- }
- }
- else {
- pwd->bIsTextTip = false;
- pwd->iIndent = opt.iTextIndent;
- pwd->iSidebarWidth = opt.iSidebarWidth;
- pwd->hContact = (MCONTACT)pwd->clcit.hItem;
- pwd->iIconIndex = (int)CallService(MS_CLIST_GETCONTACTICON, pwd->hContact, 0);
-
- // don't use stored status message
- if (!opt.bWaitForContent)
- db_unset(pwd->hContact, MODULE, "TempStatusMsg");
-
- TCHAR *swzNick = pcli->pfnGetContactDisplayName(pwd->hContact, 0);
- _tcsncpy(pwd->swzTitle, swzNick, TITLE_TEXT_LEN);
-
- char *szProto = GetContactProto(pwd->hContact);
- pwd->spiTitle = Smileys_PreParse(pwd->swzTitle, -1, szProto);
-
- // get extra icons
- DBVARIANT dbv = { 0 };
- int i = 0;
-
- if (szProto) {
- // status icon
- if (pwd->bIsIconVisible[0]) {
- for (i = 0; opt.exIconsOrder[i] != 0; i++);
- pwd->extraIcons[i].hIcon = ImageList_GetIcon((HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), pwd->iIconIndex, 0);
- pwd->extraIcons[i].bDestroy = true;
- }
-
- // xstatus icon
- if (pwd->bIsIconVisible[1]) {
- for (i = 0; opt.exIconsOrder[i] != 1; i++);
- int iXstatus = db_get_b(pwd->hContact, szProto, "XStatusId", 0);
- if (iXstatus) {
- char szIconProto[64];
- if (strcmp(szProto, META_PROTO) != 0)
- strcpy(szIconProto, szProto);
- else if (!db_get_s(pwd->hContact, szProto, "XStatusProto", &dbv)) {
- strcpy(szIconProto, dbv.pszVal);
- db_free(&dbv);
- }
-
- pwd->extraIcons[i].hIcon = (HICON)CallProtoService(szIconProto, PS_GETCUSTOMSTATUSICON, (WPARAM)iXstatus, LR_SHARED);
- pwd->extraIcons[i].bDestroy = false;
- }
- }
-
- // activity icon
- if (pwd->bIsIconVisible[2]) {
- for (i = 0; opt.exIconsOrder[i] != 2; i++);
- pwd->extraIcons[i].hIcon = GetJabberActivityIcon(pwd->hContact, szProto);
- pwd->extraIcons[i].bDestroy = false;
- }
-
- // gender icon
- if (pwd->bIsIconVisible[3]) {
- for (i = 0; opt.exIconsOrder[i] != 3; i++);
- int iGender = db_get_b(pwd->hContact, "UserInfo", "Gender", 0);
- if (iGender == 0)
- iGender = db_get_b(pwd->hContact, szProto, "Gender", 0);
-
- if (iGender == GEN_FEMALE)
- pwd->extraIcons[i].hIcon = Skin_GetIcon("gender_female");
- else if (iGender == GEN_MALE)
- pwd->extraIcons[i].hIcon = Skin_GetIcon("gender_male");
- pwd->extraIcons[i].bDestroy = false;
- }
-
- // flags icon
- if (pwd->bIsIconVisible[4]) {
- for (i = 0; opt.exIconsOrder[i] != 4; i++);
-
- INT_PTR iCountry = CallService(MS_FLAGS_DETECTCONTACTORIGINCOUNTRY, pwd->hContact, 0);
- if (iCountry == CALLSERVICE_NOTFOUND)
- iCountry = CallService(MS_FLAGS_GETCONTACTORIGINCOUNTRY, pwd->hContact, 0);
-
- if (iCountry != CALLSERVICE_NOTFOUND && iCountry != 0 && iCountry != CTRY_UNKNOWN && iCountry != CTRY_ERROR) {
- pwd->extraIcons[i].hIcon = LoadFlagIcon(iCountry);
- pwd->extraIcons[i].bDestroy = false;
- }
- }
-
- // fingerprint icon
- if (pwd->bIsIconVisible[5]) {
- for (i = 0; opt.exIconsOrder[i] != 5; i++);
- if (ServiceExists(MS_FP_GETCLIENTICONT)) {
- if (!db_get_ts(pwd->hContact, szProto, "MirVer", &dbv)) {
- pwd->extraIcons[i].hIcon = Finger_GetClientIcon(dbv.ptszVal, 0);
- pwd->extraIcons[i].bDestroy = true;
- db_free(&dbv);
- }
- }
- }
-
- //request xstatus details
- if (opt.bRetrieveXstatus)
- if (!db_get_b(0, szProto, "XStatusAuto", 1) && ProtoServiceExists(szProto, PS_ICQ_REQUESTCUSTOMSTATUS))
- CallProtoService(szProto, PS_ICQ_REQUESTCUSTOMSTATUS, pwd->hContact, 0);
- }
-
- SendMessage(hwnd, PUM_REFRESH_VALUES, FALSE, 0);
- }
-
- SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
- SendMessage(hwnd, PUM_CALCPOS, 0, 0);
-
- // transparency
- SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
-
- if (opt.bDropShadow && opt.skinMode == SM_COLORFILL)
- SetClassLongPtr(hwnd, GCL_STYLE, CS_DROPSHADOW);
- else
- SetClassLongPtr(hwnd, GCL_STYLE, 0);
-
- if (!skin.bNeedLayerUpdate)
- SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_ALPHA);
-
- if (opt.showEffect)
- SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0);
-
- ShowWindow(hwnd, SW_SHOWNOACTIVATE);
- InvalidateRect(hwnd, 0, FALSE);
-
- // since tipper win is topmost, this should put it at top of topmost windows
- SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
- }
- return 0;
-
- case WM_ERASEBKGND:
- if (!skin.bNeedLayerUpdate) {
- HDC hdc = (HDC)wParam;
- RECT rc;
- GetClientRect(hwnd, &rc);
-
- BitBlt(hdc, 0, 0, skin.iWidth, skin.iHeight, skin.hdc, 0, 0, SRCCOPY);
-
- // border
- if (opt.bBorder) {
- HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
- HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenBorder);
-
- int h = 0;
- if (opt.bRound) {
- int v;
- int w = 14;
- h = (rc.right - rc.left) > (w * 2) ? w : (rc.right - rc.left);
- v = (rc.bottom - rc.top) > (w * 2) ? w : (rc.bottom - rc.top);
- h = (h < v) ? h : v;
- }
-
- RoundRect(hdc, 0, 0, (rc.right - rc.left), (rc.bottom - rc.top), h, h);
-
- SelectObject(hdc, hOldBrush);
- SelectObject(hdc, hOldPen);
- }
- }
- return TRUE;
-
- case WM_PAINT:
- {
- RECT r, r2;
- PAINTSTRUCT ps;
- BeginPaint(hwnd, &ps);
- HDC hdc = skin.bNeedLayerUpdate ? skin.hdc : ps.hdc;
-
- GetClientRect(hwnd, &r);
- r2 = r;
- HFONT hOldFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
-
- // text background
- SetBkMode(hdc, TRANSPARENT);
-
- BLENDFUNCTION blend;
- blend.BlendOp = AC_SRC_OVER;
- blend.BlendFlags = 0;
- blend.SourceConstantAlpha = 255;
- blend.AlphaFormat = AC_SRC_ALPHA;
-
- // avatar
- if (!pwd->bIsTextTip && opt.avatarLayout != PAV_NONE && pwd->iAvatarHeight) {
- RECT rcAvatar;
- rcAvatar.top = opt.iOuterAvatarPadding;
-
- if (opt.avatarLayout == PAV_LEFT) {
- rcAvatar.left = r.left + opt.iOuterAvatarPadding;
- rcAvatar.right = rcAvatar.left + pwd->iRealAvatarWidth;
- r2.left += pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding); // padding re-added for text
- }
- else if (opt.avatarLayout == PAV_RIGHT) {
- rcAvatar.right = r.right - opt.iOuterAvatarPadding;
- rcAvatar.left = rcAvatar.right - pwd->iRealAvatarWidth;
- r2.right -= pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding);
- }
-
- rcAvatar.bottom = rcAvatar.top + pwd->iRealAvatarHeight;
-
- AVATARCACHEENTRY *ace = 0;
- if (pwd->hContact)
- ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, pwd->hContact, 0);
- else
- ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto);
-
- if (ace && ace->hbmPic && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
- ResizeBitmap rb = { 0 };
- rb.size = sizeof(rb);
- rb.max_width = pwd->iRealAvatarWidth;
- rb.max_height = pwd->iRealAvatarHeight;
- rb.fit = RESIZEBITMAP_STRETCH | RESIZEBITMAP_KEEP_PROPORTIONS;
- rb.hBmp = ace->hbmPic;
- HBITMAP hbmpAvatar = (HBITMAP)CallService(MS_IMG_RESIZE, (WPARAM)&rb, 0);
-
- if (hbmpAvatar) {
- HRGN hrgnAvatar = 0;
- if (opt.bAvatarRound) {
- hrgnAvatar = CreateRoundRectRgn(rcAvatar.left, rcAvatar.top, rcAvatar.right + 1, rcAvatar.bottom + 1, 9, 9);
- SelectClipRgn(hdc, hrgnAvatar);
- }
-
- BITMAP bm;
- GetObject(hbmpAvatar, sizeof(bm), &bm);
- HDC hdcMem = CreateCompatibleDC(hdc);
- SelectObject(hdcMem, hbmpAvatar);
-
- blend.SourceConstantAlpha = (BYTE)(opt.iAvatarOpacity / 100.0 * 255);
- AlphaBlend(hdc, rcAvatar.left, rcAvatar.top, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, blend);
- blend.SourceConstantAlpha = 255;
-
- if (opt.bAvatarBorder) {
- SaveAlpha(&rcAvatar);
- HBRUSH hbrBorder = CreateSolidBrush(opt.colAvatarBorder);
- if (opt.bAvatarRound)
- FrameRgn(hdc, hrgnAvatar, hbrBorder, 1, 1);
- else
- FrameRect(hdc, &rcAvatar, hbrBorder);
-
- DeleteObject(hbrBorder);
- RestoreAlpha(&rcAvatar, (BYTE)(opt.iAvatarOpacity / 100.0 * 255));
- }
-
- if (hrgnAvatar) {
- SelectClipRgn(hdc, 0);
- DeleteObject(hrgnAvatar);
- }
-
- if (hbmpAvatar != ace->hbmPic)
- DeleteObject(hbmpAvatar);
-
- DeleteDC(hdcMem);
- }
- }
- }
-
- RECT tr;
- tr.left = r2.left + opt.iPadding + opt.iTitleIndent;
- tr.right = r2.right - opt.iPadding;
- tr.top = 0;
- tr.bottom = opt.iPadding;
-
- if (!pwd->bIsTextTip) {
- if (opt.titleIconLayout != PTL_NOICON) {
- // draw icons
- int iIconX, iIconY;
- iIconY = opt.iPadding + opt.iTextPadding;
-
- if (opt.titleIconLayout == PTL_RIGHTICON)
- iIconX = r2.right - 16 - opt.iPadding;
- else
- iIconX = r2.left + opt.iPadding;
-
- for (int i = 0; i < EXICONS_COUNT; i++) {
- if (pwd->extraIcons[i].hIcon) {
- DrawIconExAlpha(hdc, iIconX, iIconY, pwd->extraIcons[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false);
- iIconY += 20;
- }
- }
- }
-
- // title text
- if (opt.bShowTitle) {
- if (hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle);
- SetTextColor(hdc, opt.colTitle);
- tr.top = opt.iPadding;
- tr.bottom = tr.top + pwd->iTitleHeight - opt.iPadding;
- UINT uTextFormat = DT_TOP | DT_LEFT | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX;
- DrawTextExt(hdc, pwd->swzTitle, -1, &tr, uTextFormat, NULL, pwd->spiTitle);
- }
- }
-
- // values
- pwd->iTextHeight = 0;
- bool bIconPainted, bUseRect = true;
- int iRowHeight;
- for (int i = 0; i < pwd->iRowCount; i++) {
- tr.top = tr.bottom;
- bUseRect = (tr.top + opt.iTextPadding >= pwd->iAvatarHeight);
- bIconPainted = false;
- if (bUseRect) {
- if (pwd->rows[i].bLineAbove) {
- HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenDivider);
- tr.top += opt.iTextPadding;
- RECT rec;
- SetRect(&rec, r.left + opt.iPadding + pwd->iIndent, tr.top, r.right - opt.iPadding, tr.top + 1);
- SaveAlpha(&rec);
- Rectangle(hdc, rec.left, rec.top, rec.right, rec.bottom);
- RestoreAlpha(&rec);
- SelectObject(hdc, hOldPen);
- }
-
- tr.left = r.left + opt.iPadding + pwd->iIndent;
- if (pwd->rows[i].bValueNewline)
- tr.right = r.right - opt.iPadding;
- else
- tr.right = r.left + opt.iPadding + pwd->iIndent + pwd->iLabelWidth;
- }
- else {
- if (pwd->rows[i].bLineAbove) {
- HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenDivider);
- tr.top += opt.iTextPadding;
- RECT rec;
- SetRect(&rec, r2.left + opt.iPadding + pwd->iIndent, tr.top, r2.right - opt.iPadding, tr.top + 1);
- SaveAlpha(&rec);
- Rectangle(hdc, rec.left, rec.top, rec.right, rec.bottom);
- RestoreAlpha(&rec);
- SelectObject(hdc, hOldPen);
- }
-
- tr.left = r2.left + opt.iPadding + pwd->iIndent;
- if (pwd->rows[i].bValueNewline)
- tr.right = r2.right - opt.iPadding;
- else
- tr.right = r2.left + opt.iPadding + pwd->iIndent + pwd->iLabelWidth;
- }
-
- if (pwd->rows[i].bValueNewline)
- iRowHeight = pwd->rows[i].iLabelHeight;
- else
- iRowHeight = max(pwd->rows[i].iLabelHeight, pwd->rows[i].iValueHeight);
-
- if (pwd->rows[i].iLabelHeight) {
- tr.top += opt.iTextPadding;
- tr.bottom = tr.top + iRowHeight;
-
- if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) {
- if (hFontTrayTitle) SelectObject(hdc, (HGDIOBJ)hFontTrayTitle);
- SetTextColor(hdc, opt.colTrayTitle);
- }
- else {
- if (hFontLabels) SelectObject(hdc, (HGDIOBJ)hFontLabels);
- SetTextColor(hdc, opt.colLabel);
- }
-
- // status icon in tray tooltip
- if (opt.titleIconLayout != PTL_NOICON && pwd->bIsTrayTip && pwd->rows[i].hIcon) {
- DrawIconExAlpha(hdc, opt.iPadding, tr.top + (pwd->rows[i].iLabelHeight - 16) / 2, pwd->rows[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false);
- bIconPainted = true;
- }
-
- DrawTextAlpha(hdc, pwd->rows[i].swzLabel, -1, &tr, opt.iLabelValign | ((opt.iLabelHalign == DT_RIGHT && !pwd->rows[i].bValueNewline) ? DT_RIGHT : DT_LEFT) | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX);
- if (pwd->rows[i].bValueNewline)
- tr.top = tr.bottom;
- }
- else tr.bottom = tr.top;
-
- if (pwd->rows[i].bValueNewline)
- iRowHeight = pwd->rows[i].iValueHeight;
-
- if (hFontValues)
- SelectObject(hdc, (HGDIOBJ)hFontValues);
- SetTextColor(hdc, opt.colValue);
- if (bUseRect) {
- tr.left = r.left + opt.iPadding + pwd->iIndent;
- if (!pwd->rows[i].bValueNewline)
- tr.left += pwd->iLabelWidth + opt.iValueIndent;
-
- tr.right = r.right - opt.iPadding;
- }
- else {
- tr.left = r2.left + opt.iPadding + pwd->iIndent;
- if (!pwd->rows[i].bValueNewline)
- tr.left += pwd->iLabelWidth + opt.iValueIndent;
-
- tr.right = r2.right - opt.iPadding;
- }
-
- if (pwd->rows[i].iValueHeight) {
- if (pwd->rows[i].bValueNewline || !pwd->rows[i].iLabelHeight) tr.top += opt.iTextPadding;
- if (pwd->rows[i].iLabelHeight > pwd->rows[i].iValueHeight && pwd->bIsTextTip&& pwd->rows[i].bIsTitle)
- tr.top = tr.bottom - pwd->rows[i].iValueHeight - 2;
- else
- tr.bottom = tr.top + iRowHeight;
-
- if (opt.titleIconLayout != PTL_NOICON && pwd->bIsTrayTip && pwd->rows[i].hIcon && !bIconPainted)
- DrawIconExAlpha(hdc, opt.iPadding, tr.top + (pwd->rows[i].iValueHeight - 16) / 2, pwd->rows[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false);
-
- UINT uFormat = opt.iValueValign | opt.iValueHalign | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX;
- DrawTextExt(hdc, pwd->rows[i].swzValue, -1, &tr, uFormat, NULL, pwd->rows[i].spi);
- }
- }
-
- PremultipleChannels();
-
- if (opt.showEffect == PSE_NONE) {
- if (skin.bNeedLayerUpdate) {
- POINT ptSrc = { 0, 0 };
- SIZE szTip = { r.right - r.left, r.bottom - r.top };
- blend.SourceConstantAlpha = pwd->iTrans;
- UpdateLayeredWindow(hwnd, NULL, NULL, &szTip, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
-
- if (opt.bAeroGlass && MyDwmEnableBlurBehindWindow) {
- DWM_BLURBEHIND bb = { 0 };
- bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- bb.fEnable = TRUE;
- bb.hRgnBlur = CreateOpaqueRgn(25, true);
- MyDwmEnableBlurBehindWindow(hwnd, &bb);
- }
- }
- else SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), pwd->iTrans, LWA_ALPHA);
- }
-
- SelectObject(hdc, hOldFont);
- EndPaint(hwnd, &ps);
- pwd->bIsPainted = true;
- }
- return 0;
-
- case WM_HOTKEY:
- if (LOWORD(lParam) == MOD_CONTROL && HIWORD(lParam) == 0x43) { // CTRL+C
- if (pwd->iRowCount == 0)
- return 0;
-
- ShowWindow(hwnd, SW_HIDE);
- HMENU hMenu = CreatePopupMenu();
- if (!hMenu)
- return 0;
-
- HICON hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ITEM_ALL), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
- if (!hIcon) {
- DestroyMenu(hMenu);
- return 0;
- }
-
- ICONINFO iconInfo;
- GetIconInfo(hIcon, &iconInfo);
- HBITMAP hbmpAllItems = iconInfo.hbmColor;
- DestroyIcon(hIcon);
-
- AppendMenu(hMenu, MF_STRING, COPYMENU_ALLITEMS_LABELS, LPGENT("Copy all items with labels"));
- AppendMenu(hMenu, MF_STRING, COPYMENU_ALLITEMS, LPGENT("Copy all items"));
- if (pwd->clcit.szProto || pwd->hContact)
- AppendMenu(hMenu, MF_STRING, COPYMENU_AVATAR, LPGENT("Copy avatar"));
- AppendMenu(hMenu, MF_SEPARATOR, 2000, 0);
- TranslateMenu(hMenu);
-
- SetMenuItemBitmaps(hMenu, COPYMENU_ALLITEMS_LABELS, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems);
- SetMenuItemBitmaps(hMenu, COPYMENU_ALLITEMS, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems);
- SetMenuItemBitmaps(hMenu, COPYMENU_AVATAR, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems);
-
- hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ITEM), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
- if (!hIcon) {
- DeleteObject(hbmpAllItems);
- DestroyMenu(hMenu);
- return 0;
- }
-
- GetIconInfo(hIcon, &iconInfo);
- HBITMAP hbmpItem = iconInfo.hbmColor;
- DestroyIcon(hIcon);
-
- for (int i = 0; i < pwd->iRowCount; i++) {
- if (pwd->rows[i].swzValue) {
- TCHAR buff[128];
- int iLen = (int)_tcslen(pwd->rows[i].swzValue);
- if (iLen) {
- if (iLen > MAX_VALUE_LEN) {
- _tcsncpy(buff, pwd->rows[i].swzValue, MAX_VALUE_LEN);
- buff[MAX_VALUE_LEN] = 0;
- _tcscat(buff, _T("..."));
- }
- else _tcscpy(buff, pwd->rows[i].swzValue);
-
- AppendMenu(hMenu, MF_STRING, i + 1, buff); // first id = 1, because no select have id = 0
- SetMenuItemBitmaps(hMenu, i + 1, MF_BYCOMMAND, hbmpItem, hbmpItem);
- }
- else AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
- }
- }
-
- POINT pt;
- GetCursorPos(&pt);
- SetForegroundWindow(hwnd);
- int iSelItem = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, 0);
- DeleteObject(hbmpAllItems);
- DeleteObject(hbmpItem);
- DestroyMenu(hMenu);
-
- if (iSelItem == 0)
- return 0; // no item was selected
-
- if (OpenClipboard(NULL)) {
- EmptyClipboard();
- if (iSelItem == COPYMENU_AVATAR) { // copy avatar
- AVATARCACHEENTRY *ace = 0;
- if (pwd->hContact)
- ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, pwd->hContact, 0);
- else
- ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto);
- if (ace && ace->hbmPic && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
- HDC hdc = GetDC(hwnd);
- HDC hdcSrc = CreateCompatibleDC(hdc);
- HDC hdcDes = CreateCompatibleDC(hdc);
- HBITMAP hbmAvr = CreateCompatibleBitmap(hdc, ace->bmWidth, ace->bmHeight);
- SelectObject(hdcSrc, ace->hbmPic);
- SelectObject(hdcDes, hbmAvr);
- BitBlt(hdcDes, 0, 0, ace->bmWidth, ace->bmHeight, hdcSrc, 0, 0, SRCCOPY);
- SetClipboardData(CF_BITMAP, hbmAvr);
- ReleaseDC(hwnd, hdc);
- DeleteDC(hdcSrc);
- DeleteDC(hdcDes);
- }
- }
- else { // copy text
- HGLOBAL hClipboardData = GlobalAlloc(GMEM_DDESHARE, 4096);
- TCHAR *pchData = (TCHAR *)GlobalLock(hClipboardData);
- pchData[0] = 0;
- if (iSelItem == COPYMENU_ALLITEMS_LABELS) { // copy all items with labels
- for (int i = 0; i < pwd->iRowCount; i++) {
- if ((pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) || (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0])) {
- if (pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) {
- _tcscat(pchData, pwd->rows[i].swzLabel);
- _tcscat(pchData, _T(" "));
- }
- else _tcscat(pchData, TranslateT("<No Label>: "));
-
- if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0])
- _tcscat(pchData, pwd->rows[i].swzValue);
- else
- _tcscat(pchData, TranslateT("<No Value>"));
-
- _tcscat(pchData, _T("\r\n"));
- }
- }
- }
- else if (iSelItem == COPYMENU_ALLITEMS) { // copy all items
- for (int i = 0; i < pwd->iRowCount; i++) {
- if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) {
- _tcscat(pchData, pwd->rows[i].swzValue);
- _tcscat(pchData, _T("\r\n"));
- }
- }
- }
- // single row
- else _tcscpy(pchData, pwd->rows[iSelItem - 1].swzValue);
-
- GlobalUnlock(hClipboardData);
- SetClipboardData(CF_UNICODETEXT, hClipboardData);
- }
-
- CloseClipboard();
- }
- }
- break;
-
- case PUM_FADEOUTWINDOW:
- // kill timers
- KillTimer(hwnd, ID_TIMER_ANIMATE);
- KillTimer(hwnd, ID_TIMER_CHECKMOUSE);
- KillTimer(hwnd, ID_TIMER_TRAYTIP);
-
- if (opt.showEffect != PSE_NONE) {
- if (skin.bNeedLayerUpdate) {
- POINT ptSrc = { 0, 0 };
- SIZE sz = { pwd->rcWindow.right - pwd->rcWindow.left, pwd->rcWindow.bottom - pwd->rcWindow.top };
-
- BLENDFUNCTION blend;
- blend.BlendOp = AC_SRC_OVER;
- blend.BlendFlags = 0;
- blend.SourceConstantAlpha = pwd->iTrans;
- blend.AlphaFormat = AC_SRC_ALPHA;
-
- while (blend.SourceConstantAlpha != 0) {
- UpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
- blend.SourceConstantAlpha = max(blend.SourceConstantAlpha - opt.iAnimateSpeed, 0);
- Sleep(ANIM_ELAPSE);
- }
- }
- else {
- int iTrans = pwd->iTrans;
- while (iTrans != 0) {
- SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), iTrans, LWA_ALPHA);
- iTrans = max(iTrans - opt.iAnimateSpeed, 0);
- Sleep(ANIM_ELAPSE);
- }
- }
- }
- break;
-
- case WM_DESTROY:
- ShowWindow(hwnd, SW_HIDE);
-
- // unregister hotkey
- UnregisterHotKey(hwnd, pwd->iHotkeyId);
-
- DeleteObject(pwd->hpenBorder);
- DeleteObject(pwd->hpenDivider);
-
- if (pwd->hrgnAeroGlass)
- DeleteObject(pwd->hrgnAeroGlass);
-
- Smileys_FreeParse(pwd->spiTitle);
-
- for (int i = 0; i < pwd->iRowCount; i++) {
- mir_free(pwd->rows[i].swzLabel);
- mir_free(pwd->rows[i].swzValue);
- Smileys_FreeParse(pwd->rows[i].spi);
- }
-
- if (pwd->rows)
- mir_free(pwd->rows);
- pwd->rows = NULL;
-
- // destroy icons
- for (int i = 0; i < EXICONS_COUNT; i++) {
- if (pwd->extraIcons[i].hIcon == NULL)
- continue;
-
- if (pwd->extraIcons[i].bDestroy)
- DestroyIcon(pwd->extraIcons[i].hIcon);
- else
- Skin_ReleaseIcon(pwd->extraIcons[i].hIcon);
- }
-
- if (pwd->clcit.swzText) {
- mir_free(pwd->clcit.swzText);
- pwd->clcit.swzText = NULL;
- }
-
- mir_free(pwd);
- pwd = NULL;
-
- if (skin.colSavedBits) mir_free(skin.colSavedBits);
- if (skin.hBitmap)DeleteObject(skin.hBitmap);
- if (skin.hdc) DeleteDC(skin.hdc);
- skin.colSavedBits = NULL;
- skin.hBitmap = NULL;
- skin.hdc = NULL;
-
- SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
- break;
-
- case WM_TIMER:
- if (wParam == ID_TIMER_ANIMATE) {
- pwd->iAnimStep++;
- if (pwd->iAnimStep == ANIM_STEPS)
- KillTimer(hwnd, ID_TIMER_ANIMATE);
-
- SendMessage(hwnd, PUM_UPDATERGN, 1, 0);
- }
- else if (wParam == ID_TIMER_CHECKMOUSE) {
- // workaround for tips that just won't go away
- POINT pt;
- GetCursorPos(&pt);
-
- // mouse has moved beyond tollerance
- if (abs(pt.x - pwd->ptCursorStartPos.x) > opt.iMouseTollerance || abs(pt.y - pwd->ptCursorStartPos.y) > opt.iMouseTollerance)
- PostMPMessage(MUM_DELETEPOPUP, 0, 0);
- }
- else if (wParam == ID_TIMER_TRAYTIP) {
- KillTimer(hwnd, ID_TIMER_TRAYTIP);
- SendMessage(hwnd, PUM_EXPANDTRAYTIP, 0, 0);
- }
-
- break;
-
- case PUM_SETSTATUSTEXT:
- if (pwd && wParam == pwd->hContact) {
- db_set_ts(pwd->hContact, MODULE, "TempStatusMsg", (TCHAR *)lParam);
- pwd->bIsPainted = false;
- pwd->bNeedRefresh = true;
- SendMessage(hwnd, PUM_REFRESH_VALUES, TRUE, 0);
- InvalidateRect(hwnd, 0, TRUE);
- }
-
- if (lParam) mir_free((void *)lParam);
- return TRUE;
-
- case PUM_SHOWXSTATUS:
- if (pwd && wParam == pwd->hContact) {
- // in case we have retrieve xstatus
- pwd->bIsPainted = false;
- SendMessage(hwnd, PUM_REFRESH_VALUES, TRUE, 0);
- InvalidateRect(hwnd, 0, TRUE);
- }
- return TRUE;
-
- case PUM_SETAVATAR:
- if (pwd && wParam == pwd->hContact) {
- pwd->bIsPainted = false;
- SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
- SendMessage(hwnd, PUM_CALCPOS, 0, 0);
- InvalidateRect(hwnd, 0, TRUE);
- }
- return TRUE;
-
- case PUM_EXPANDTRAYTIP:
- pwd->bIsPainted = false;
- if (skin.bNeedLayerUpdate) {
- RECT r = pwd->rcWindow;
- POINT ptSrc = {0, 0};
- SIZE sz = {r.right - r.left, r.bottom - r.top};
-
- BLENDFUNCTION blend;
- blend.BlendOp = AC_SRC_OVER;
- blend.BlendFlags = 0;
- blend.SourceConstantAlpha = 0;
- blend.AlphaFormat = AC_SRC_ALPHA;
-
- UpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
- }
- else SetLayeredWindowAttributes(hwnd, RGB(0,0,0), 0, LWA_ALPHA);
-
- SendMessage(hwnd, PUM_REFRESHTRAYTIP, 1, 0);
- SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
- SendMessage(hwnd, PUM_CALCPOS, 0, 0);
- InvalidateRect(hwnd, 0, TRUE);
-
- if (opt.showEffect) {
- KillTimer(hwnd, ID_TIMER_ANIMATE);
- SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0);
- pwd->iAnimStep = 0;
- pwd->iCurrentTrans = 0;
- }
- return TRUE;
-
- case PUM_REFRESH_VALUES:
- if (pwd && pwd->clcit.szProto == 0 && !pwd->bIsTextTip) {
- for (int i = 0; i < pwd->iRowCount; i++) {
- mir_free(pwd->rows[i].swzLabel);
- mir_free(pwd->rows[i].swzValue);
- Smileys_FreeParse(pwd->rows[i].spi);
- }
-
- if (pwd->rows) {
- mir_free(pwd->rows);
- pwd->rows = 0;
- }
- pwd->iRowCount = 0;
-
- DIListNode *node = opt.diList;
- TCHAR buff_label[LABEL_LEN], buff[VALUE_LEN];
- while (node) {
- if (node->di.bIsVisible && CheckContactType(pwd->hContact, node->di)) {
- if (GetLabelText(pwd->hContact, node->di, buff_label, LABEL_LEN) && GetValueText(pwd->hContact, node->di, buff, VALUE_LEN)) {
- if (node->di.bLineAbove // we have a line above
- && pwd->iRowCount > 0 // and we're not the first row
- && pwd->rows[pwd->iRowCount - 1].bLineAbove // and above us there's a line above
- && pwd->rows[pwd->iRowCount - 1].swzLabel[0] == 0 // with no label
- && pwd->rows[pwd->iRowCount - 1].swzValue[0] == 0) // and no value
- {
- // overwrite item above
- pwd->iRowCount--;
- mir_free(pwd->rows[pwd->iRowCount].swzLabel);
- mir_free(pwd->rows[pwd->iRowCount].swzValue);
- Smileys_FreeParse(pwd->rows[pwd->iRowCount].spi); //prevent possible mem leak
- }
- else pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData)* (pwd->iRowCount + 1));
-
- char *szProto = GetContactProto(pwd->hContact);
-
- pwd->rows[pwd->iRowCount].swzLabel = mir_tstrdup(buff_label);
- pwd->rows[pwd->iRowCount].swzValue = mir_tstrdup(buff);
- pwd->rows[pwd->iRowCount].spi = Smileys_PreParse(buff, (int)_tcslen(buff), szProto);
- pwd->rows[pwd->iRowCount].bValueNewline = node->di.bValueNewline;
- pwd->rows[pwd->iRowCount].bLineAbove = node->di.bLineAbove;
- pwd->iRowCount++;
- }
- }
- node = node->next;
- }
-
- // if the last item is just a divider, remove it
- if (pwd->iRowCount > 0
- && pwd->rows[pwd->iRowCount - 1].bLineAbove // and above us there's a line above
- && pwd->rows[pwd->iRowCount - 1].swzLabel[0] == 0 // with no label
- && pwd->rows[pwd->iRowCount - 1].swzValue[0] == 0) // and no value
- {
- pwd->iRowCount--;
- mir_free(pwd->rows[pwd->iRowCount].swzLabel);
- mir_free(pwd->rows[pwd->iRowCount].swzValue);
- Smileys_FreeParse(pwd->rows[pwd->iRowCount].spi); //prevent possible mem leak
-
- if (pwd->iRowCount == 0) {
- mir_free(pwd->rows);
- pwd->rows = 0;
- }
- }
-
- if (wParam == TRUE) {
- SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
- SendMessage(hwnd, PUM_CALCPOS, 0, 0);
- }
- }
- return TRUE;
-
- case PUM_GETHEIGHT:
- {
- int *pHeight = (int *)wParam;
- HDC hdc = GetDC(hwnd);
- SIZE sz;
- RECT rc, smr;
- rc.top = rc.left = 0;
- rc.right = opt.iWinWidth;
- int iWidth = opt.iPadding;
- int iWinAvatarHeight = 0;
- bool bStatusMsg = false;
- HFONT hOldFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
-
- // avatar height
- pwd->iAvatarHeight = 0;
- if (!pwd->bIsTextTip && opt.avatarLayout != PAV_NONE && ServiceExists(MS_AV_GETAVATARBITMAP)) {
- AVATARCACHEENTRY *ace = 0;
- if (pwd->hContact) ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pwd->hContact, 0);
- else ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto);
-
- if (ace && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
- if (opt.bOriginalAvatarSize && max(ace->bmWidth, ace->bmHeight) <= opt.iAvatarSize) {
- pwd->iRealAvatarHeight = ace->bmHeight;
- pwd->iRealAvatarWidth = ace->bmWidth;
- }
- else if (ace->bmHeight >= ace->bmWidth) {
- pwd->iRealAvatarHeight = opt.iAvatarSize;
- pwd->iRealAvatarWidth = (int)(opt.iAvatarSize * (ace->bmWidth / (double)ace->bmHeight));
- }
- else {
- pwd->iRealAvatarHeight = (int)(opt.iAvatarSize * (ace->bmHeight / (double)ace->bmWidth));
- pwd->iRealAvatarWidth = opt.iAvatarSize;
- }
-
- pwd->iAvatarHeight = opt.iOuterAvatarPadding + opt.iInnerAvatarPadding + pwd->iRealAvatarHeight;
- iWinAvatarHeight = 2 * opt.iOuterAvatarPadding + pwd->iRealAvatarHeight;
- iWidth += pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding);
- }
- }
-
- // titlebar height
- if (!pwd->bIsTextTip && pwd->swzTitle && opt.bShowTitle) {
- smr.top = smr.bottom = 0;
- smr.left = rc.left + opt.iPadding + pwd->iIndent;
- smr.right = rc.right;
-
- if (pwd->iRealAvatarWidth > 0)
- smr.right -= pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding;
- else
- smr.right -= opt.iPadding;
-
- if (hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle);
- DrawTextExt(hdc, pwd->swzTitle, -1, &smr, DT_CALCRECT | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, NULL, pwd->spiTitle);
-
- iWidth += opt.iPadding + opt.iTitleIndent + smr.right;
- pwd->iTitleHeight = opt.iPadding + smr.bottom;
- }
- else pwd->iTitleHeight = opt.iPadding;
-
- // icon height
- int i, iCount = 0;
- if (pwd->hContact || pwd->clcit.szProto) {
- for(i = 0; i < EXICONS_COUNT; i++) {
- if ((INT_PTR)pwd->extraIcons[i].hIcon == CALLSERVICE_NOTFOUND)
- pwd->extraIcons[i].hIcon = 0;
-
- if (pwd->extraIcons[i].hIcon)
- iCount++;
- }
- }
- pwd->iIconsHeight = (iCount * 20) + 20;
-
- // text height
- pwd->iTextHeight = pwd->iLabelWidth = 0;
- // iterate once to find max label width for items with label and value on same line, but don't consider width of labels on a new line
- for (i = 0; i < pwd->iRowCount; i++) {
- if (pwd->rows[i].swzLabel && !pwd->rows[i].bValueNewline) {
- if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) {
- if (hFontTrayTitle)
- SelectObject(hdc, (HGDIOBJ)hFontTrayTitle);
- }
- else if (hFontLabels)
- SelectObject(hdc, (HGDIOBJ)hFontLabels);
-
- GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, (int)_tcslen(pwd->rows[i].swzLabel), &sz);
- if (sz.cx > pwd->iLabelWidth)
- pwd->iLabelWidth = sz.cx;
- }
- }
-
- for (i = 0; i < pwd->iRowCount; i++) {
- if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) {
- if (hFontTrayTitle)
- SelectObject(hdc, (HGDIOBJ)hFontTrayTitle);
- }
- else if (hFontLabels)
- SelectObject(hdc, (HGDIOBJ)hFontLabels);
-
- if (pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0])
- GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, (int)_tcslen(pwd->rows[i].swzLabel), &sz);
- else
- sz.cy = sz.cx = 0;
-
- // save so we don't have to recalculate
- pwd->rows[i].iLabelHeight = sz.cy;
-
- smr.top = smr.bottom = 0;
- smr.left = rc.left + opt.iPadding + pwd->iIndent;
- smr.right = rc.right;
- if (hFontValues) SelectObject(hdc, (HGDIOBJ)hFontValues);
- if (pwd->iTitleHeight + pwd->iTextHeight + opt.iTextPadding < pwd->iAvatarHeight)
- smr.right -= pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding;
- else
- smr.right -= opt.iPadding;
-
- if (!pwd->rows[i].bValueNewline)
- smr.right -= pwd->iLabelWidth + opt.iValueIndent;
-
- if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) {
- if (!bStatusMsg && opt.bGetNewStatusMsg) {
- if (!_tcscmp(pwd->rows[i].swzValue, _T("%sys:status_msg%")))
- bStatusMsg = true;
- }
-
- DrawTextExt(hdc, pwd->rows[i].swzValue, -1, &smr, DT_CALCRECT | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, NULL, pwd->rows[i].spi);
- }
- else smr.left = smr.right = 0;
-
- // save so we don't have to recalculate
- pwd->rows[i].iValueHeight = smr.bottom;
-
- pwd->rows[i].iTotalHeight = (pwd->rows[i].bLineAbove ? opt.iTextPadding : 0);
- if (pwd->rows[i].bValueNewline) {
- if (sz.cy) pwd->rows[i].iTotalHeight += sz.cy + opt.iTextPadding;
- if (smr.bottom) pwd->rows[i].iTotalHeight += smr.bottom + opt.iTextPadding;
- }
- else {
- int maxheight = max(sz.cy, smr.bottom);
- if (maxheight) pwd->rows[i].iTotalHeight += maxheight + opt.iTextPadding;
- }
-
- // only consider this item's width, and include it's height, if it doesn't make the window too big
- if (max(pwd->iTitleHeight + pwd->iTextHeight + opt.iPadding + pwd->rows[i].iTotalHeight, pwd->iAvatarHeight) <= opt.iWinMaxHeight || pwd->bIsTrayTip) {
- if (iWidth < opt.iWinWidth) {
- int wid = opt.iPadding + pwd->iIndent + (pwd->rows[i].bValueNewline ? max(sz.cx, smr.right - smr.left) : pwd->iLabelWidth + opt.iValueIndent + (smr.right - smr.left));
- if (pwd->iTitleHeight + pwd->iTextHeight + opt.iTextPadding < pwd->iAvatarHeight)
- iWidth = max(iWidth, wid + pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding);
- else
- iWidth = max(iWidth, wid + opt.iPadding);
- }
-
- pwd->iTextHeight += pwd->rows[i].iTotalHeight;
- }
- }
-
- SelectObject(hdc, hOldFont);
- ReleaseDC(hwnd, hdc);
-
- int iHeight = max(pwd->iTitleHeight + pwd->iTextHeight + opt.iPadding, iWinAvatarHeight);
- iHeight = max(pwd->iIconsHeight, iHeight);
- if (bStatusMsg) iHeight += 50;
-
- if (iHeight < opt.iMinHeight) iHeight = opt.iMinHeight;
- // ignore minwidth for text tips
- if (!pwd->bIsTextTip && iWidth < opt.iMinWidth) iWidth = opt.iMinWidth;
-
- // ignore maxheight for tray tip
- if (!pwd->bIsTrayTip && iHeight > opt.iWinMaxHeight) iHeight = opt.iWinMaxHeight;
- if (iWidth > opt.iWinWidth) iWidth = opt.iWinWidth;
-
- CreateSkinBitmap(iWidth, iHeight, pwd->bIsTextTip && !pwd->bIsTrayTip);
-
- GetWindowRect(hwnd, &rc);
- if (rc.right - rc.left != iWidth || rc.bottom - rc.top != iHeight)
- {
- SetWindowPos(hwnd, 0, 0, 0, iWidth, iHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
- GetWindowRect(hwnd, &pwd->rcWindow);
- SendMessage(hwnd, PUM_UPDATERGN, 0, 0);
- InvalidateRect(hwnd, 0, TRUE);
- }
-
- if (pHeight)
- *pHeight = iHeight;
- }
- return TRUE;
-
- case PUM_UPDATERGN:
- {
- HRGN hRgn;
- RECT r = pwd->rcWindow;
- int v, h;
- int w = 11;
-
- r.right -= r.left;
- r.left = 0;
- r.bottom -= r.top;
- r.top = 0;
-
- if (opt.showEffect == PSE_FADE && wParam == 1) {
- if (skin.bNeedLayerUpdate) {
- POINT ptSrc = { 0, 0 };
- SIZE sz = { r.right - r.left, r.bottom - r.top };
-
- BLENDFUNCTION blend;
- blend.BlendOp = AC_SRC_OVER;
- blend.BlendFlags = 0;
- blend.SourceConstantAlpha = pwd->iCurrentTrans;
- blend.AlphaFormat = AC_SRC_ALPHA;
-
- pwd->iCurrentTrans += opt.iAnimateSpeed;
- if (pwd->iCurrentTrans > pwd->iTrans) {
- pwd->iCurrentTrans = pwd->iTrans;
- pwd->iAnimStep = ANIM_STEPS;
- }
-
- UpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
-
- }
- else {
- pwd->iCurrentTrans += opt.iAnimateSpeed;
- if (pwd->iCurrentTrans > pwd->iTrans) {
- pwd->iCurrentTrans = pwd->iTrans;
- pwd->iAnimStep = ANIM_STEPS;
- }
-
- SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), pwd->iCurrentTrans, LWA_ALPHA);
- }
- }
- else if (opt.showEffect == PSE_ANIMATE && pwd->bIsPainted) {
- if (pwd->iAnimStep <= (ANIM_STEPS / opt.iAnimateSpeed)) {
- float frac = 1.0f - pwd->iAnimStep / ((float)ANIM_STEPS / opt.iAnimateSpeed);
- int wi = r.right, hi = r.bottom;
-
- r.left += (int)(wi / 2.0f * frac + 0.5f);
- r.right -= (int)(wi / 2.0f * frac + 0.5f);
- r.top += (int)(hi / 2.0f * frac + 0.5f);
- r.bottom -= (int)(hi / 2.0f * frac + 0.5f);
- }
- else pwd->iAnimStep = ANIM_STEPS;
-
- if (skin.bNeedLayerUpdate) {
- RECT r2 = pwd->rcWindow;
- POINT ptPos = { r.left + r2.left, r.top + r2.top };
- POINT ptSrc = { r.left, r.top };
-
- SIZE sz = { r.right - r.left, r.bottom - r.top };
-
- BLENDFUNCTION blend;
- blend.BlendOp = AC_SRC_OVER;
- blend.BlendFlags = 0;
- blend.SourceConstantAlpha = pwd->iTrans;
- blend.AlphaFormat = AC_SRC_ALPHA;
-
- UpdateLayeredWindow(hwnd, NULL, &ptPos, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
- }
- }
-
- if (!skin.bNeedLayerUpdate) {
- // round corners
- if (opt.bRound) {
- h = (r.right - r.left) > (w * 2) ? w : (r.right - r.left);
- v = (r.bottom - r.top) > (w * 2) ? w : (r.bottom - r.top);
- h = (h < v) ? h : v;
- }
- else h = 0;
-
- hRgn = CreateRoundRectRgn(r.left, r.top, r.right + 1, r.bottom + 1, h, h);
- SetWindowRgn(hwnd, hRgn, FALSE);
-
- if (opt.showEffect == PSE_ANIMATE && pwd->iAnimStep == 1)
- SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), pwd->iTrans, LWA_ALPHA);
- }
- else {
- // aero glass (vista+)
- if (opt.bAeroGlass && MyDwmEnableBlurBehindWindow && pwd->iAnimStep > 5) {
- if (pwd->hrgnAeroGlass) {
- DeleteObject(pwd->hrgnAeroGlass);
- pwd->hrgnAeroGlass = 0;
- }
-
- pwd->hrgnAeroGlass = CreateOpaqueRgn(25, true);
-
- if (pwd->hrgnAeroGlass) {
- DWM_BLURBEHIND bb = { 0 };
- bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- bb.fEnable = TRUE;
- bb.hRgnBlur = pwd->hrgnAeroGlass;
- MyDwmEnableBlurBehindWindow(hwnd, &bb);
- }
- }
- }
- }
- return TRUE;
-
- case PUM_CALCPOS:
- {
- RECT rcWork, rc;
- SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, FALSE);
-
- HMONITOR hMon = MonitorFromPoint(pwd->clcit.ptCursor, MONITOR_DEFAULTTONEAREST);
- MONITORINFO mi;
- mi.cbSize = sizeof(mi);
- if (GetMonitorInfo(hMon, &mi))
- rcWork = mi.rcWork;
-
- GetWindowRect(hwnd, &rc);
-
- int x = 0, y = 0, iWidth = (rc.right - rc.left), iHeight = (rc.bottom - rc.top);
-
- switch (opt.pos) {
- case PP_BOTTOMRIGHT:
- x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON); // cursor size is too large - use small icon size
- y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON);
- break;
- case PP_BOTTOMLEFT:
- x = pwd->clcit.ptCursor.x - iWidth - GetSystemMetrics(SM_CXSMICON);
- y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON);
- break;
- case PP_TOPRIGHT:
- x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON);
- y = pwd->clcit.ptCursor.y - iHeight - GetSystemMetrics(SM_CYSMICON);
- break;
- case PP_TOPLEFT:
- x = pwd->clcit.ptCursor.x - iWidth - GetSystemMetrics(SM_CXSMICON);
- y = pwd->clcit.ptCursor.y - iHeight - GetSystemMetrics(SM_CYSMICON);
- break;
- }
-
-
- if (x + iWidth + 8 > rcWork.right)
- x = rcWork.right - iWidth - 8;
- if (x - 8 < rcWork.left)
- x = rcWork.left + 8;
-
- if (pwd->bAllowReposition || !pwd->bNeedRefresh) {
- if (y + iHeight > rcWork.bottom) {
- y = pwd->clcit.ptCursor.y - iHeight - 8;
- pwd->bAllowReposition = true;
- }
-
- if (y - 8 < rcWork.top) {
- y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON);
- pwd->bAllowReposition = true;
- }
- }
-
- SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
- GetWindowRect(hwnd, &pwd->rcWindow);
- }
- return TRUE;
-
- case PUM_REFRESHTRAYTIP:
- for (int i = 0; i < pwd->iRowCount; i++) {
- mir_free(pwd->rows[i].swzLabel);
- mir_free(pwd->rows[i].swzValue);
- Smileys_FreeParse(pwd->rows[i].spi);
- }
-
- if (pwd->rows) {
- mir_free(pwd->rows);
- pwd->rows = NULL;
- }
-
- pwd->iRowCount = 0;
-
- DWORD dwItems = (wParam == 0) ? opt.iFirstItems : opt.iSecondItems;
- bool bFirstItem = true;
- TCHAR buff[64];
-
- int oldOrder = -1, iProtoCount = 0;
- PROTOACCOUNT **accs;
- ProtoEnumAccounts(&iProtoCount, &accs);
-
- for (int j = 0; j < iProtoCount; j++) {
- PROTOACCOUNT *pa = NULL;
- for (int i = 0; i < iProtoCount; i++)
- if (accs[i]->iOrder > oldOrder && (pa == NULL || accs[i]->iOrder < pa->iOrder))
- pa = accs[i];
-
- if (pa == NULL)
- continue;
-
- oldOrder = pa->iOrder;
-
- WORD wStatus = CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0);
- if (opt.bHideOffline && wStatus == ID_STATUS_OFFLINE)
- continue;
-
- if (!IsAccountEnabled(pa) || !IsTrayProto(pa->tszAccountName, (BOOL)wParam))
- continue;
-
- if (dwItems & TRAYTIP_NUMCONTACTS) {
- int iCount = 0, iCountOnline = 0;
- for (MCONTACT hContact = db_find_first(pa->szModuleName); hContact; hContact = db_find_next(hContact, pa->szModuleName)) {
- if (db_get_w(hContact, pa->szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
- iCountOnline++;
- iCount++;
- }
- mir_sntprintf(buff, 64, _T("(%d/%d)"), iCountOnline, iCount);
- }
- else buff[0] = 0;
-
- TCHAR swzProto[256];
- _tcscpy(swzProto, pa->tszAccountName);
- if (dwItems & TRAYTIP_LOCKSTATUS)
- if (CallService(MS_PROTO_ISACCOUNTLOCKED, 0, (LPARAM)pa->szModuleName))
- mir_sntprintf(swzProto, SIZEOF(swzProto), TranslateT("%s (locked)"), pa->tszAccountName);
-
- AddRow(pwd, swzProto, buff, NULL, false, false, !bFirstItem, true, LoadSkinnedProtoIcon(pa->szModuleName, wStatus));
- bFirstItem = false;
-
- if (dwItems & TRAYTIP_LOGON) {
- if (TimestampToTimeDifference(NULL, pa->szModuleName, "LogonTS", buff, 59)) {
- TCHAR ago[96];
- mir_sntprintf(ago, SIZEOF(ago), TranslateT("%s ago"), buff);
- AddRow(pwd, TranslateT("Log on:"), ago, NULL, false, false, false);
- }
- }
-
- if (dwItems & TRAYTIP_UNREAD_EMAILS && ProtoServiceExists(pa->szModuleName, PS_GETUNREADEMAILCOUNT)) {
- int iCount = (int)ProtoCallService(pa->szModuleName, PS_GETUNREADEMAILCOUNT, 0, 0);
- if (iCount > 0) {
- _itot(iCount, buff, 10);
- AddRow(pwd, TranslateT("Unread emails:"), buff, NULL, false, false, false);
- }
- }
-
- if (dwItems & TRAYTIP_STATUS) {
- TCHAR *swzText = pcli->pfnGetStatusModeDescription(wStatus, 0);
- if (swzText)
- AddRow(pwd, TranslateT("Status:"), swzText, NULL, false, false, false);
- }
-
- if (wStatus >= ID_STATUS_ONLINE && wStatus <= ID_STATUS_OUTTOLUNCH) {
- if (dwItems & TRAYTIP_STATUS_MSG) {
- TCHAR *swzText = GetProtoStatusMessage(pa->szModuleName, wStatus);
- if (swzText) {
- StripBBCodesInPlace(swzText);
- AddRow(pwd, TranslateT("Status message:"), swzText, pa->szModuleName, true, true, false);
- mir_free(swzText);
- }
- }
-
- if (dwItems & TRAYTIP_EXTRA_STATUS) {
- // jabber mood or icq xstatus
- TCHAR *swzAdvTitle = GetJabberAdvStatusText(pa->szModuleName, "mood", "title");
- if (swzAdvTitle) {
- StripBBCodesInPlace(swzAdvTitle);
- AddRow(pwd, TranslateT("Mood:"), swzAdvTitle, pa->szModuleName, true, false, false);
- mir_free(swzAdvTitle);
-
- TCHAR *swzAdvText = GetJabberAdvStatusText(pa->szModuleName, "mood", "text");
- if (swzAdvText) {
- StripBBCodesInPlace(swzAdvText);
- AddRow(pwd, _T(""), swzAdvText, pa->szModuleName, true, true, false);
- mir_free(swzAdvText);
- }
- }
- else {
- if (db_get_b(0, pa->szModuleName, "XStatusId", 0)) {
- // xstatus title
- swzAdvTitle = GetProtoExtraStatusTitle(pa->szModuleName);
- if (swzAdvTitle) {
- StripBBCodesInPlace(swzAdvTitle);
- AddRow(pwd, TranslateT("xStatus:"), swzAdvTitle, pa->szModuleName, true, false, false);
- mir_free(swzAdvTitle);
- }
-
- // xstatus message
- TCHAR *swzAdvText = GetProtoExtraStatusMessage(pa->szModuleName);
- if (swzAdvText) {
- StripBBCodesInPlace(swzAdvText);
- AddRow(pwd, _T(""), swzAdvText, pa->szModuleName, true, true, false);
- mir_free(swzAdvText);
- }
- }
- }
-
- TCHAR *swzActTitle = GetJabberAdvStatusText(pa->szModuleName, "activity", "title");
- if (swzActTitle) {
- StripBBCodesInPlace(swzActTitle);
- AddRow(pwd, TranslateT("Activity:"), swzActTitle, pa->szModuleName, true, false, false);
- mir_free(swzActTitle);
- }
-
- TCHAR *swzActText = GetJabberAdvStatusText(pa->szModuleName, "activity", "text");
- if (swzActText) {
- StripBBCodesInPlace(swzActText);
- AddRow(pwd, _T(""), swzActText, pa->szModuleName, true, true, false);
- mir_free(swzActText);
- }
- }
-
- if (dwItems & TRAYTIP_LISTENINGTO) {
- TCHAR *swzListening = GetListeningTo(pa->szModuleName);
- if (swzListening) {
- StripBBCodesInPlace(swzListening);
- AddRow(pwd, TranslateT("Listening to:"), swzListening, NULL, false, true, false);
- mir_free(swzListening);
- }
- }
- }
- }
-
- if (dwItems & TRAYTIP_FAVCONTACTS) {
- if (db_get_dw(0, MODULE, "FavouriteContactsCount", 0)) {
- TCHAR swzName[256];
- TCHAR swzStatus[256];
- bool bTitlePainted = false;
- int iCount = 0, iCountOnline = 0;
-
- for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
- if (db_get_b(hContact, MODULE, "FavouriteContact", 0)) {
- char *proto = GetContactProto(hContact);
- if (proto == NULL)
- continue;
-
- WORD wStatus = db_get_w(hContact, proto, "Status", ID_STATUS_OFFLINE);
- WordToStatusDesc(hContact, proto, "Status", swzStatus, 256);
-
- if (wStatus != ID_STATUS_OFFLINE)
- iCountOnline++;
-
- iCount++;
-
- if (!(opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE && wStatus == ID_STATUS_OFFLINE)) {
- if (!bTitlePainted) {
- AddRow(pwd, TranslateT("Fav. contacts"), NULL, NULL, false, false, !bFirstItem, true, NULL);
- bFirstItem = false;
- bTitlePainted = true;
- }
-
- TCHAR *swzNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, hContact, GCDNF_TCHAR);
- if (opt.iFavoriteContFlags & FAVCONT_APPEND_PROTO) {
- TCHAR *swzProto = a2t(proto);
- mir_sntprintf(swzName, 256, _T("%s (%s)"), swzNick, swzProto);
- mir_free(swzProto);
- }
- else _tcscpy(swzName, swzNick);
-
- AddRow(pwd, swzName, swzStatus, NULL, false, false, false);
- }
- }
- }
-
- int index = pwd->iRowCount - 1;
- if (opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE)
- index -= iCountOnline;
- else
- index -= iCount;
-
- if (index >= 0 && (dwItems & TRAYTIP_NUMCONTACTS) && !((opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE) && iCountOnline == 0)) {
- mir_sntprintf(buff, 64, _T("(%d/%d)"), iCountOnline, iCount);
- pwd->rows[index].swzValue = mir_tstrdup(buff);
- }
- }
- }
-
- if (dwItems & TRAYTIP_MIRANDA_UPTIME) {
- if (TimestampToTimeDifference(NULL, MODULE, "MirandaStartTS", buff, 64)) {
- AddRow(pwd, TranslateT("Other"), _T(""), NULL, false, false, !bFirstItem, true, NULL);
- AddRow(pwd, TranslateT("Miranda uptime:"), buff, NULL, false, false, false);
- }
- }
-
- if (dwItems & TRAYTIP_CLIST_EVENT && pwd->clcit.swzText) {
- TCHAR *pchBr = _tcschr(pwd->clcit.swzText, '\n');
- TCHAR *pchBold = _tcsstr(pwd->clcit.swzText, _T("<b>"));
-
- if (!pchBold || pchBold != pwd->clcit.swzText) {
- TCHAR swzText[256];
- _tcscpy(swzText, pwd->clcit.swzText);
- if (pchBr) swzText[pchBr - pwd->clcit.swzText] = 0;
- AddRow(pwd, swzText, _T(""), NULL, false, true, false, true, LoadSkinnedIcon(SKINICON_OTHER_FILLEDBLOB));
- }
- }
-
- return TRUE;
- }
-
- return DefWindowProc(hwnd, uMsg, wParam, lParam);
-}
+/*
+Copyright (C) 2006-2007 Scott Ellis
+Copyright (C) 2007-2011 Jan Holub
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "common.h"
+
+__inline void AddRow(PopupWindowData *pwd, TCHAR *swzLabel, TCHAR *swzValue, char *szProto, bool bParseSmileys, bool bNewline, bool bLineAbove, bool bIsTitle = false, HICON hIcon = NULL)
+{
+ pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData) * (pwd->iRowCount + 1));
+ pwd->rows[pwd->iRowCount].swzLabel = swzLabel ? mir_tstrdup(swzLabel) : NULL;
+ pwd->rows[pwd->iRowCount].swzValue = swzValue ? mir_tstrdup(swzValue) : NULL;
+ pwd->rows[pwd->iRowCount].spi = bParseSmileys ? Smileys_PreParse(swzValue, (int)_tcslen(swzValue), szProto) : NULL;
+ pwd->rows[pwd->iRowCount].bValueNewline = bNewline;
+ pwd->rows[pwd->iRowCount].bLineAbove = bLineAbove;
+ pwd->rows[pwd->iRowCount].bIsTitle = bIsTitle;
+ pwd->rows[pwd->iRowCount].hIcon = hIcon;
+ pwd->iRowCount++;
+}
+
+LRESULT CALLBACK PopupWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ PopupWindowData *pwd = (PopupWindowData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch(uMsg) {
+ case WM_CREATE:
+ {
+ CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+ pwd = (PopupWindowData *)mir_alloc(sizeof(PopupWindowData));
+ memset(pwd, 0, sizeof(PopupWindowData));
+ pwd->clcit = *(CLCINFOTIPEX *)cs->lpCreateParams;
+ pwd->iIconIndex = -1;
+ pwd->hpenBorder = CreatePen(PS_SOLID, 1, opt.bBorder ? opt.colBorder : opt.colBg);
+ pwd->hpenDivider = CreatePen(PS_SOLID, 1, opt.colDivider);
+ pwd->iTrans = (int)(opt.iOpacity / 100.0 * 255);
+
+ // load icons order
+ for (int i = 0; i < EXICONS_COUNT; i++)
+ pwd->bIsIconVisible[opt.exIconsOrder[i]] = opt.exIconsVis[i] ? true : false;
+
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pwd);
+
+ // work around bug hiding tips
+ GetCursorPos(&pwd->ptCursorStartPos);
+ SetTimer(hwnd, ID_TIMER_CHECKMOUSE, CHECKMOUSE_ELAPSE, 0);
+
+ //Register copy menu hotkey (CTRL+C)
+ pwd->iHotkeyId = GlobalAddAtom(_T("Tipper"));
+ RegisterHotKey(hwnd, pwd->iHotkeyId, MOD_CONTROL, 0x43);
+
+ if (pwd->clcit.szProto) {
+ pwd->bIsTextTip = false;
+ pwd->iIndent = opt.iTextIndent;
+ pwd->iSidebarWidth = opt.iSidebarWidth;
+
+ if (ServiceExists(MS_PROTO_GETACCOUNT)) {
+ PROTOACCOUNT *pa = ProtoGetAccount(pwd->clcit.szProto);
+ if (pa)
+ _tcscpy(pwd->swzTitle, pa->tszAccountName);
+ }
+
+ if (_tcslen(pwd->swzTitle) == 0)
+ a2t(pwd->clcit.szProto, pwd->swzTitle, TITLE_TEXT_LEN);
+
+ if (CallService(MS_PROTO_ISACCOUNTLOCKED, 0, (LPARAM)pwd->clcit.szProto))
+ mir_sntprintf(pwd->swzTitle, SIZEOF(pwd->swzTitle), TranslateT("%s (locked)"), pwd->swzTitle);
+
+ // protocol status
+ WORD wStatus = (WORD)CallProtoService(pwd->clcit.szProto, PS_GETSTATUS, 0, 0);
+
+ // get status icon
+ if (pwd->bIsIconVisible[0]) {
+ pwd->extraIcons[0].hIcon = LoadSkinnedProtoIcon(pwd->clcit.szProto, wStatus);
+ pwd->extraIcons[0].bDestroy = false;
+ }
+
+ // get activity icon
+ if (pwd->bIsIconVisible[2]) {
+ pwd->extraIcons[2].hIcon = GetJabberActivityIcon(0, pwd->clcit.szProto);
+ pwd->extraIcons[2].bDestroy = false;
+ }
+
+ // uid info
+ TCHAR swzUid[256], swzUidName[256];
+ if (Uid(0, pwd->clcit.szProto, swzUid, 256) && UidName(pwd->clcit.szProto, swzUidName, 253)) {
+ _tcscat(swzUidName, _T(": "));
+ AddRow(pwd, swzUidName, swzUid, NULL, false, false, false);
+ }
+
+ // logon info
+ TCHAR swzLogon[64];
+ if (TimestampToTimeDifference(NULL, pwd->clcit.szProto, "LogonTS", swzLogon, 59)) {
+ TCHAR ago[96];
+ mir_sntprintf(ago, SIZEOF(ago), TranslateT("%s ago"), swzLogon);
+ AddRow(pwd, TranslateT("Log on:"), ago, NULL, false, false, false);
+ }
+
+ // number of unread emails
+ TCHAR swzEmailCount[64];
+ if (ProtoServiceExists(pwd->clcit.szProto, PS_GETUNREADEMAILCOUNT)) {
+ int iCount = (int)ProtoCallService(pwd->clcit.szProto, PS_GETUNREADEMAILCOUNT, 0, 0);
+ if (iCount > 0) {
+ _itot(iCount, swzEmailCount, 10);
+ AddRow(pwd, TranslateT("Unread emails:"), swzEmailCount, NULL, false, false, false);
+ }
+ }
+
+ TCHAR *swzText = pcli->pfnGetStatusModeDescription(wStatus, 0);
+ if (swzText)
+ AddRow(pwd, TranslateT("Status:"), swzText, NULL, false, false, false);
+
+ if (wStatus >= ID_STATUS_ONLINE && wStatus <= ID_STATUS_OUTTOLUNCH) {
+ // status message
+ TCHAR *swzText = GetProtoStatusMessage(pwd->clcit.szProto, wStatus);
+ if (swzText) {
+ StripBBCodesInPlace(swzText);
+ AddRow(pwd, TranslateT("Status message:"), swzText, pwd->clcit.szProto, true, true, true);
+ mir_free(swzText);
+ }
+
+ // jabber mood or icq xstatus
+ TCHAR *swzAdvTitle = GetJabberAdvStatusText(pwd->clcit.szProto, "mood", "title");
+ if (swzAdvTitle) {
+ StripBBCodesInPlace(swzAdvTitle);
+ AddRow(pwd, TranslateT("Mood:"), swzAdvTitle, pwd->clcit.szProto, true, false, true);
+
+ TCHAR *swzAdvText = GetJabberAdvStatusText(pwd->clcit.szProto, "mood", "text");
+ if (swzAdvText) {
+ StripBBCodesInPlace(swzAdvText);
+ AddRow(pwd, _T(""), swzAdvText, pwd->clcit.szProto, true, true, false);
+ mir_free(swzAdvText);
+ }
+ }
+ else {
+ if (db_get_b(0, pwd->clcit.szProto, "XStatusId", 0)) {
+ // xstatus title
+ swzAdvTitle = GetProtoExtraStatusTitle(pwd->clcit.szProto);
+ if (swzAdvTitle) {
+ StripBBCodesInPlace(swzAdvTitle);
+ AddRow(pwd, TranslateT("xStatus:"), swzAdvTitle, pwd->clcit.szProto, true, false, true);
+ }
+
+ // xstatus message
+ TCHAR *swzAdvText = GetProtoExtraStatusMessage(pwd->clcit.szProto);
+ if (swzAdvText) {
+ StripBBCodesInPlace(swzAdvText);
+ AddRow(pwd, _T(""), swzAdvText, pwd->clcit.szProto, true, true, false);
+ mir_free(swzAdvText);
+ }
+ }
+ }
+
+ if (swzAdvTitle) {
+ mir_free(swzAdvTitle);
+ // get advanced status icon
+ if (pwd->bIsIconVisible[1]) {
+ pwd->extraIcons[1].hIcon = (HICON)CallProtoService(pwd->clcit.szProto, PS_GETCUSTOMSTATUSICON, 0, LR_SHARED);
+ pwd->extraIcons[1].bDestroy = false;
+ }
+ }
+
+ // jabber activity
+ TCHAR *swzActTitle = GetJabberAdvStatusText(pwd->clcit.szProto, "activity", "title");
+ if (swzActTitle) {
+ StripBBCodesInPlace(swzActTitle);
+ AddRow(pwd, TranslateT("Activity:"), swzActTitle, pwd->clcit.szProto, true, false, true);
+ mir_free(swzActTitle);
+ }
+
+ TCHAR *swzActText = GetJabberAdvStatusText(pwd->clcit.szProto, "activity", "text");
+ if (swzActText) {
+ StripBBCodesInPlace(swzActText);
+ AddRow(pwd, _T(""), swzActText, pwd->clcit.szProto, true, true, false);
+ mir_free(swzActText);
+ }
+
+ // listening to
+ TCHAR *swzListening = GetListeningTo(pwd->clcit.szProto);
+ if (swzListening) {
+ StripBBCodesInPlace(swzListening);
+ AddRow(pwd, TranslateT("Listening to:"), swzListening, NULL, false, true, true);
+ mir_free(swzListening);
+ }
+ }
+ }
+ else if (pwd->clcit.swzText) {
+ pwd->bIsTextTip = true;
+ pwd->iIndent = 0;
+ pwd->iSidebarWidth = 0;
+
+ RECT rc = pwd->clcit.rcItem;
+ bool mirandaTrayTip = ((rc.right - rc.left) == 20) && ((rc.bottom - rc.top) == 20) ? true : false;
+
+ if (mirandaTrayTip && !opt.bTraytip) {
+ MyDestroyWindow(hwnd);
+ return 0;
+ }
+
+ if (mirandaTrayTip && opt.bHandleByTipper) { // extended tray tooltip
+ pwd->bIsTrayTip = true;
+ pwd->iIndent = opt.iTextIndent;
+ pwd->iSidebarWidth = opt.iSidebarWidth;
+
+ SendMessage(hwnd, PUM_REFRESHTRAYTIP, 0, 0);
+
+ if (opt.bExpandTraytip)
+ SetTimer(hwnd, ID_TIMER_TRAYTIP, opt.iExpandTime, 0);
+ }
+ else {
+ TCHAR buff[2048], *swzText = pwd->clcit.swzText;
+ size_t iBuffPos, i = 0, iSize = _tcslen(pwd->clcit.swzText);
+ bool bTopMessage = false;
+
+ while (i < iSize && swzText[i] != _T('<')) {
+ iBuffPos = 0;
+ while (swzText[i] != _T('\n') && swzText[i] != _T('\r') && i < iSize && iBuffPos < 2048) {
+ if (swzText[i] != _T('\t'))
+ buff[iBuffPos++] = swzText[i];
+ i++;
+ }
+
+ buff[iBuffPos] = 0;
+
+ if (iBuffPos) {
+ AddRow(pwd, _T(""), buff, NULL, false, true, false);
+ bTopMessage = true;
+ }
+
+ while (i < iSize && (swzText[i] == _T('\n') || swzText[i] == _T('\r')))
+ i++;
+ }
+
+ // parse bold bits into labels and the rest into items
+ while (i < iSize) {
+ while (i + 2 < iSize && (swzText[i] != _T('<') || swzText[i + 1] != _T('b') || swzText[i + 2] != _T('>')))
+ i++;
+
+ i += 3;
+
+ iBuffPos = 0;
+ while (i + 3 < iSize && iBuffPos < 2048 && (swzText[i] != _T('<')
+ || swzText[i + 1] != _T('/') || swzText[i + 2] != _T('b') || swzText[i + 3] != _T('>'))) {
+ if (swzText[i] != _T('\t'))
+ buff[iBuffPos++] = swzText[i];
+ i++;
+ }
+
+ i += 4;
+
+ buff[iBuffPos] = 0;
+
+ if (iBuffPos) {
+ pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData)* (pwd->iRowCount + 1));
+ pwd->rows[pwd->iRowCount].bValueNewline = false;
+ pwd->rows[pwd->iRowCount].swzLabel = mir_tstrdup(buff);
+ if (pwd->iRowCount == 1 && bTopMessage)
+ pwd->rows[pwd->iRowCount].bLineAbove = true;
+ else
+ pwd->rows[pwd->iRowCount].bLineAbove = false;
+
+ iBuffPos = 0;
+ while (i < iSize && iBuffPos < 2048 && swzText[i] != _T('\n')) {
+ if (swzText[i] != _T('\t') && swzText[i] != _T('\r'))
+ buff[iBuffPos++] = swzText[i];
+ i++;
+ }
+ buff[iBuffPos] = 0;
+
+ pwd->rows[pwd->iRowCount].swzValue = mir_tstrdup(buff);
+ pwd->rows[pwd->iRowCount].spi = NULL;
+ pwd->iRowCount++;
+ }
+
+ i++;
+ }
+
+ if (pwd->iRowCount == 0) {
+ // single item
+ pwd->iRowCount = 1;
+ pwd->rows = (RowData *)mir_alloc(sizeof(RowData));
+ pwd->rows[0].bLineAbove = pwd->rows[0].bValueNewline = false;
+ pwd->rows[0].swzLabel = 0;
+ pwd->rows[0].swzValue = swzText;
+ pwd->rows[0].spi = NULL;
+ }
+ }
+ }
+ else {
+ pwd->bIsTextTip = false;
+ pwd->iIndent = opt.iTextIndent;
+ pwd->iSidebarWidth = opt.iSidebarWidth;
+ pwd->hContact = (MCONTACT)pwd->clcit.hItem;
+ pwd->iIconIndex = (int)CallService(MS_CLIST_GETCONTACTICON, pwd->hContact, 0);
+
+ // don't use stored status message
+ if (!opt.bWaitForContent)
+ db_unset(pwd->hContact, MODULE, "TempStatusMsg");
+
+ TCHAR *swzNick = pcli->pfnGetContactDisplayName(pwd->hContact, 0);
+ _tcsncpy(pwd->swzTitle, swzNick, TITLE_TEXT_LEN);
+
+ char *szProto = GetContactProto(pwd->hContact);
+ pwd->spiTitle = Smileys_PreParse(pwd->swzTitle, -1, szProto);
+
+ // get extra icons
+ DBVARIANT dbv = { 0 };
+ int i = 0;
+
+ if (szProto) {
+ // status icon
+ if (pwd->bIsIconVisible[0]) {
+ for (i = 0; opt.exIconsOrder[i] != 0; i++);
+ pwd->extraIcons[i].hIcon = ImageList_GetIcon((HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), pwd->iIconIndex, 0);
+ pwd->extraIcons[i].bDestroy = true;
+ }
+
+ // xstatus icon
+ if (pwd->bIsIconVisible[1]) {
+ for (i = 0; opt.exIconsOrder[i] != 1; i++);
+ int iXstatus = db_get_b(pwd->hContact, szProto, "XStatusId", 0);
+ if (iXstatus) {
+ char szIconProto[64];
+ if (strcmp(szProto, META_PROTO) != 0)
+ strcpy(szIconProto, szProto);
+ else if (!db_get_s(pwd->hContact, szProto, "XStatusProto", &dbv)) {
+ strcpy(szIconProto, dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ pwd->extraIcons[i].hIcon = (HICON)CallProtoService(szIconProto, PS_GETCUSTOMSTATUSICON, (WPARAM)iXstatus, LR_SHARED);
+ pwd->extraIcons[i].bDestroy = false;
+ }
+ }
+
+ // activity icon
+ if (pwd->bIsIconVisible[2]) {
+ for (i = 0; opt.exIconsOrder[i] != 2; i++);
+ pwd->extraIcons[i].hIcon = GetJabberActivityIcon(pwd->hContact, szProto);
+ pwd->extraIcons[i].bDestroy = false;
+ }
+
+ // gender icon
+ if (pwd->bIsIconVisible[3]) {
+ for (i = 0; opt.exIconsOrder[i] != 3; i++);
+ int iGender = db_get_b(pwd->hContact, "UserInfo", "Gender", 0);
+ if (iGender == 0)
+ iGender = db_get_b(pwd->hContact, szProto, "Gender", 0);
+
+ if (iGender == GEN_FEMALE)
+ pwd->extraIcons[i].hIcon = Skin_GetIcon("gender_female");
+ else if (iGender == GEN_MALE)
+ pwd->extraIcons[i].hIcon = Skin_GetIcon("gender_male");
+ pwd->extraIcons[i].bDestroy = false;
+ }
+
+ // flags icon
+ if (pwd->bIsIconVisible[4]) {
+ for (i = 0; opt.exIconsOrder[i] != 4; i++);
+
+ INT_PTR iCountry = CallService(MS_FLAGS_DETECTCONTACTORIGINCOUNTRY, pwd->hContact, 0);
+ if (iCountry == CALLSERVICE_NOTFOUND)
+ iCountry = CallService(MS_FLAGS_GETCONTACTORIGINCOUNTRY, pwd->hContact, 0);
+
+ if (iCountry != CALLSERVICE_NOTFOUND && iCountry != 0 && iCountry != CTRY_UNKNOWN && iCountry != CTRY_ERROR) {
+ pwd->extraIcons[i].hIcon = LoadFlagIcon(iCountry);
+ pwd->extraIcons[i].bDestroy = false;
+ }
+ }
+
+ // fingerprint icon
+ if (pwd->bIsIconVisible[5]) {
+ for (i = 0; opt.exIconsOrder[i] != 5; i++);
+ if (ServiceExists(MS_FP_GETCLIENTICONT)) {
+ if (!db_get_ts(pwd->hContact, szProto, "MirVer", &dbv)) {
+ pwd->extraIcons[i].hIcon = Finger_GetClientIcon(dbv.ptszVal, 0);
+ pwd->extraIcons[i].bDestroy = true;
+ db_free(&dbv);
+ }
+ }
+ }
+
+ //request xstatus details
+ if (opt.bRetrieveXstatus)
+ if (!db_get_b(0, szProto, "XStatusAuto", 1) && ProtoServiceExists(szProto, PS_ICQ_REQUESTCUSTOMSTATUS))
+ CallProtoService(szProto, PS_ICQ_REQUESTCUSTOMSTATUS, pwd->hContact, 0);
+ }
+
+ SendMessage(hwnd, PUM_REFRESH_VALUES, FALSE, 0);
+ }
+
+ SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
+ SendMessage(hwnd, PUM_CALCPOS, 0, 0);
+
+ // transparency
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+
+ if (opt.bDropShadow && opt.skinMode == SM_COLORFILL)
+ SetClassLongPtr(hwnd, GCL_STYLE, CS_DROPSHADOW);
+ else
+ SetClassLongPtr(hwnd, GCL_STYLE, 0);
+
+ if (!skin.bNeedLayerUpdate)
+ SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_ALPHA);
+
+ if (opt.showEffect)
+ SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0);
+
+ ShowWindow(hwnd, SW_SHOWNOACTIVATE);
+ InvalidateRect(hwnd, 0, FALSE);
+
+ // since tipper win is topmost, this should put it at top of topmost windows
+ SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ return 0;
+
+ case WM_ERASEBKGND:
+ if (!skin.bNeedLayerUpdate) {
+ HDC hdc = (HDC)wParam;
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+
+ BitBlt(hdc, 0, 0, skin.iWidth, skin.iHeight, skin.hdc, 0, 0, SRCCOPY);
+
+ // border
+ if (opt.bBorder) {
+ HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
+ HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenBorder);
+
+ int h = 0;
+ if (opt.bRound) {
+ int v;
+ int w = 14;
+ h = (rc.right - rc.left) > (w * 2) ? w : (rc.right - rc.left);
+ v = (rc.bottom - rc.top) > (w * 2) ? w : (rc.bottom - rc.top);
+ h = (h < v) ? h : v;
+ }
+
+ RoundRect(hdc, 0, 0, (rc.right - rc.left), (rc.bottom - rc.top), h, h);
+
+ SelectObject(hdc, hOldBrush);
+ SelectObject(hdc, hOldPen);
+ }
+ }
+ return TRUE;
+
+ case WM_PAINT:
+ {
+ RECT r, r2;
+ PAINTSTRUCT ps;
+ BeginPaint(hwnd, &ps);
+ HDC hdc = skin.bNeedLayerUpdate ? skin.hdc : ps.hdc;
+
+ GetClientRect(hwnd, &r);
+ r2 = r;
+ HFONT hOldFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
+
+ // text background
+ SetBkMode(hdc, TRANSPARENT);
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = 255;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ // avatar
+ if (!pwd->bIsTextTip && opt.avatarLayout != PAV_NONE && pwd->iAvatarHeight) {
+ RECT rcAvatar;
+ rcAvatar.top = opt.iOuterAvatarPadding;
+
+ if (opt.avatarLayout == PAV_LEFT) {
+ rcAvatar.left = r.left + opt.iOuterAvatarPadding;
+ rcAvatar.right = rcAvatar.left + pwd->iRealAvatarWidth;
+ r2.left += pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding); // padding re-added for text
+ }
+ else if (opt.avatarLayout == PAV_RIGHT) {
+ rcAvatar.right = r.right - opt.iOuterAvatarPadding;
+ rcAvatar.left = rcAvatar.right - pwd->iRealAvatarWidth;
+ r2.right -= pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding);
+ }
+
+ rcAvatar.bottom = rcAvatar.top + pwd->iRealAvatarHeight;
+
+ AVATARCACHEENTRY *ace = 0;
+ if (pwd->hContact)
+ ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, pwd->hContact, 0);
+ else
+ ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto);
+
+ if (ace && ace->hbmPic && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
+ ResizeBitmap rb = { 0 };
+ rb.size = sizeof(rb);
+ rb.max_width = pwd->iRealAvatarWidth;
+ rb.max_height = pwd->iRealAvatarHeight;
+ rb.fit = RESIZEBITMAP_STRETCH | RESIZEBITMAP_KEEP_PROPORTIONS;
+ rb.hBmp = ace->hbmPic;
+ HBITMAP hbmpAvatar = (HBITMAP)CallService(MS_IMG_RESIZE, (WPARAM)&rb, 0);
+
+ if (hbmpAvatar) {
+ HRGN hrgnAvatar = 0;
+ if (opt.bAvatarRound) {
+ hrgnAvatar = CreateRoundRectRgn(rcAvatar.left, rcAvatar.top, rcAvatar.right + 1, rcAvatar.bottom + 1, 9, 9);
+ SelectClipRgn(hdc, hrgnAvatar);
+ }
+
+ BITMAP bm;
+ GetObject(hbmpAvatar, sizeof(bm), &bm);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ SelectObject(hdcMem, hbmpAvatar);
+
+ blend.SourceConstantAlpha = (BYTE)(opt.iAvatarOpacity / 100.0 * 255);
+ AlphaBlend(hdc, rcAvatar.left, rcAvatar.top, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, blend);
+ blend.SourceConstantAlpha = 255;
+
+ if (opt.bAvatarBorder) {
+ SaveAlpha(&rcAvatar);
+ HBRUSH hbrBorder = CreateSolidBrush(opt.colAvatarBorder);
+ if (opt.bAvatarRound)
+ FrameRgn(hdc, hrgnAvatar, hbrBorder, 1, 1);
+ else
+ FrameRect(hdc, &rcAvatar, hbrBorder);
+
+ DeleteObject(hbrBorder);
+ RestoreAlpha(&rcAvatar, (BYTE)(opt.iAvatarOpacity / 100.0 * 255));
+ }
+
+ if (hrgnAvatar) {
+ SelectClipRgn(hdc, 0);
+ DeleteObject(hrgnAvatar);
+ }
+
+ if (hbmpAvatar != ace->hbmPic)
+ DeleteObject(hbmpAvatar);
+
+ DeleteDC(hdcMem);
+ }
+ }
+ }
+
+ RECT tr;
+ tr.left = r2.left + opt.iPadding + opt.iTitleIndent;
+ tr.right = r2.right - opt.iPadding;
+ tr.top = 0;
+ tr.bottom = opt.iPadding;
+
+ if (!pwd->bIsTextTip) {
+ if (opt.titleIconLayout != PTL_NOICON) {
+ // draw icons
+ int iIconX, iIconY;
+ iIconY = opt.iPadding + opt.iTextPadding;
+
+ if (opt.titleIconLayout == PTL_RIGHTICON)
+ iIconX = r2.right - 16 - opt.iPadding;
+ else
+ iIconX = r2.left + opt.iPadding;
+
+ for (int i = 0; i < EXICONS_COUNT; i++) {
+ if (pwd->extraIcons[i].hIcon) {
+ DrawIconExAlpha(hdc, iIconX, iIconY, pwd->extraIcons[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false);
+ iIconY += 20;
+ }
+ }
+ }
+
+ // title text
+ if (opt.bShowTitle) {
+ if (hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle);
+ SetTextColor(hdc, opt.colTitle);
+ tr.top = opt.iPadding;
+ tr.bottom = tr.top + pwd->iTitleHeight - opt.iPadding;
+ UINT uTextFormat = DT_TOP | DT_LEFT | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX;
+ DrawTextExt(hdc, pwd->swzTitle, -1, &tr, uTextFormat, NULL, pwd->spiTitle);
+ }
+ }
+
+ // values
+ pwd->iTextHeight = 0;
+ bool bIconPainted, bUseRect = true;
+ int iRowHeight;
+ for (int i = 0; i < pwd->iRowCount; i++) {
+ tr.top = tr.bottom;
+ bUseRect = (tr.top + opt.iTextPadding >= pwd->iAvatarHeight);
+ bIconPainted = false;
+ if (bUseRect) {
+ if (pwd->rows[i].bLineAbove) {
+ HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenDivider);
+ tr.top += opt.iTextPadding;
+ RECT rec;
+ SetRect(&rec, r.left + opt.iPadding + pwd->iIndent, tr.top, r.right - opt.iPadding, tr.top + 1);
+ SaveAlpha(&rec);
+ Rectangle(hdc, rec.left, rec.top, rec.right, rec.bottom);
+ RestoreAlpha(&rec);
+ SelectObject(hdc, hOldPen);
+ }
+
+ tr.left = r.left + opt.iPadding + pwd->iIndent;
+ if (pwd->rows[i].bValueNewline)
+ tr.right = r.right - opt.iPadding;
+ else
+ tr.right = r.left + opt.iPadding + pwd->iIndent + pwd->iLabelWidth;
+ }
+ else {
+ if (pwd->rows[i].bLineAbove) {
+ HPEN hOldPen = (HPEN)SelectObject(hdc, pwd->hpenDivider);
+ tr.top += opt.iTextPadding;
+ RECT rec;
+ SetRect(&rec, r2.left + opt.iPadding + pwd->iIndent, tr.top, r2.right - opt.iPadding, tr.top + 1);
+ SaveAlpha(&rec);
+ Rectangle(hdc, rec.left, rec.top, rec.right, rec.bottom);
+ RestoreAlpha(&rec);
+ SelectObject(hdc, hOldPen);
+ }
+
+ tr.left = r2.left + opt.iPadding + pwd->iIndent;
+ if (pwd->rows[i].bValueNewline)
+ tr.right = r2.right - opt.iPadding;
+ else
+ tr.right = r2.left + opt.iPadding + pwd->iIndent + pwd->iLabelWidth;
+ }
+
+ if (pwd->rows[i].bValueNewline)
+ iRowHeight = pwd->rows[i].iLabelHeight;
+ else
+ iRowHeight = max(pwd->rows[i].iLabelHeight, pwd->rows[i].iValueHeight);
+
+ if (pwd->rows[i].iLabelHeight) {
+ tr.top += opt.iTextPadding;
+ tr.bottom = tr.top + iRowHeight;
+
+ if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) {
+ if (hFontTrayTitle) SelectObject(hdc, (HGDIOBJ)hFontTrayTitle);
+ SetTextColor(hdc, opt.colTrayTitle);
+ }
+ else {
+ if (hFontLabels) SelectObject(hdc, (HGDIOBJ)hFontLabels);
+ SetTextColor(hdc, opt.colLabel);
+ }
+
+ // status icon in tray tooltip
+ if (opt.titleIconLayout != PTL_NOICON && pwd->bIsTrayTip && pwd->rows[i].hIcon) {
+ DrawIconExAlpha(hdc, opt.iPadding, tr.top + (pwd->rows[i].iLabelHeight - 16) / 2, pwd->rows[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false);
+ bIconPainted = true;
+ }
+
+ DrawTextAlpha(hdc, pwd->rows[i].swzLabel, -1, &tr, opt.iLabelValign | ((opt.iLabelHalign == DT_RIGHT && !pwd->rows[i].bValueNewline) ? DT_RIGHT : DT_LEFT) | DT_END_ELLIPSIS | DT_SINGLELINE | DT_NOPREFIX);
+ if (pwd->rows[i].bValueNewline)
+ tr.top = tr.bottom;
+ }
+ else tr.bottom = tr.top;
+
+ if (pwd->rows[i].bValueNewline)
+ iRowHeight = pwd->rows[i].iValueHeight;
+
+ if (hFontValues)
+ SelectObject(hdc, (HGDIOBJ)hFontValues);
+ SetTextColor(hdc, opt.colValue);
+ if (bUseRect) {
+ tr.left = r.left + opt.iPadding + pwd->iIndent;
+ if (!pwd->rows[i].bValueNewline)
+ tr.left += pwd->iLabelWidth + opt.iValueIndent;
+
+ tr.right = r.right - opt.iPadding;
+ }
+ else {
+ tr.left = r2.left + opt.iPadding + pwd->iIndent;
+ if (!pwd->rows[i].bValueNewline)
+ tr.left += pwd->iLabelWidth + opt.iValueIndent;
+
+ tr.right = r2.right - opt.iPadding;
+ }
+
+ if (pwd->rows[i].iValueHeight) {
+ if (pwd->rows[i].bValueNewline || !pwd->rows[i].iLabelHeight) tr.top += opt.iTextPadding;
+ if (pwd->rows[i].iLabelHeight > pwd->rows[i].iValueHeight && pwd->bIsTextTip&& pwd->rows[i].bIsTitle)
+ tr.top = tr.bottom - pwd->rows[i].iValueHeight - 2;
+ else
+ tr.bottom = tr.top + iRowHeight;
+
+ if (opt.titleIconLayout != PTL_NOICON && pwd->bIsTrayTip && pwd->rows[i].hIcon && !bIconPainted)
+ DrawIconExAlpha(hdc, opt.iPadding, tr.top + (pwd->rows[i].iValueHeight - 16) / 2, pwd->rows[i].hIcon, 16, 16, 0, NULL, DI_NORMAL, false);
+
+ UINT uFormat = opt.iValueValign | opt.iValueHalign | DT_WORDBREAK | DT_WORD_ELLIPSIS | DT_END_ELLIPSIS | DT_NOPREFIX;
+ DrawTextExt(hdc, pwd->rows[i].swzValue, -1, &tr, uFormat, NULL, pwd->rows[i].spi);
+ }
+ }
+
+ PremultipleChannels();
+
+ if (opt.showEffect == PSE_NONE) {
+ if (skin.bNeedLayerUpdate) {
+ POINT ptSrc = { 0, 0 };
+ SIZE szTip = { r.right - r.left, r.bottom - r.top };
+ blend.SourceConstantAlpha = pwd->iTrans;
+ UpdateLayeredWindow(hwnd, NULL, NULL, &szTip, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
+
+ if (opt.bAeroGlass && MyDwmEnableBlurBehindWindow) {
+ DWM_BLURBEHIND bb = { 0 };
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.fEnable = TRUE;
+ bb.hRgnBlur = CreateOpaqueRgn(25, true);
+ MyDwmEnableBlurBehindWindow(hwnd, &bb);
+ }
+ }
+ else SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), pwd->iTrans, LWA_ALPHA);
+ }
+
+ SelectObject(hdc, hOldFont);
+ EndPaint(hwnd, &ps);
+ pwd->bIsPainted = true;
+ }
+ return 0;
+
+ case WM_HOTKEY:
+ if (LOWORD(lParam) == MOD_CONTROL && HIWORD(lParam) == 0x43) { // CTRL+C
+ if (pwd->iRowCount == 0)
+ return 0;
+
+ ShowWindow(hwnd, SW_HIDE);
+ HMENU hMenu = CreatePopupMenu();
+ if (!hMenu)
+ return 0;
+
+ HICON hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ITEM_ALL), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
+ if (!hIcon) {
+ DestroyMenu(hMenu);
+ return 0;
+ }
+
+ ICONINFO iconInfo;
+ GetIconInfo(hIcon, &iconInfo);
+ HBITMAP hbmpAllItems = iconInfo.hbmColor;
+ DestroyIcon(hIcon);
+
+ AppendMenu(hMenu, MF_STRING, COPYMENU_ALLITEMS_LABELS, LPGENT("Copy all items with labels"));
+ AppendMenu(hMenu, MF_STRING, COPYMENU_ALLITEMS, LPGENT("Copy all items"));
+ if (pwd->clcit.szProto || pwd->hContact)
+ AppendMenu(hMenu, MF_STRING, COPYMENU_AVATAR, LPGENT("Copy avatar"));
+ AppendMenu(hMenu, MF_SEPARATOR, 2000, 0);
+ TranslateMenu(hMenu);
+
+ SetMenuItemBitmaps(hMenu, COPYMENU_ALLITEMS_LABELS, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems);
+ SetMenuItemBitmaps(hMenu, COPYMENU_ALLITEMS, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems);
+ SetMenuItemBitmaps(hMenu, COPYMENU_AVATAR, MF_BYCOMMAND, hbmpAllItems, hbmpAllItems);
+
+ hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ITEM), IMAGE_ICON, 0, 0, LR_LOADTRANSPARENT);
+ if (!hIcon) {
+ DeleteObject(hbmpAllItems);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+
+ GetIconInfo(hIcon, &iconInfo);
+ HBITMAP hbmpItem = iconInfo.hbmColor;
+ DestroyIcon(hIcon);
+
+ for (int i = 0; i < pwd->iRowCount; i++) {
+ if (pwd->rows[i].swzValue) {
+ TCHAR buff[128];
+ int iLen = (int)_tcslen(pwd->rows[i].swzValue);
+ if (iLen) {
+ if (iLen > MAX_VALUE_LEN) {
+ _tcsncpy(buff, pwd->rows[i].swzValue, MAX_VALUE_LEN);
+ buff[MAX_VALUE_LEN] = 0;
+ _tcscat(buff, _T("..."));
+ }
+ else _tcscpy(buff, pwd->rows[i].swzValue);
+
+ AppendMenu(hMenu, MF_STRING, i + 1, buff); // first id = 1, because no select have id = 0
+ SetMenuItemBitmaps(hMenu, i + 1, MF_BYCOMMAND, hbmpItem, hbmpItem);
+ }
+ else AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
+ }
+ }
+
+ POINT pt;
+ GetCursorPos(&pt);
+ SetForegroundWindow(hwnd);
+ int iSelItem = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, 0);
+ DeleteObject(hbmpAllItems);
+ DeleteObject(hbmpItem);
+ DestroyMenu(hMenu);
+
+ if (iSelItem == 0)
+ return 0; // no item was selected
+
+ if (OpenClipboard(NULL)) {
+ EmptyClipboard();
+ if (iSelItem == COPYMENU_AVATAR) { // copy avatar
+ AVATARCACHEENTRY *ace = 0;
+ if (pwd->hContact)
+ ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, pwd->hContact, 0);
+ else
+ ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto);
+ if (ace && ace->hbmPic && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
+ HDC hdc = GetDC(hwnd);
+ HDC hdcSrc = CreateCompatibleDC(hdc);
+ HDC hdcDes = CreateCompatibleDC(hdc);
+ HBITMAP hbmAvr = CreateCompatibleBitmap(hdc, ace->bmWidth, ace->bmHeight);
+ SelectObject(hdcSrc, ace->hbmPic);
+ SelectObject(hdcDes, hbmAvr);
+ BitBlt(hdcDes, 0, 0, ace->bmWidth, ace->bmHeight, hdcSrc, 0, 0, SRCCOPY);
+ SetClipboardData(CF_BITMAP, hbmAvr);
+ ReleaseDC(hwnd, hdc);
+ DeleteDC(hdcSrc);
+ DeleteDC(hdcDes);
+ }
+ }
+ else { // copy text
+ HGLOBAL hClipboardData = GlobalAlloc(GMEM_DDESHARE, 4096);
+ TCHAR *pchData = (TCHAR *)GlobalLock(hClipboardData);
+ pchData[0] = 0;
+ if (iSelItem == COPYMENU_ALLITEMS_LABELS) { // copy all items with labels
+ for (int i = 0; i < pwd->iRowCount; i++) {
+ if ((pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) || (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0])) {
+ if (pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0]) {
+ _tcscat(pchData, pwd->rows[i].swzLabel);
+ _tcscat(pchData, _T(" "));
+ }
+ else _tcscat(pchData, TranslateT("<No Label>: "));
+
+ if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0])
+ _tcscat(pchData, pwd->rows[i].swzValue);
+ else
+ _tcscat(pchData, TranslateT("<No Value>"));
+
+ _tcscat(pchData, _T("\r\n"));
+ }
+ }
+ }
+ else if (iSelItem == COPYMENU_ALLITEMS) { // copy all items
+ for (int i = 0; i < pwd->iRowCount; i++) {
+ if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) {
+ _tcscat(pchData, pwd->rows[i].swzValue);
+ _tcscat(pchData, _T("\r\n"));
+ }
+ }
+ }
+ // single row
+ else _tcscpy(pchData, pwd->rows[iSelItem - 1].swzValue);
+
+ GlobalUnlock(hClipboardData);
+ SetClipboardData(CF_UNICODETEXT, hClipboardData);
+ }
+
+ CloseClipboard();
+ }
+ }
+ break;
+
+ case PUM_FADEOUTWINDOW:
+ // kill timers
+ KillTimer(hwnd, ID_TIMER_ANIMATE);
+ KillTimer(hwnd, ID_TIMER_CHECKMOUSE);
+ KillTimer(hwnd, ID_TIMER_TRAYTIP);
+
+ if (opt.showEffect != PSE_NONE) {
+ if (skin.bNeedLayerUpdate) {
+ POINT ptSrc = { 0, 0 };
+ SIZE sz = { pwd->rcWindow.right - pwd->rcWindow.left, pwd->rcWindow.bottom - pwd->rcWindow.top };
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = pwd->iTrans;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ while (blend.SourceConstantAlpha != 0) {
+ UpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
+ blend.SourceConstantAlpha = max(blend.SourceConstantAlpha - opt.iAnimateSpeed, 0);
+ Sleep(ANIM_ELAPSE);
+ }
+ }
+ else {
+ int iTrans = pwd->iTrans;
+ while (iTrans != 0) {
+ SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), iTrans, LWA_ALPHA);
+ iTrans = max(iTrans - opt.iAnimateSpeed, 0);
+ Sleep(ANIM_ELAPSE);
+ }
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ ShowWindow(hwnd, SW_HIDE);
+
+ mir_free(skin.colSavedBits);
+ if (skin.hBitmap)
+ DeleteObject(skin.hBitmap);
+ if (skin.hdc)
+ DeleteDC(skin.hdc);
+ skin.colSavedBits = NULL;
+ skin.hBitmap = NULL;
+ skin.hdc = NULL;
+
+ if (pwd == NULL)
+ break;
+ // unregister hotkey
+ UnregisterHotKey(hwnd, pwd->iHotkeyId);
+
+ DeleteObject(pwd->hpenBorder);
+ DeleteObject(pwd->hpenDivider);
+
+ if (pwd->hrgnAeroGlass)
+ DeleteObject(pwd->hrgnAeroGlass);
+
+ Smileys_FreeParse(pwd->spiTitle);
+
+ for (int i = 0; i < pwd->iRowCount && pwd->rows != NULL; i++) {
+ mir_free(pwd->rows[i].swzLabel);
+ mir_free(pwd->rows[i].swzValue);
+ Smileys_FreeParse(pwd->rows[i].spi);
+ }
+ mir_free(pwd->rows);
+
+ // destroy icons
+ for (int i = 0; i < EXICONS_COUNT; i++) {
+ if (pwd->extraIcons[i].hIcon == NULL)
+ continue;
+
+ if (pwd->extraIcons[i].bDestroy)
+ DestroyIcon(pwd->extraIcons[i].hIcon);
+ else
+ Skin_ReleaseIcon(pwd->extraIcons[i].hIcon);
+ }
+
+ mir_free(pwd->clcit.swzText);
+ mir_free(pwd);
+ pwd = NULL;
+
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ break;
+
+ case WM_TIMER:
+ switch (wParam) {
+ case ID_TIMER_ANIMATE:
+ pwd->iAnimStep ++;
+ if (pwd->iAnimStep == ANIM_STEPS)
+ KillTimer(hwnd, ID_TIMER_ANIMATE);
+
+ SendMessage(hwnd, PUM_UPDATERGN, 1, 0);
+ break;
+ case ID_TIMER_CHECKMOUSE:
+ {
+ // workaround for tips that just won't go away
+ POINT pt;
+
+ GetCursorPos(&pt);
+ // mouse has moved beyond tollerance
+ if (abs(pt.x - pwd->ptCursorStartPos.x) > opt.iMouseTollerance || abs(pt.y - pwd->ptCursorStartPos.y) > opt.iMouseTollerance)
+ PostMPMessage(MUM_DELETEPOPUP, 0, 0);
+ }
+ break;
+ case ID_TIMER_TRAYTIP:
+ KillTimer(hwnd, ID_TIMER_TRAYTIP);
+ SendMessage(hwnd, PUM_EXPANDTRAYTIP, 0, 0);
+ break;
+ }
+ break;
+
+ case PUM_SETSTATUSTEXT:
+ if (pwd && wParam == pwd->hContact) {
+ db_set_ts(pwd->hContact, MODULE, "TempStatusMsg", (TCHAR *)lParam);
+ pwd->bIsPainted = false;
+ pwd->bNeedRefresh = true;
+ SendMessage(hwnd, PUM_REFRESH_VALUES, TRUE, 0);
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+ mir_free((void *)lParam);
+ return TRUE;
+
+ case PUM_SHOWXSTATUS:
+ if (pwd && wParam == pwd->hContact) {
+ // in case we have retrieve xstatus
+ pwd->bIsPainted = false;
+ SendMessage(hwnd, PUM_REFRESH_VALUES, TRUE, 0);
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+ return TRUE;
+
+ case PUM_SETAVATAR:
+ if (pwd && wParam == pwd->hContact) {
+ pwd->bIsPainted = false;
+ SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
+ SendMessage(hwnd, PUM_CALCPOS, 0, 0);
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+ return TRUE;
+
+ case PUM_EXPANDTRAYTIP:
+ pwd->bIsPainted = false;
+ if (skin.bNeedLayerUpdate) {
+ RECT r = pwd->rcWindow;
+ POINT ptSrc = {0, 0};
+ SIZE sz = {r.right - r.left, r.bottom - r.top};
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = 0;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ UpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
+ }
+ else SetLayeredWindowAttributes(hwnd, RGB(0,0,0), 0, LWA_ALPHA);
+
+ SendMessage(hwnd, PUM_REFRESHTRAYTIP, 1, 0);
+ SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
+ SendMessage(hwnd, PUM_CALCPOS, 0, 0);
+ InvalidateRect(hwnd, 0, TRUE);
+
+ if (opt.showEffect) {
+ KillTimer(hwnd, ID_TIMER_ANIMATE);
+ SetTimer(hwnd, ID_TIMER_ANIMATE, ANIM_ELAPSE, 0);
+ pwd->iAnimStep = 0;
+ pwd->iCurrentTrans = 0;
+ }
+ return TRUE;
+
+ case PUM_REFRESH_VALUES:
+ if (pwd && pwd->clcit.szProto == 0 && !pwd->bIsTextTip) {
+ for (int i = 0; i < pwd->iRowCount; i++) {
+ mir_free(pwd->rows[i].swzLabel);
+ mir_free(pwd->rows[i].swzValue);
+ Smileys_FreeParse(pwd->rows[i].spi);
+ }
+
+ mir_free(pwd->rows);
+ pwd->rows = NULL;
+ pwd->iRowCount = 0;
+
+ DIListNode *node = opt.diList;
+ TCHAR buff_label[LABEL_LEN], buff[VALUE_LEN];
+ while (node) {
+ if (node->di.bIsVisible && CheckContactType(pwd->hContact, node->di)) {
+ if (GetLabelText(pwd->hContact, node->di, buff_label, LABEL_LEN) && GetValueText(pwd->hContact, node->di, buff, VALUE_LEN)) {
+ if (node->di.bLineAbove // we have a line above
+ && pwd->iRowCount > 0 // and we're not the first row
+ && pwd->rows[pwd->iRowCount - 1].bLineAbove // and above us there's a line above
+ && pwd->rows[pwd->iRowCount - 1].swzLabel[0] == 0 // with no label
+ && pwd->rows[pwd->iRowCount - 1].swzValue[0] == 0) // and no value
+ {
+ // overwrite item above
+ pwd->iRowCount--;
+ mir_free(pwd->rows[pwd->iRowCount].swzLabel);
+ mir_free(pwd->rows[pwd->iRowCount].swzValue);
+ Smileys_FreeParse(pwd->rows[pwd->iRowCount].spi); //prevent possible mem leak
+ }
+ else pwd->rows = (RowData *)mir_realloc(pwd->rows, sizeof(RowData)* (pwd->iRowCount + 1));
+
+ char *szProto = GetContactProto(pwd->hContact);
+
+ pwd->rows[pwd->iRowCount].swzLabel = mir_tstrdup(buff_label);
+ pwd->rows[pwd->iRowCount].swzValue = mir_tstrdup(buff);
+ pwd->rows[pwd->iRowCount].spi = Smileys_PreParse(buff, (int)_tcslen(buff), szProto);
+ pwd->rows[pwd->iRowCount].bValueNewline = node->di.bValueNewline;
+ pwd->rows[pwd->iRowCount].bLineAbove = node->di.bLineAbove;
+ pwd->iRowCount++;
+ }
+ }
+ node = node->next;
+ }
+
+ // if the last item is just a divider, remove it
+ if (pwd->iRowCount > 0
+ && pwd->rows[pwd->iRowCount - 1].bLineAbove // and above us there's a line above
+ && pwd->rows[pwd->iRowCount - 1].swzLabel[0] == 0 // with no label
+ && pwd->rows[pwd->iRowCount - 1].swzValue[0] == 0) // and no value
+ {
+ pwd->iRowCount--;
+ mir_free(pwd->rows[pwd->iRowCount].swzLabel);
+ mir_free(pwd->rows[pwd->iRowCount].swzValue);
+ Smileys_FreeParse(pwd->rows[pwd->iRowCount].spi); //prevent possible mem leak
+
+ if (pwd->iRowCount == 0) {
+ mir_free(pwd->rows);
+ pwd->rows = NULL;
+ }
+ }
+
+ if (wParam == TRUE) {
+ SendMessage(hwnd, PUM_GETHEIGHT, 0, 0);
+ SendMessage(hwnd, PUM_CALCPOS, 0, 0);
+ }
+ }
+ return TRUE;
+
+ case PUM_GETHEIGHT:
+ {
+ int *pHeight = (int *)wParam;
+ HDC hdc = GetDC(hwnd);
+ SIZE sz;
+ RECT rc, smr;
+ rc.top = rc.left = 0;
+ rc.right = opt.iWinWidth;
+ int iWidth = opt.iPadding;
+ int iWinAvatarHeight = 0;
+ bool bStatusMsg = false;
+ HFONT hOldFont = (HFONT)GetCurrentObject(hdc,OBJ_FONT);
+
+ // avatar height
+ pwd->iAvatarHeight = 0;
+ if (!pwd->bIsTextTip && opt.avatarLayout != PAV_NONE && ServiceExists(MS_AV_GETAVATARBITMAP)) {
+ AVATARCACHEENTRY *ace = 0;
+ if (pwd->hContact) ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETAVATARBITMAP, (WPARAM)pwd->hContact, 0);
+ else ace = (AVATARCACHEENTRY *)CallService(MS_AV_GETMYAVATAR, 0, (LPARAM)pwd->clcit.szProto);
+
+ if (ace && (ace->dwFlags & AVS_BITMAP_VALID) && !(ace->dwFlags & AVS_HIDEONCLIST)) {
+ if (opt.bOriginalAvatarSize && max(ace->bmWidth, ace->bmHeight) <= opt.iAvatarSize) {
+ pwd->iRealAvatarHeight = ace->bmHeight;
+ pwd->iRealAvatarWidth = ace->bmWidth;
+ }
+ else if (ace->bmHeight >= ace->bmWidth) {
+ pwd->iRealAvatarHeight = opt.iAvatarSize;
+ pwd->iRealAvatarWidth = (int)(opt.iAvatarSize * (ace->bmWidth / (double)ace->bmHeight));
+ }
+ else {
+ pwd->iRealAvatarHeight = (int)(opt.iAvatarSize * (ace->bmHeight / (double)ace->bmWidth));
+ pwd->iRealAvatarWidth = opt.iAvatarSize;
+ }
+
+ pwd->iAvatarHeight = opt.iOuterAvatarPadding + opt.iInnerAvatarPadding + pwd->iRealAvatarHeight;
+ iWinAvatarHeight = 2 * opt.iOuterAvatarPadding + pwd->iRealAvatarHeight;
+ iWidth += pwd->iRealAvatarWidth + (opt.iOuterAvatarPadding + opt.iInnerAvatarPadding - opt.iPadding);
+ }
+ }
+
+ // titlebar height
+ if (!pwd->bIsTextTip && pwd->swzTitle && opt.bShowTitle) {
+ smr.top = smr.bottom = 0;
+ smr.left = rc.left + opt.iPadding + pwd->iIndent;
+ smr.right = rc.right;
+
+ if (pwd->iRealAvatarWidth > 0)
+ smr.right -= pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding;
+ else
+ smr.right -= opt.iPadding;
+
+ if (hFontTitle) SelectObject(hdc, (HGDIOBJ)hFontTitle);
+ DrawTextExt(hdc, pwd->swzTitle, -1, &smr, DT_CALCRECT | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, NULL, pwd->spiTitle);
+
+ iWidth += opt.iPadding + opt.iTitleIndent + smr.right;
+ pwd->iTitleHeight = opt.iPadding + smr.bottom;
+ }
+ else pwd->iTitleHeight = opt.iPadding;
+
+ // icon height
+ int i, iCount = 0;
+ if (pwd->hContact || pwd->clcit.szProto) {
+ for(i = 0; i < EXICONS_COUNT; i++) {
+ if ((INT_PTR)pwd->extraIcons[i].hIcon == CALLSERVICE_NOTFOUND)
+ pwd->extraIcons[i].hIcon = 0;
+
+ if (pwd->extraIcons[i].hIcon)
+ iCount++;
+ }
+ }
+ pwd->iIconsHeight = (iCount * 20) + 20;
+
+ // text height
+ pwd->iTextHeight = pwd->iLabelWidth = 0;
+ // iterate once to find max label width for items with label and value on same line, but don't consider width of labels on a new line
+ for (i = 0; i < pwd->iRowCount; i++) {
+ if (pwd->rows[i].swzLabel && !pwd->rows[i].bValueNewline) {
+ if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) {
+ if (hFontTrayTitle)
+ SelectObject(hdc, (HGDIOBJ)hFontTrayTitle);
+ }
+ else if (hFontLabels)
+ SelectObject(hdc, (HGDIOBJ)hFontLabels);
+
+ GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, (int)_tcslen(pwd->rows[i].swzLabel), &sz);
+ if (sz.cx > pwd->iLabelWidth)
+ pwd->iLabelWidth = sz.cx;
+ }
+ }
+
+ for (i = 0; i < pwd->iRowCount; i++) {
+ if (pwd->bIsTrayTip && pwd->rows[i].bIsTitle) {
+ if (hFontTrayTitle)
+ SelectObject(hdc, (HGDIOBJ)hFontTrayTitle);
+ }
+ else if (hFontLabels)
+ SelectObject(hdc, (HGDIOBJ)hFontLabels);
+
+ if (pwd->rows[i].swzLabel && pwd->rows[i].swzLabel[0])
+ GetTextExtentPoint32(hdc, pwd->rows[i].swzLabel, (int)_tcslen(pwd->rows[i].swzLabel), &sz);
+ else
+ sz.cy = sz.cx = 0;
+
+ // save so we don't have to recalculate
+ pwd->rows[i].iLabelHeight = sz.cy;
+
+ smr.top = smr.bottom = 0;
+ smr.left = rc.left + opt.iPadding + pwd->iIndent;
+ smr.right = rc.right;
+ if (hFontValues) SelectObject(hdc, (HGDIOBJ)hFontValues);
+ if (pwd->iTitleHeight + pwd->iTextHeight + opt.iTextPadding < pwd->iAvatarHeight)
+ smr.right -= pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding;
+ else
+ smr.right -= opt.iPadding;
+
+ if (!pwd->rows[i].bValueNewline)
+ smr.right -= pwd->iLabelWidth + opt.iValueIndent;
+
+ if (pwd->rows[i].swzValue && pwd->rows[i].swzValue[0]) {
+ if (!bStatusMsg && opt.bGetNewStatusMsg) {
+ if (!_tcscmp(pwd->rows[i].swzValue, _T("%sys:status_msg%")))
+ bStatusMsg = true;
+ }
+
+ DrawTextExt(hdc, pwd->rows[i].swzValue, -1, &smr, DT_CALCRECT | DT_LEFT | DT_WORDBREAK | DT_END_ELLIPSIS | DT_NOPREFIX, NULL, pwd->rows[i].spi);
+ }
+ else smr.left = smr.right = 0;
+
+ // save so we don't have to recalculate
+ pwd->rows[i].iValueHeight = smr.bottom;
+
+ pwd->rows[i].iTotalHeight = (pwd->rows[i].bLineAbove ? opt.iTextPadding : 0);
+ if (pwd->rows[i].bValueNewline) {
+ if (sz.cy) pwd->rows[i].iTotalHeight += sz.cy + opt.iTextPadding;
+ if (smr.bottom) pwd->rows[i].iTotalHeight += smr.bottom + opt.iTextPadding;
+ }
+ else {
+ int maxheight = max(sz.cy, smr.bottom);
+ if (maxheight) pwd->rows[i].iTotalHeight += maxheight + opt.iTextPadding;
+ }
+
+ // only consider this item's width, and include it's height, if it doesn't make the window too big
+ if (max(pwd->iTitleHeight + pwd->iTextHeight + opt.iPadding + pwd->rows[i].iTotalHeight, pwd->iAvatarHeight) <= opt.iWinMaxHeight || pwd->bIsTrayTip) {
+ if (iWidth < opt.iWinWidth) {
+ int wid = opt.iPadding + pwd->iIndent + (pwd->rows[i].bValueNewline ? max(sz.cx, smr.right - smr.left) : pwd->iLabelWidth + opt.iValueIndent + (smr.right - smr.left));
+ if (pwd->iTitleHeight + pwd->iTextHeight + opt.iTextPadding < pwd->iAvatarHeight)
+ iWidth = max(iWidth, wid + pwd->iRealAvatarWidth + opt.iOuterAvatarPadding + opt.iInnerAvatarPadding);
+ else
+ iWidth = max(iWidth, wid + opt.iPadding);
+ }
+
+ pwd->iTextHeight += pwd->rows[i].iTotalHeight;
+ }
+ }
+
+ SelectObject(hdc, hOldFont);
+ ReleaseDC(hwnd, hdc);
+
+ int iHeight = max(pwd->iTitleHeight + pwd->iTextHeight + opt.iPadding, iWinAvatarHeight);
+ iHeight = max(pwd->iIconsHeight, iHeight);
+ if (bStatusMsg) iHeight += 50;
+
+ if (iHeight < opt.iMinHeight) iHeight = opt.iMinHeight;
+ // ignore minwidth for text tips
+ if (!pwd->bIsTextTip && iWidth < opt.iMinWidth) iWidth = opt.iMinWidth;
+
+ // ignore maxheight for tray tip
+ if (!pwd->bIsTrayTip && iHeight > opt.iWinMaxHeight) iHeight = opt.iWinMaxHeight;
+ if (iWidth > opt.iWinWidth) iWidth = opt.iWinWidth;
+
+ CreateSkinBitmap(iWidth, iHeight, pwd->bIsTextTip && !pwd->bIsTrayTip);
+
+ GetWindowRect(hwnd, &rc);
+ if (rc.right - rc.left != iWidth || rc.bottom - rc.top != iHeight)
+ {
+ SetWindowPos(hwnd, 0, 0, 0, iWidth, iHeight, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
+ GetWindowRect(hwnd, &pwd->rcWindow);
+ SendMessage(hwnd, PUM_UPDATERGN, 0, 0);
+ InvalidateRect(hwnd, 0, TRUE);
+ }
+
+ if (pHeight)
+ *pHeight = iHeight;
+ }
+ return TRUE;
+
+ case PUM_UPDATERGN:
+ {
+ HRGN hRgn;
+ RECT r = pwd->rcWindow;
+ int v, h;
+ int w = 11;
+
+ r.right -= r.left;
+ r.left = 0;
+ r.bottom -= r.top;
+ r.top = 0;
+
+ if (opt.showEffect == PSE_FADE && wParam == 1) {
+ if (skin.bNeedLayerUpdate) {
+ POINT ptSrc = { 0, 0 };
+ SIZE sz = { r.right - r.left, r.bottom - r.top };
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = pwd->iCurrentTrans;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ pwd->iCurrentTrans += opt.iAnimateSpeed;
+ if (pwd->iCurrentTrans > pwd->iTrans) {
+ pwd->iCurrentTrans = pwd->iTrans;
+ pwd->iAnimStep = ANIM_STEPS;
+ }
+
+ UpdateLayeredWindow(hwnd, NULL, NULL, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
+
+ }
+ else {
+ pwd->iCurrentTrans += opt.iAnimateSpeed;
+ if (pwd->iCurrentTrans > pwd->iTrans) {
+ pwd->iCurrentTrans = pwd->iTrans;
+ pwd->iAnimStep = ANIM_STEPS;
+ }
+
+ SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), pwd->iCurrentTrans, LWA_ALPHA);
+ }
+ }
+ else if (opt.showEffect == PSE_ANIMATE && pwd->bIsPainted) {
+ if (pwd->iAnimStep <= (ANIM_STEPS / opt.iAnimateSpeed)) {
+ float frac = 1.0f - pwd->iAnimStep / ((float)ANIM_STEPS / opt.iAnimateSpeed);
+ int wi = r.right, hi = r.bottom;
+
+ r.left += (int)(wi / 2.0f * frac + 0.5f);
+ r.right -= (int)(wi / 2.0f * frac + 0.5f);
+ r.top += (int)(hi / 2.0f * frac + 0.5f);
+ r.bottom -= (int)(hi / 2.0f * frac + 0.5f);
+ }
+ else pwd->iAnimStep = ANIM_STEPS;
+
+ if (skin.bNeedLayerUpdate) {
+ RECT r2 = pwd->rcWindow;
+ POINT ptPos = { r.left + r2.left, r.top + r2.top };
+ POINT ptSrc = { r.left, r.top };
+
+ SIZE sz = { r.right - r.left, r.bottom - r.top };
+
+ BLENDFUNCTION blend;
+ blend.BlendOp = AC_SRC_OVER;
+ blend.BlendFlags = 0;
+ blend.SourceConstantAlpha = pwd->iTrans;
+ blend.AlphaFormat = AC_SRC_ALPHA;
+
+ UpdateLayeredWindow(hwnd, NULL, &ptPos, &sz, skin.hdc, &ptSrc, 0xffffffff, &blend, LWA_ALPHA);
+ }
+ }
+
+ if (!skin.bNeedLayerUpdate) {
+ // round corners
+ if (opt.bRound) {
+ h = (r.right - r.left) > (w * 2) ? w : (r.right - r.left);
+ v = (r.bottom - r.top) > (w * 2) ? w : (r.bottom - r.top);
+ h = (h < v) ? h : v;
+ }
+ else h = 0;
+
+ hRgn = CreateRoundRectRgn(r.left, r.top, r.right + 1, r.bottom + 1, h, h);
+ SetWindowRgn(hwnd, hRgn, FALSE);
+
+ if (opt.showEffect == PSE_ANIMATE && pwd->iAnimStep == 1)
+ SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), pwd->iTrans, LWA_ALPHA);
+ }
+ else {
+ // aero glass (vista+)
+ if (opt.bAeroGlass && MyDwmEnableBlurBehindWindow && pwd->iAnimStep > 5) {
+ if (pwd->hrgnAeroGlass) {
+ DeleteObject(pwd->hrgnAeroGlass);
+ pwd->hrgnAeroGlass = 0;
+ }
+
+ pwd->hrgnAeroGlass = CreateOpaqueRgn(25, true);
+
+ if (pwd->hrgnAeroGlass) {
+ DWM_BLURBEHIND bb = { 0 };
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.fEnable = TRUE;
+ bb.hRgnBlur = pwd->hrgnAeroGlass;
+ MyDwmEnableBlurBehindWindow(hwnd, &bb);
+ }
+ }
+ }
+ }
+ return TRUE;
+
+ case PUM_CALCPOS:
+ {
+ RECT rcWork, rc;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, FALSE);
+
+ HMONITOR hMon = MonitorFromPoint(pwd->clcit.ptCursor, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ if (GetMonitorInfo(hMon, &mi))
+ rcWork = mi.rcWork;
+
+ GetWindowRect(hwnd, &rc);
+
+ int x = 0, y = 0, iWidth = (rc.right - rc.left), iHeight = (rc.bottom - rc.top);
+
+ switch (opt.pos) {
+ case PP_BOTTOMRIGHT:
+ x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON); // cursor size is too large - use small icon size
+ y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON);
+ break;
+ case PP_BOTTOMLEFT:
+ x = pwd->clcit.ptCursor.x - iWidth - GetSystemMetrics(SM_CXSMICON);
+ y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON);
+ break;
+ case PP_TOPRIGHT:
+ x = pwd->clcit.ptCursor.x + GetSystemMetrics(SM_CXSMICON);
+ y = pwd->clcit.ptCursor.y - iHeight - GetSystemMetrics(SM_CYSMICON);
+ break;
+ case PP_TOPLEFT:
+ x = pwd->clcit.ptCursor.x - iWidth - GetSystemMetrics(SM_CXSMICON);
+ y = pwd->clcit.ptCursor.y - iHeight - GetSystemMetrics(SM_CYSMICON);
+ break;
+ }
+
+
+ if (x + iWidth + 8 > rcWork.right)
+ x = rcWork.right - iWidth - 8;
+ if (x - 8 < rcWork.left)
+ x = rcWork.left + 8;
+
+ if (pwd->bAllowReposition || !pwd->bNeedRefresh) {
+ if (y + iHeight > rcWork.bottom) {
+ y = pwd->clcit.ptCursor.y - iHeight - 8;
+ pwd->bAllowReposition = true;
+ }
+
+ if (y - 8 < rcWork.top) {
+ y = pwd->clcit.ptCursor.y + GetSystemMetrics(SM_CYSMICON);
+ pwd->bAllowReposition = true;
+ }
+ }
+
+ SetWindowPos(hwnd, 0, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+ GetWindowRect(hwnd, &pwd->rcWindow);
+ }
+ return TRUE;
+
+ case PUM_REFRESHTRAYTIP:
+ for (int i = 0; i < pwd->iRowCount; i++) {
+ mir_free(pwd->rows[i].swzLabel);
+ mir_free(pwd->rows[i].swzValue);
+ Smileys_FreeParse(pwd->rows[i].spi);
+ }
+
+
+ mir_free(pwd->rows);
+ pwd->rows = NULL;
+ pwd->iRowCount = 0;
+
+ DWORD dwItems = (wParam == 0) ? opt.iFirstItems : opt.iSecondItems;
+ bool bFirstItem = true;
+ TCHAR buff[64];
+
+ int oldOrder = -1, iProtoCount = 0;
+ PROTOACCOUNT **accs;
+ ProtoEnumAccounts(&iProtoCount, &accs);
+
+ for (int j = 0; j < iProtoCount; j++) {
+ PROTOACCOUNT *pa = NULL;
+ for (int i = 0; i < iProtoCount; i++)
+ if (accs[i]->iOrder > oldOrder && (pa == NULL || accs[i]->iOrder < pa->iOrder))
+ pa = accs[i];
+
+ if (pa == NULL)
+ continue;
+
+ oldOrder = pa->iOrder;
+
+ WORD wStatus = CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0);
+ if (opt.bHideOffline && wStatus == ID_STATUS_OFFLINE)
+ continue;
+
+ if (!IsAccountEnabled(pa) || !IsTrayProto(pa->tszAccountName, (BOOL)wParam))
+ continue;
+
+ if (dwItems & TRAYTIP_NUMCONTACTS) {
+ int iCount = 0, iCountOnline = 0;
+ for (MCONTACT hContact = db_find_first(pa->szModuleName); hContact; hContact = db_find_next(hContact, pa->szModuleName)) {
+ if (db_get_w(hContact, pa->szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE)
+ iCountOnline++;
+ iCount++;
+ }
+ mir_sntprintf(buff, 64, _T("(%d/%d)"), iCountOnline, iCount);
+ }
+ else buff[0] = 0;
+
+ TCHAR swzProto[256];
+ _tcscpy(swzProto, pa->tszAccountName);
+ if (dwItems & TRAYTIP_LOCKSTATUS)
+ if (CallService(MS_PROTO_ISACCOUNTLOCKED, 0, (LPARAM)pa->szModuleName))
+ mir_sntprintf(swzProto, SIZEOF(swzProto), TranslateT("%s (locked)"), pa->tszAccountName);
+
+ AddRow(pwd, swzProto, buff, NULL, false, false, !bFirstItem, true, LoadSkinnedProtoIcon(pa->szModuleName, wStatus));
+ bFirstItem = false;
+
+ if (dwItems & TRAYTIP_LOGON) {
+ if (TimestampToTimeDifference(NULL, pa->szModuleName, "LogonTS", buff, 59)) {
+ TCHAR ago[96];
+ mir_sntprintf(ago, SIZEOF(ago), TranslateT("%s ago"), buff);
+ AddRow(pwd, TranslateT("Log on:"), ago, NULL, false, false, false);
+ }
+ }
+
+ if (dwItems & TRAYTIP_UNREAD_EMAILS && ProtoServiceExists(pa->szModuleName, PS_GETUNREADEMAILCOUNT)) {
+ int iCount = (int)ProtoCallService(pa->szModuleName, PS_GETUNREADEMAILCOUNT, 0, 0);
+ if (iCount > 0) {
+ _itot(iCount, buff, 10);
+ AddRow(pwd, TranslateT("Unread emails:"), buff, NULL, false, false, false);
+ }
+ }
+
+ if (dwItems & TRAYTIP_STATUS) {
+ TCHAR *swzText = pcli->pfnGetStatusModeDescription(wStatus, 0);
+ if (swzText)
+ AddRow(pwd, TranslateT("Status:"), swzText, NULL, false, false, false);
+ }
+
+ if (wStatus >= ID_STATUS_ONLINE && wStatus <= ID_STATUS_OUTTOLUNCH) {
+ if (dwItems & TRAYTIP_STATUS_MSG) {
+ TCHAR *swzText = GetProtoStatusMessage(pa->szModuleName, wStatus);
+ if (swzText) {
+ StripBBCodesInPlace(swzText);
+ AddRow(pwd, TranslateT("Status message:"), swzText, pa->szModuleName, true, true, false);
+ mir_free(swzText);
+ }
+ }
+
+ if (dwItems & TRAYTIP_EXTRA_STATUS) {
+ // jabber mood or icq xstatus
+ TCHAR *swzAdvTitle = GetJabberAdvStatusText(pa->szModuleName, "mood", "title");
+ if (swzAdvTitle) {
+ StripBBCodesInPlace(swzAdvTitle);
+ AddRow(pwd, TranslateT("Mood:"), swzAdvTitle, pa->szModuleName, true, false, false);
+ mir_free(swzAdvTitle);
+
+ TCHAR *swzAdvText = GetJabberAdvStatusText(pa->szModuleName, "mood", "text");
+ if (swzAdvText) {
+ StripBBCodesInPlace(swzAdvText);
+ AddRow(pwd, _T(""), swzAdvText, pa->szModuleName, true, true, false);
+ mir_free(swzAdvText);
+ }
+ }
+ else {
+ if (db_get_b(0, pa->szModuleName, "XStatusId", 0)) {
+ // xstatus title
+ swzAdvTitle = GetProtoExtraStatusTitle(pa->szModuleName);
+ if (swzAdvTitle) {
+ StripBBCodesInPlace(swzAdvTitle);
+ AddRow(pwd, TranslateT("xStatus:"), swzAdvTitle, pa->szModuleName, true, false, false);
+ mir_free(swzAdvTitle);
+ }
+
+ // xstatus message
+ TCHAR *swzAdvText = GetProtoExtraStatusMessage(pa->szModuleName);
+ if (swzAdvText) {
+ StripBBCodesInPlace(swzAdvText);
+ AddRow(pwd, _T(""), swzAdvText, pa->szModuleName, true, true, false);
+ mir_free(swzAdvText);
+ }
+ }
+ }
+
+ TCHAR *swzActTitle = GetJabberAdvStatusText(pa->szModuleName, "activity", "title");
+ if (swzActTitle) {
+ StripBBCodesInPlace(swzActTitle);
+ AddRow(pwd, TranslateT("Activity:"), swzActTitle, pa->szModuleName, true, false, false);
+ mir_free(swzActTitle);
+ }
+
+ TCHAR *swzActText = GetJabberAdvStatusText(pa->szModuleName, "activity", "text");
+ if (swzActText) {
+ StripBBCodesInPlace(swzActText);
+ AddRow(pwd, _T(""), swzActText, pa->szModuleName, true, true, false);
+ mir_free(swzActText);
+ }
+ }
+
+ if (dwItems & TRAYTIP_LISTENINGTO) {
+ TCHAR *swzListening = GetListeningTo(pa->szModuleName);
+ if (swzListening) {
+ StripBBCodesInPlace(swzListening);
+ AddRow(pwd, TranslateT("Listening to:"), swzListening, NULL, false, true, false);
+ mir_free(swzListening);
+ }
+ }
+ }
+ }
+
+ if (dwItems & TRAYTIP_FAVCONTACTS) {
+ if (db_get_dw(0, MODULE, "FavouriteContactsCount", 0)) {
+ TCHAR swzName[256];
+ TCHAR swzStatus[256];
+ bool bTitlePainted = false;
+ int iCount = 0, iCountOnline = 0;
+
+ for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) {
+ if (db_get_b(hContact, MODULE, "FavouriteContact", 0)) {
+ char *proto = GetContactProto(hContact);
+ if (proto == NULL)
+ continue;
+
+ WORD wStatus = db_get_w(hContact, proto, "Status", ID_STATUS_OFFLINE);
+ WordToStatusDesc(hContact, proto, "Status", swzStatus, 256);
+
+ if (wStatus != ID_STATUS_OFFLINE)
+ iCountOnline++;
+
+ iCount++;
+
+ if (!(opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE && wStatus == ID_STATUS_OFFLINE)) {
+ if (!bTitlePainted) {
+ AddRow(pwd, TranslateT("Fav. contacts"), NULL, NULL, false, false, !bFirstItem, true, NULL);
+ bFirstItem = false;
+ bTitlePainted = true;
+ }
+
+ TCHAR *swzNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, hContact, GCDNF_TCHAR);
+ if (opt.iFavoriteContFlags & FAVCONT_APPEND_PROTO) {
+ TCHAR *swzProto = a2t(proto);
+ mir_sntprintf(swzName, 256, _T("%s (%s)"), swzNick, swzProto);
+ mir_free(swzProto);
+ }
+ else _tcscpy(swzName, swzNick);
+
+ AddRow(pwd, swzName, swzStatus, NULL, false, false, false);
+ }
+ }
+ }
+
+ int index = pwd->iRowCount - 1;
+ if (opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE)
+ index -= iCountOnline;
+ else
+ index -= iCount;
+
+ if (index >= 0 && (dwItems & TRAYTIP_NUMCONTACTS) && !((opt.iFavoriteContFlags & FAVCONT_HIDE_OFFLINE) && iCountOnline == 0)) {
+ mir_sntprintf(buff, 64, _T("(%d/%d)"), iCountOnline, iCount);
+ pwd->rows[index].swzValue = mir_tstrdup(buff);
+ }
+ }
+ }
+
+ if (dwItems & TRAYTIP_MIRANDA_UPTIME) {
+ if (TimestampToTimeDifference(NULL, MODULE, "MirandaStartTS", buff, 64)) {
+ AddRow(pwd, TranslateT("Other"), _T(""), NULL, false, false, !bFirstItem, true, NULL);
+ AddRow(pwd, TranslateT("Miranda uptime:"), buff, NULL, false, false, false);
+ }
+ }
+
+ if (dwItems & TRAYTIP_CLIST_EVENT && pwd->clcit.swzText) {
+ TCHAR *pchBr = _tcschr(pwd->clcit.swzText, '\n');
+ TCHAR *pchBold = _tcsstr(pwd->clcit.swzText, _T("<b>"));
+
+ if (!pchBold || pchBold != pwd->clcit.swzText) {
+ TCHAR swzText[256];
+ _tcscpy(swzText, pwd->clcit.swzText);
+ if (pchBr) swzText[pchBr - pwd->clcit.swzText] = 0;
+ AddRow(pwd, swzText, _T(""), NULL, false, true, false, true, LoadSkinnedIcon(SKINICON_OTHER_FILLEDBLOB));
+ }
+ }
+
+ return TRUE;
+ }
+
+ return DefWindowProc(hwnd, uMsg, wParam, lParam);
+}
diff --git a/plugins/TipperYM/src/subst.cpp b/plugins/TipperYM/src/subst.cpp
index 01f3344305..97559c11da 100644
--- a/plugins/TipperYM/src/subst.cpp
+++ b/plugins/TipperYM/src/subst.cpp
@@ -1,852 +1,852 @@
-/*
-Copyright (C) 2006-2007 Scott Ellis
-Copyright (C) 2007-2011 Jan Holub
-
-This is free software; you can redistribute it and/or
-modify it under the terms of the GNU Library General Public
-License as published by the Free Software Foundation; either
-version 2 of the License, or (at your option) any later version.
-
-This 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
-Library General Public License for more details.
-
-You should have received a copy of the GNU Library General Public
-License along with this file; see the file license.txt. If
-not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
-*/
-
-#include "common.h"
-
-bool DBGetContactSettingAsString(MCONTACT hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen)
-{
- DBVARIANT dbv;
- buff[0] = 0;
-
- if (!szModuleName || !szSettingName)
- return false;
-
- if (!db_get(hContact, szModuleName, szSettingName, &dbv)) {
- switch (dbv.type) {
- case DBVT_BYTE:
- _itot(dbv.bVal, buff, 10);
- break;
- case DBVT_WORD:
- _ltot(dbv.wVal, buff, 10);
- break;
- case DBVT_DWORD:
- _ltot(dbv.dVal, buff, 10);
- break;
- case DBVT_ASCIIZ:
- if (dbv.pszVal) a2t(dbv.pszVal, buff, bufflen);
- buff[bufflen - 1] = 0;
- break;
- case DBVT_UTF8:
- if (dbv.pszVal) utf2t(dbv.pszVal, buff, bufflen);
- buff[bufflen - 1] = 0;
- break;
-
- case DBVT_WCHAR:
- if (dbv.pwszVal) wcsncpy(buff, dbv.pwszVal, bufflen);
- buff[bufflen - 1] = 0;
- break;
- }
-
- db_free(&dbv);
- }
-
- return buff[0] ? true : false;
-}
-
-bool CheckContactType(MCONTACT hContact, const DISPLAYITEM &di)
-{
- if (di.type == DIT_ALL)
- return true;
-
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- if (db_get_b(hContact, szProto, "ChatRoom", 0) != 0)
- return di.type == DIT_CHATS;
- else
- return di.type == DIT_CONTACTS;
- }
-
- return false;
-}
-
-void StripBBCodesInPlace(TCHAR *swzText)
-{
- if (!db_get_b(0, MODULE, "StripBBCodes", 1))
- return;
-
- if (swzText == 0)
- return;
-
- size_t iRead = 0, iWrite = 0;
- size_t iLen = _tcslen(swzText);
-
- while(iRead <= iLen) { // copy terminating null too
- while (iRead <= iLen && swzText[iRead] != '[') {
- if (swzText[iRead] != swzText[iWrite]) swzText[iWrite] = swzText[iRead];
- iRead++; iWrite++;
- }
-
- if (iRead > iLen)
- break;
-
- if (iLen - iRead >= 3 && (_tcsnicmp(swzText + iRead, _T("[b]"), 3) == 0 || _tcsnicmp(swzText + iRead, _T("[i]"), 3) == 0))
- iRead += 3;
- else if (iLen - iRead >= 4 && (_tcsnicmp(swzText + iRead, _T("[/b]"), 4) == 0 || _tcsnicmp(swzText + iRead, _T("[/i]"), 4) == 0))
- iRead += 4;
- else if (iLen - iRead >= 6 && (_tcsnicmp(swzText + iRead, _T("[color"), 6) == 0)) {
- while (iRead < iLen && swzText[iRead] != ']') iRead++;
- iRead++;// skip the ']'
- }
- else if (iLen - iRead >= 8 && (_tcsnicmp(swzText + iRead, _T("[/color]"), 8) == 0))
- iRead += 8;
- else if (iLen - iRead >= 5 && (_tcsnicmp(swzText + iRead, _T("[size"), 5) == 0)) {
- while (iRead < iLen && swzText[iRead] != ']') iRead++;
- iRead++;// skip the ']'
- }
- else if (iLen - iRead >= 7 && (_tcsnicmp(swzText + iRead, _T("[/size]"), 7) == 0))
- iRead += 7;
- else {
- if (swzText[iRead] != swzText[iWrite]) swzText[iWrite] = swzText[iRead];
- iRead++; iWrite++;
- }
- }
-}
-
-DWORD LastMessageTimestamp(MCONTACT hContact, bool received)
-{
- for (HANDLE hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
- DBEVENTINFO dbei = { sizeof(dbei) };
- db_event_get(hDbEvent, &dbei);
- if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT) == received)
- return dbei.timestamp;
- }
-
- return 0;
-}
-
-void FormatTimestamp(DWORD ts, char *szFormat, TCHAR *buff, int bufflen)
-{
- TCHAR swzForm[16];
- DBTIMETOSTRINGT dbt = {0};
- dbt.cbDest = bufflen;
- dbt.szDest = buff;
- a2t(szFormat, swzForm, 16);
- dbt.szFormat = swzForm;
- CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt);
-}
-
-bool Uid(MCONTACT hContact, char *szProto, TCHAR *buff, int bufflen)
-{
- char *tmpProto = (hContact) ? tmpProto = GetContactProto(hContact) : szProto;
- if (tmpProto) {
- char *szUid = (char*)CallProtoService(tmpProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
- if (szUid && (INT_PTR)szUid != CALLSERVICE_NOTFOUND)
- return DBGetContactSettingAsString(hContact, tmpProto, szUid, buff, bufflen);
- }
-
- return false;
-}
-
-bool UidName(char *szProto, TCHAR *buff, int bufflen)
-{
- if (szProto) {
- char *szUidName = (char*)CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0);
- if (szUidName && (INT_PTR)szUidName != CALLSERVICE_NOTFOUND) {
- a2t(szUidName, buff, bufflen);
- return true;
- }
- }
- return false;
-}
-
-TCHAR *GetLastMessageText(MCONTACT hContact, bool received)
-{
- for (HANDLE hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
- DBEVENTINFO dbei = { sizeof(dbei) };
- db_event_get(hDbEvent, &dbei);
- if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT) == received) {
- dbei.pBlob = (BYTE *)alloca(dbei.cbBlob);
- db_event_get(hDbEvent, &dbei);
- if (dbei.cbBlob == 0 || dbei.pBlob == 0)
- return 0;
-
- TCHAR *buff = DbGetEventTextT( &dbei, CP_ACP );
- TCHAR *swzMsg = mir_tstrdup(buff);
- mir_free(buff);
-
- StripBBCodesInPlace(swzMsg);
- return swzMsg;
- }
- }
-
- return 0;
-}
-
-bool CanRetrieveStatusMsg(MCONTACT hContact, char *szProto)
-{
- if (opt.bGetNewStatusMsg) {
- int iFlags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0);
- WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
- if ((CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) && (iFlags & Proto_Status2Flag(wStatus))) {
- iFlags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & (PF1_VISLIST | PF1_INVISLIST);
- if (opt.bDisableIfInvisible && iFlags) {
- int iVisMode = db_get_w(hContact, szProto, "ApparentMode", 0);
- int wProtoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
- if ((iVisMode == ID_STATUS_OFFLINE) || (wProtoStatus == ID_STATUS_INVISIBLE && iVisMode != ID_STATUS_ONLINE))
- return false;
- return true;
- }
- return true;
- }
- }
-
- return false;
-}
-
-TCHAR* GetStatusMessageText(MCONTACT hContact)
-{
- TCHAR *swzMsg = 0;
- DBVARIANT dbv;
-
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- if (!strcmp(szProto, META_PROTO))
- hContact = db_mc_getMostOnline(hContact);
- else {
- WORD wStatus = (int)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
- if (wStatus == ID_STATUS_OFFLINE)
- return NULL;
-
- if (!db_get_ts(hContact, MODULE, "TempStatusMsg", &dbv)) {
- if (_tcslen(dbv.ptszVal) != 0)
- swzMsg = mir_tstrdup(dbv.ptszVal);
- db_free(&dbv);
- }
- }
-
- if (!swzMsg) {
- if (CanRetrieveStatusMsg(hContact, szProto))
- if (CallContactService(hContact, PSS_GETAWAYMSG, 0, 0))
- return NULL;
-
- if (!db_get_ts(hContact, "CList", "StatusMsg", &dbv)) {
- if (dbv.ptszVal && _tcslen(dbv.ptszVal) != 0)
- swzMsg = mir_tstrdup(dbv.ptszVal);
- db_free(&dbv);
- }
- }
- }
-
- if (swzMsg)
- StripBBCodesInPlace(swzMsg);
-
- return swzMsg;
-}
-
-bool GetSysSubstText(MCONTACT hContact, TCHAR *swzRawSpec, TCHAR *buff, int bufflen)
-{
- bool recv = false;
-
- if (!_tcscmp(swzRawSpec, _T("uid")))
- return Uid(hContact, 0, buff, bufflen);
-
- if (!_tcscmp(swzRawSpec, _T("proto"))) {
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- a2t(szProto, buff, bufflen);
- return true;
- }
- }
- else if (!_tcscmp(swzRawSpec, _T("account"))) {
- char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEACCOUNT, hContact, 0);
- if ((INT_PTR)szProto == CALLSERVICE_NOTFOUND) {
- return GetSysSubstText(hContact, _T("proto"), buff, bufflen);
- }
- else if (szProto) {
- PROTOACCOUNT *pa = ProtoGetAccount(szProto);
- if (pa && pa->tszAccountName) {
- _tcsncpy(buff, pa->tszAccountName, bufflen);
- return true;
- }
- else
- return GetSysSubstText(hContact, _T("proto"), buff, bufflen);
- }
- }
- else if (!_tcscmp(swzRawSpec, _T("time"))) {
- if (tmi.printDateTime && !tmi.printDateTimeByContact(hContact, _T("t"), buff, bufflen, TZF_KNOWNONLY))
- return true;
- }
- else if (!_tcscmp(swzRawSpec, _T("uidname"))) {
- char *szProto = GetContactProto(hContact);
- return UidName(szProto, buff, bufflen);
- }
- else if (!_tcscmp(swzRawSpec, _T("status_msg"))) {
- TCHAR *swzMsg = GetStatusMessageText(hContact);
- if (swzMsg) {
- _tcsncpy(buff, swzMsg, bufflen);
- mir_free(swzMsg);
- return true;
- }
- }
- else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg"))) || !_tcscmp(swzRawSpec, _T("last_msg_out"))) {
- TCHAR *swzMsg = GetLastMessageText(hContact, recv);
- if (swzMsg) {
- _tcsncpy(buff, swzMsg, bufflen);
- mir_free(swzMsg);
- return true;
- }
- }
- else if (!_tcscmp(swzRawSpec, _T("meta_subname"))) {
- // get contact list name of active subcontact
- MCONTACT hSubContact = db_mc_getMostOnline(hContact);
- if (!hSubContact)
- return false;
-
- TCHAR *swzNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, GCDNF_TCHAR);
- if (swzNick) _tcsncpy(buff, swzNick, bufflen);
- return true;
- }
- else if (!_tcscmp(swzRawSpec, _T("meta_subuid"))) {
- MCONTACT hSubContact = db_mc_getMostOnline(hContact);
- if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND)
- return false;
- return Uid(hSubContact, 0, buff, bufflen);
- }
- else if (!_tcscmp(swzRawSpec, _T("meta_subproto"))) {
- // get protocol of active subcontact
- MCONTACT hSubContact = db_mc_getMostOnline(hContact);
- if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND)
- return false;
- return GetSysSubstText(hSubContact, _T("account"), buff, bufflen);
- }
- else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg_time"))) || !_tcscmp(swzRawSpec, _T("last_msg_out_time"))) {
- DWORD ts = LastMessageTimestamp(hContact, recv);
- if (ts == 0) return false;
- FormatTimestamp(ts, "t", buff, bufflen);
- return true;
- }
- else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg_date"))) || !_tcscmp(swzRawSpec, _T("last_msg_out_date"))) {
- DWORD ts = LastMessageTimestamp(hContact, recv);
- if (ts == 0) return false;
- FormatTimestamp(ts, "d", buff, bufflen);
- return true;
- }
- else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg_reltime"))) || !_tcscmp(swzRawSpec, _T("last_msg_out_reltime"))) {
- DWORD ts = LastMessageTimestamp(hContact, recv);
- if (ts == 0) return false;
- DWORD t = (DWORD)time(0);
- DWORD diff = (t - ts);
- int d = (diff / 60 / 60 / 24);
- int h = (diff - d * 60 * 60 * 24) / 60 / 60;
- int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60;
- if (d > 0) mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m);
- else if (h > 0) mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m);
- else mir_sntprintf(buff, bufflen, TranslateT("%dm"), m);
- return true;
- }
- else if (!_tcscmp(swzRawSpec, _T("msg_count_all")) || !_tcscmp(swzRawSpec, _T("msg_count_out")) || !_tcscmp(swzRawSpec, _T("msg_count_in"))) {
- DWORD dwCountOut, dwCountIn;
- DWORD dwMetaCountOut = 0, dwMetaCountIn = 0;
- DWORD dwLastTs, dwNewTs, dwRecountTs;
- DWORD dwTime, dwDiff;
- int iNumber = 1;
- MCONTACT hTmpContact = hContact;
-
- char *szProto = GetContactProto(hContact);
- if (szProto && !strcmp(szProto, META_PROTO)) {
- iNumber = db_mc_getSubCount(hContact);
- hTmpContact = db_mc_getSub(hContact, 0);
- }
-
- for (int i = 0; i < iNumber; i++) {
- if (i > 0)
- hTmpContact = db_mc_getSub(hContact, i);
- dwRecountTs = db_get_dw(hTmpContact, MODULE, "LastCountTS", 0);
- dwTime = (DWORD)time(0);
- dwDiff = (dwTime - dwRecountTs);
- if (dwDiff > (60 * 60 * 24 * 3)) {
- db_set_dw(hTmpContact, MODULE, "LastCountTS", dwTime);
- dwCountOut = dwCountIn = dwLastTs = 0;
- }
- else {
- dwCountOut = db_get_dw(hTmpContact, MODULE, "MsgCountOut", 0);
- dwCountIn = db_get_dw(hTmpContact, MODULE, "MsgCountIn", 0);
- dwLastTs = db_get_dw(hTmpContact, MODULE, "LastMsgTS", 0);
- }
-
- dwNewTs = dwLastTs;
-
- HANDLE dbe = db_event_last(hTmpContact);
- while (dbe != NULL) {
- DBEVENTINFO dbei = { sizeof(dbei) };
- if (!db_event_get(dbe, &dbei)) {
- if (dbei.eventType == EVENTTYPE_MESSAGE) {
- dwNewTs = max(dwNewTs, dbei.timestamp);
- if (dbei.timestamp > dwLastTs) {
- if (dbei.flags & DBEF_SENT) dwCountOut++;
- else dwCountIn++;
- }
- else break;
- }
- }
- dbe = db_event_prev(hTmpContact, dbe);
- }
-
- if (dwNewTs > dwLastTs) {
- db_set_dw(hTmpContact, MODULE, "MsgCountOut", dwCountOut);
- db_set_dw(hTmpContact, MODULE, "MsgCountIn", dwCountIn);
- db_set_dw(hTmpContact, MODULE, "LastMsgTS", dwNewTs);
- }
-
- dwMetaCountOut += dwCountOut;
- dwMetaCountIn += dwCountIn;
- }
-
- if (!_tcscmp(swzRawSpec, _T("msg_count_out")))
- mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountOut);
- else if (!_tcscmp(swzRawSpec, _T("msg_count_in")))
- mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountIn);
- else
- mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountOut + dwMetaCountIn);
- return true;
- }
-
- return false;
-}
-
-bool GetSubstText(MCONTACT hContact, const DISPLAYSUBST &ds, TCHAR *buff, int bufflen)
-{
- TranslateFunc *transFunc = 0;
- for (int i = 0; i < iTransFuncsCount; i++)
- if (translations[i].id == (DWORD)ds.iTranslateFuncId) {
- transFunc = translations[i].transFunc;
- break;
- }
-
- if (!transFunc)
- return false;
-
- switch (ds.type) {
- case DVT_DB:
- return transFunc(hContact, ds.szModuleName, ds.szSettingName, buff, bufflen) != 0;
- case DVT_PROTODB:
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- if (transFunc(hContact, szProto, ds.szSettingName, buff, bufflen) != 0)
- return true;
- return transFunc(hContact, "UserInfo", ds.szSettingName, buff, bufflen) != 0;
- }
- break;
- }
- return false;
-}
-
-bool GetRawSubstText(MCONTACT hContact, char *szRawSpec, TCHAR *buff, int bufflen)
-{
- size_t lenght = strlen(szRawSpec);
- for (size_t i = 0; i < lenght; i++) {
- if (szRawSpec[i] == '/') {
- szRawSpec[i] = 0;
- if (strlen(szRawSpec) == 0) {
- char *szProto = GetContactProto(hContact);
- if (szProto) {
- if (translations[0].transFunc(hContact, szProto, &szRawSpec[i + 1], buff, bufflen) != 0)
- return true;
- return translations[0].transFunc(hContact, "UserInfo", &szRawSpec[i + 1], buff, bufflen) != 0;
- }
- return false;
- }
- return translations[0].transFunc(hContact, szRawSpec, &szRawSpec[i + 1], buff, bufflen) != 0;
- }
- }
- return false;
-}
-
-bool ApplySubst(MCONTACT hContact, const TCHAR *swzSource, bool parseTipperVarsFirst, TCHAR *swzDest, int iDestLen)
-{
- // hack - allow empty strings before passing to variables (note - zero length strings return false after this)
- if (swzDest && swzSource && _tcslen(swzSource) == 0) {
- swzDest[0] = 0;
- return true;
- }
-
- // pass to variables plugin if available
- TCHAR *swzVarSrc;
- if (parseTipperVarsFirst)
- swzVarSrc = mir_tstrdup(swzSource);
- else
- swzVarSrc = variables_parsedup((TCHAR *)swzSource, 0, hContact);
-
- size_t iSourceLen = _tcslen(swzVarSrc);
- size_t si = 0, di = 0, v = 0;
-
- TCHAR swzVName[LABEL_LEN];
- TCHAR swzRep[VALUE_LEN], swzAlt[VALUE_LEN];
- while (si < iSourceLen && di < (size_t)iDestLen - 1) {
- if (swzVarSrc[si] == _T('%')) {
- si++;
- v = 0;
- while (si < iSourceLen && v < LABEL_LEN) {
- if (swzVarSrc[si] == _T('%'))
- break;
-
- swzVName[v] = swzVarSrc[si];
- v++; si++;
- }
-
- if (v == 0) // bSubst len is 0 - just a % symbol
- swzDest[di] = _T('%');
- else if (si < iSourceLen) // we found end %
- {
- swzVName[v] = 0;
-
- bool bAltSubst = false;
- bool bSubst = false;
-
- // apply only to specific protocols
- TCHAR *p = _tcsrchr(swzVName, _T('^')); // use last '^', so if you want a ^ in swzAlt text, you can just put a '^' on the end
- if (p) {
- *p = 0;
- p++;
- if (*p) {
- char *cp = GetContactProto(hContact);
- if (cp != NULL) {
- PROTOACCOUNT *acc = ProtoGetAccount(cp);
- if (acc != NULL) {
- cp = acc->szProtoName;
- }
- }
-
- if (cp == NULL)
- goto empty;
-
- bool negate = false;
- if (*p == _T('!')) {
- p++;
- if (*p == 0) goto error;
- negate = true;
- }
-
- char sproto[256];
- bool spec = false;
- int len;
-
- TCHAR *last = _tcsrchr(p, _T(','));
- if (!last) last = p;
-
- while (p <= last + 1) {
- len = (int)_tcscspn(p, _T(","));
- t2a(p, sproto, len);
- sproto[len] = 0;
- p += len + 1;
-
- if (_stricmp(cp, sproto) == 0) {
- spec = true;
- break;
- }
- }
-
- if (negate ? spec : !spec)
- goto empty;
- }
- }
-
- // get alternate text, if bSubst fails
- swzAlt[0] = 0;
- p = _tcschr(swzVName, _T('|')); // use first '|' - so you can use the '|' symbol in swzAlt text
- if (p) {
- *p = 0; // clip swzAlt from swzVName
- p++;
- if (_tcslen(p) > 4 && _tcsncmp(p, _T("raw:"), 4) == 0) { // raw db substitution
- char raw_spec[LABEL_LEN];
- p += 4;
- t2a(p, raw_spec, LABEL_LEN);
- GetRawSubstText(hContact, raw_spec, swzAlt, VALUE_LEN);
- }
- else if (_tcslen(p) > 4 && _tcsncmp(p, _T("sys:"), 4) == 0) { // 'system' substitution
- p += 4;
- GetSysSubstText(hContact, p, swzAlt, VALUE_LEN);
- }
- else {
- // see if we can find the bSubst
- DSListNode *ds_node = opt.dsList;
- while (ds_node) {
- if (_tcscmp(ds_node->ds.swzName, p) == 0)
- break;
-
- ds_node = ds_node->next;
- }
-
- if (ds_node)
- GetSubstText(hContact, ds_node->ds, swzAlt, VALUE_LEN);
- else {
- _tcsncpy(swzAlt, p, VALUE_LEN);
- bAltSubst = true;
- }
- }
- swzAlt[VALUE_LEN - 1] = 0;
- if (_tcslen(swzAlt) != 0)
- bAltSubst = true;
- }
-
- // get bSubst text
- if (v > 4 && _tcsncmp(swzVName, _T("raw:"), 4) == 0) // raw db substitution
- {
- char raw_spec[LABEL_LEN];
- t2a(&swzVName[4], raw_spec, LABEL_LEN);
- bSubst = GetRawSubstText(hContact, raw_spec, swzRep, VALUE_LEN);
- }
- else if (v > 4 && _tcsncmp(swzVName, _T("sys:"), 4) == 0) // 'system' substitution
- {
- bSubst = GetSysSubstText(hContact, &swzVName[4], swzRep, VALUE_LEN);
- }
- else {
- // see if we can find the bSubst
- DSListNode *ds_node = opt.dsList;
- while (ds_node) {
- if (_tcscmp(ds_node->ds.swzName, swzVName) == 0)
- break;
-
- ds_node = ds_node->next;
- }
-
- if (!ds_node)
- goto error; // no such bSubst
-
- bSubst = GetSubstText(hContact, ds_node->ds, swzRep, VALUE_LEN);
- }
-
- if (bSubst) {
- size_t rep_len = _tcslen(swzRep);
- _tcsncpy(&swzDest[di], swzRep, min(rep_len, iDestLen - di));
- di += rep_len - 1; // -1 because we inc at bottom of loop
- }
- else if (bAltSubst) {
- size_t alt_len = _tcslen(swzAlt);
- _tcsncpy(&swzDest[di], swzAlt, min(alt_len, iDestLen - di));
- di += alt_len - 1; // -1 because we inc at bottom of loop
- }
- else goto empty; // empty value
- }
- else // no end % - error
- goto error;
- }
- else swzDest[di] = swzVarSrc[si];
-
- si++;
- di++;
- }
-
- mir_free(swzVarSrc);
- swzDest[di] = 0;
-
- if (parseTipperVarsFirst) {
- swzVarSrc = variables_parsedup((TCHAR *)swzDest, 0, hContact);
- _tcscpy(swzDest, swzVarSrc);
- mir_free(swzVarSrc);
- }
-
-
- // check for a 'blank' string - just spaces etc
- for (si = 0; si <= di; si++) {
- if (swzDest[si] != 0 && swzDest[si] != _T(' ') && swzDest[si] != _T('\t') && swzDest[si] != _T('\r') && swzDest[si] != _T('\n'))
- return true;
- }
-
- return false;
-
-empty:
- mir_free(swzVarSrc);
- return false;
-
-error:
- swzDest[0] = _T('*');
- swzDest[1] = 0;
- mir_free(swzVarSrc);
- return true;
-}
-
-bool GetLabelText(MCONTACT hContact, const DISPLAYITEM &di, TCHAR *buff, int bufflen)
-{
- return ApplySubst(hContact, di.swzLabel, false, buff, bufflen);
-}
-
-bool GetValueText(MCONTACT hContact, const DISPLAYITEM &di, TCHAR *buff, int bufflen)
-{
- return ApplySubst(hContact, di.swzValue, di.bParseTipperVarsFirst, buff, bufflen);
-}
-
-void TruncateString(TCHAR *swzText)
-{
- if (swzText && opt.iLimitCharCount > 3) {
- if ((int)_tcslen(swzText) > opt.iLimitCharCount) {
- swzText[opt.iLimitCharCount - 3] = 0;
- _tcscat(swzText, _T("..."));
- }
- }
-}
-
-TCHAR *GetProtoStatusMessage(char *szProto, WORD wStatus)
-{
- if (!szProto || wStatus == ID_STATUS_OFFLINE)
- return NULL;
-
- // check if protocol supports status message for status
- int flags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0);
- if (!(flags & Proto_Status2Flag(wStatus)))
- return NULL;
-
- TCHAR *swzText = (TCHAR *)CallProtoService(szProto, PS_GETMYAWAYMSG, 0, SGMA_TCHAR);
- if ((INT_PTR)swzText == CALLSERVICE_NOTFOUND)
- swzText = (TCHAR*)CallService(MS_AWAYMSG_GETSTATUSMSGT, wStatus, 0);
-
- else if (swzText == NULL) {
- // try to use service without SGMA_TCHAR
- char *tmpMsg = (char *)CallProtoService(szProto, PS_GETMYAWAYMSG, 0, 0);
- if (tmpMsg && (INT_PTR)tmpMsg != CALLSERVICE_NOTFOUND) {
- swzText = mir_a2t(tmpMsg);
- mir_free(tmpMsg);
- }
- }
-
-
- if (swzText && !swzText[0]) {
- mir_free(swzText);
- swzText = NULL;
- }
-
- if (swzText && opt.bLimitMsg)
- TruncateString(swzText);
-
- return swzText;
-}
-
-TCHAR *GetProtoExtraStatusTitle(char *szProto)
-{
- DBVARIANT dbv;
- TCHAR *swzText = NULL;
-
- if (!szProto)
- return NULL;
-
- if (!db_get_ts(0, szProto, "XStatusName", &dbv)) {
- if (_tcslen(dbv.ptszVal) != 0)
- swzText = mir_tstrdup(dbv.ptszVal);
- db_free(&dbv);
- }
-
- if (!swzText) {
- TCHAR buff[256];
- if (EmptyXStatusToDefaultName(0, szProto, 0, buff, 256))
- swzText = mir_tstrdup(buff);
- }
-
- if (opt.bLimitMsg)
- TruncateString(swzText);
-
- return swzText;
-}
-
-TCHAR *GetProtoExtraStatusMessage(char *szProto)
-{
- if (!szProto)
- return NULL;
-
- TCHAR *swzText = NULL;
- DBVARIANT dbv;
- if (!db_get_ts(0, szProto, "XStatusMsg", &dbv)) {
- if (_tcslen(dbv.ptszVal) != 0)
- swzText = mir_tstrdup(dbv.ptszVal);
- db_free(&dbv);
-
- if (ServiceExists(MS_VARS_FORMATSTRING)) {
- MCONTACT hContact = db_find_first();
- char *proto = GetContactProto(hContact);
- while (!proto) {
- hContact = db_find_next(hContact);
- if (hContact)
- proto = GetContactProto(hContact);
- else {
- hContact = NULL;
- break;
- }
- }
-
- TCHAR *tszParsed = variables_parse(swzText, NULL, hContact);
- if (tszParsed)
- replaceStrT(swzText, tszParsed);
- }
- }
-
- if (opt.bLimitMsg)
- TruncateString(swzText);
-
- return swzText;
-}
-
-TCHAR *GetListeningTo(char *szProto)
-{
- DBVARIANT dbv;
- TCHAR *swzText = NULL;
-
- if (!szProto)
- return NULL;
-
- if (!db_get_ts(0, szProto, "ListeningTo", &dbv)) {
- if (_tcslen(dbv.ptszVal) != 0)
- swzText = mir_tstrdup(dbv.ptszVal);
- db_free(&dbv);
- }
-
- if (opt.bLimitMsg)
- TruncateString(swzText);
-
- return swzText;
-}
-
-TCHAR *GetJabberAdvStatusText(char *szProto, const char *szSlot, const char *szValue)
-{
- DBVARIANT dbv;
- TCHAR *swzText = NULL;
-
- if (!szProto)
- return NULL;
-
- char szSetting[128];
- mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, szSlot, szValue);
- if (!db_get_ts(0, "AdvStatus", szSetting, &dbv)) {
- if (_tcslen(dbv.ptszVal) != 0)
- swzText = mir_tstrdup(dbv.ptszVal);
- db_free(&dbv);
- }
-
- if (opt.bLimitMsg)
- TruncateString(swzText);
-
- return swzText;
-}
-
-HICON GetJabberActivityIcon(MCONTACT hContact, char *szProto)
-{
- DBVARIANT dbv;
- HICON hIcon = NULL;
-
- if (!szProto)
- return NULL;
-
- char szSetting[128];
- mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, "activity", "icon");
- if (!db_get_s(hContact, "AdvStatus", szSetting, &dbv)) {
- hIcon = Skin_GetIcon(dbv.pszVal);
- db_free(&dbv);
- }
-
- return hIcon;
+/*
+Copyright (C) 2006-2007 Scott Ellis
+Copyright (C) 2007-2011 Jan Holub
+
+This is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this file; see the file license.txt. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+*/
+
+#include "common.h"
+
+bool DBGetContactSettingAsString(MCONTACT hContact, const char *szModuleName, const char *szSettingName, TCHAR *buff, int bufflen)
+{
+ DBVARIANT dbv;
+ buff[0] = 0;
+
+ if (!szModuleName || !szSettingName)
+ return false;
+
+ if (!db_get(hContact, szModuleName, szSettingName, &dbv)) {
+ switch (dbv.type) {
+ case DBVT_BYTE:
+ _itot(dbv.bVal, buff, 10);
+ break;
+ case DBVT_WORD:
+ _ltot(dbv.wVal, buff, 10);
+ break;
+ case DBVT_DWORD:
+ _ltot(dbv.dVal, buff, 10);
+ break;
+ case DBVT_ASCIIZ:
+ if (dbv.pszVal) a2t(dbv.pszVal, buff, bufflen);
+ buff[bufflen - 1] = 0;
+ break;
+ case DBVT_UTF8:
+ if (dbv.pszVal) utf2t(dbv.pszVal, buff, bufflen);
+ buff[bufflen - 1] = 0;
+ break;
+
+ case DBVT_WCHAR:
+ if (dbv.pwszVal) wcsncpy(buff, dbv.pwszVal, bufflen);
+ buff[bufflen - 1] = 0;
+ break;
+ }
+
+ db_free(&dbv);
+ }
+
+ return buff[0] ? true : false;
+}
+
+bool CheckContactType(MCONTACT hContact, const DISPLAYITEM &di)
+{
+ if (di.type == DIT_ALL)
+ return true;
+
+ char *szProto = GetContactProto(hContact);
+ if (szProto) {
+ if (db_get_b(hContact, szProto, "ChatRoom", 0) != 0)
+ return di.type == DIT_CHATS;
+ else
+ return di.type == DIT_CONTACTS;
+ }
+
+ return false;
+}
+
+void StripBBCodesInPlace(TCHAR *swzText)
+{
+ if (!db_get_b(0, MODULE, "StripBBCodes", 1))
+ return;
+
+ if (swzText == 0)
+ return;
+
+ size_t iRead = 0, iWrite = 0;
+ size_t iLen = _tcslen(swzText);
+
+ while(iRead <= iLen) { // copy terminating null too
+ while (iRead <= iLen && swzText[iRead] != '[') {
+ if (swzText[iRead] != swzText[iWrite]) swzText[iWrite] = swzText[iRead];
+ iRead++; iWrite++;
+ }
+
+ if (iRead > iLen)
+ break;
+
+ if (iLen - iRead >= 3 && (_tcsnicmp(swzText + iRead, _T("[b]"), 3) == 0 || _tcsnicmp(swzText + iRead, _T("[i]"), 3) == 0))
+ iRead += 3;
+ else if (iLen - iRead >= 4 && (_tcsnicmp(swzText + iRead, _T("[/b]"), 4) == 0 || _tcsnicmp(swzText + iRead, _T("[/i]"), 4) == 0))
+ iRead += 4;
+ else if (iLen - iRead >= 6 && (_tcsnicmp(swzText + iRead, _T("[color"), 6) == 0)) {
+ while (iRead < iLen && swzText[iRead] != ']') iRead++;
+ iRead++;// skip the ']'
+ }
+ else if (iLen - iRead >= 8 && (_tcsnicmp(swzText + iRead, _T("[/color]"), 8) == 0))
+ iRead += 8;
+ else if (iLen - iRead >= 5 && (_tcsnicmp(swzText + iRead, _T("[size"), 5) == 0)) {
+ while (iRead < iLen && swzText[iRead] != ']') iRead++;
+ iRead++;// skip the ']'
+ }
+ else if (iLen - iRead >= 7 && (_tcsnicmp(swzText + iRead, _T("[/size]"), 7) == 0))
+ iRead += 7;
+ else {
+ if (swzText[iRead] != swzText[iWrite]) swzText[iWrite] = swzText[iRead];
+ iRead++; iWrite++;
+ }
+ }
+}
+
+DWORD LastMessageTimestamp(MCONTACT hContact, bool received)
+{
+ for (HANDLE hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ db_event_get(hDbEvent, &dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT) == received)
+ return dbei.timestamp;
+ }
+
+ return 0;
+}
+
+void FormatTimestamp(DWORD ts, char *szFormat, TCHAR *buff, int bufflen)
+{
+ TCHAR swzForm[16];
+ DBTIMETOSTRINGT dbt = {0};
+ dbt.cbDest = bufflen;
+ dbt.szDest = buff;
+ a2t(szFormat, swzForm, 16);
+ dbt.szFormat = swzForm;
+ CallService(MS_DB_TIME_TIMESTAMPTOSTRINGT, (WPARAM)ts, (LPARAM)&dbt);
+}
+
+bool Uid(MCONTACT hContact, char *szProto, TCHAR *buff, int bufflen)
+{
+ char *tmpProto = (hContact) ? tmpProto = GetContactProto(hContact) : szProto;
+ if (tmpProto) {
+ char *szUid = (char*)CallProtoService(tmpProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
+ if (szUid && (INT_PTR)szUid != CALLSERVICE_NOTFOUND)
+ return DBGetContactSettingAsString(hContact, tmpProto, szUid, buff, bufflen);
+ }
+
+ return false;
+}
+
+bool UidName(char *szProto, TCHAR *buff, int bufflen)
+{
+ if (szProto) {
+ char *szUidName = (char*)CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0);
+ if (szUidName && (INT_PTR)szUidName != CALLSERVICE_NOTFOUND) {
+ a2t(szUidName, buff, bufflen);
+ return true;
+ }
+ }
+ return false;
+}
+
+TCHAR *GetLastMessageText(MCONTACT hContact, bool received)
+{
+ for (HANDLE hDbEvent = db_event_last(hContact); hDbEvent; hDbEvent = db_event_prev(hContact, hDbEvent)) {
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ db_event_get(hDbEvent, &dbei);
+ if (dbei.eventType == EVENTTYPE_MESSAGE && !(dbei.flags & DBEF_SENT) == received) {
+ dbei.pBlob = (BYTE *)alloca(dbei.cbBlob);
+ db_event_get(hDbEvent, &dbei);
+ if (dbei.cbBlob == 0 || dbei.pBlob == 0)
+ return 0;
+
+ TCHAR *buff = DbGetEventTextT( &dbei, CP_ACP );
+ TCHAR *swzMsg = mir_tstrdup(buff);
+ mir_free(buff);
+
+ StripBBCodesInPlace(swzMsg);
+ return swzMsg;
+ }
+ }
+
+ return 0;
+}
+
+bool CanRetrieveStatusMsg(MCONTACT hContact, char *szProto)
+{
+ if (opt.bGetNewStatusMsg) {
+ int iFlags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0);
+ WORD wStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ if ((CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) && (iFlags & Proto_Status2Flag(wStatus))) {
+ iFlags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & (PF1_VISLIST | PF1_INVISLIST);
+ if (opt.bDisableIfInvisible && iFlags) {
+ int iVisMode = db_get_w(hContact, szProto, "ApparentMode", 0);
+ int wProtoStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if ((iVisMode == ID_STATUS_OFFLINE) || (wProtoStatus == ID_STATUS_INVISIBLE && iVisMode != ID_STATUS_ONLINE))
+ return false;
+ return true;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+TCHAR* GetStatusMessageText(MCONTACT hContact)
+{
+ TCHAR *swzMsg = NULL;
+ DBVARIANT dbv;
+
+ char *szProto = GetContactProto(hContact);
+ if (szProto) {
+ if (!strcmp(szProto, META_PROTO))
+ hContact = db_mc_getMostOnline(hContact);
+ else {
+ WORD wStatus = (int)CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (wStatus == ID_STATUS_OFFLINE)
+ return NULL;
+
+ if (!db_get_ts(hContact, MODULE, "TempStatusMsg", &dbv)) {
+ if (_tcslen(dbv.ptszVal) != 0)
+ swzMsg = mir_tstrdup(dbv.ptszVal);
+ db_free(&dbv);
+ }
+ }
+
+ if (!swzMsg) {
+ if (CanRetrieveStatusMsg(hContact, szProto))
+ if (CallContactService(hContact, PSS_GETAWAYMSG, 0, 0))
+ return NULL;
+
+ if (!db_get_ts(hContact, "CList", "StatusMsg", &dbv)) {
+ if (_tcslen(dbv.ptszVal) != 0)
+ swzMsg = mir_tstrdup(dbv.ptszVal);
+ db_free(&dbv);
+ }
+ }
+ }
+
+ if (swzMsg)
+ StripBBCodesInPlace(swzMsg);
+
+ return swzMsg;
+}
+
+bool GetSysSubstText(MCONTACT hContact, TCHAR *swzRawSpec, TCHAR *buff, int bufflen)
+{
+ bool recv = false;
+
+ if (!_tcscmp(swzRawSpec, _T("uid")))
+ return Uid(hContact, 0, buff, bufflen);
+
+ if (!_tcscmp(swzRawSpec, _T("proto"))) {
+ char *szProto = GetContactProto(hContact);
+ if (szProto) {
+ a2t(szProto, buff, bufflen);
+ return true;
+ }
+ }
+ else if (!_tcscmp(swzRawSpec, _T("account"))) {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEACCOUNT, hContact, 0);
+ if ((INT_PTR)szProto == CALLSERVICE_NOTFOUND) {
+ return GetSysSubstText(hContact, _T("proto"), buff, bufflen);
+ }
+ else if (szProto) {
+ PROTOACCOUNT *pa = ProtoGetAccount(szProto);
+ if (pa && pa->tszAccountName) {
+ _tcsncpy(buff, pa->tszAccountName, bufflen);
+ return true;
+ }
+ else
+ return GetSysSubstText(hContact, _T("proto"), buff, bufflen);
+ }
+ }
+ else if (!_tcscmp(swzRawSpec, _T("time"))) {
+ if (tmi.printDateTime && !tmi.printDateTimeByContact(hContact, _T("t"), buff, bufflen, TZF_KNOWNONLY))
+ return true;
+ }
+ else if (!_tcscmp(swzRawSpec, _T("uidname"))) {
+ char *szProto = GetContactProto(hContact);
+ return UidName(szProto, buff, bufflen);
+ }
+ else if (!_tcscmp(swzRawSpec, _T("status_msg"))) {
+ TCHAR *swzMsg = GetStatusMessageText(hContact);
+ if (swzMsg) {
+ _tcsncpy(buff, swzMsg, bufflen);
+ mir_free(swzMsg);
+ return true;
+ }
+ }
+ else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg"))) || !_tcscmp(swzRawSpec, _T("last_msg_out"))) {
+ TCHAR *swzMsg = GetLastMessageText(hContact, recv);
+ if (swzMsg) {
+ _tcsncpy(buff, swzMsg, bufflen);
+ mir_free(swzMsg);
+ return true;
+ }
+ }
+ else if (!_tcscmp(swzRawSpec, _T("meta_subname"))) {
+ // get contact list name of active subcontact
+ MCONTACT hSubContact = db_mc_getMostOnline(hContact);
+ if (!hSubContact)
+ return false;
+
+ TCHAR *swzNick = (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hSubContact, GCDNF_TCHAR);
+ if (swzNick) _tcsncpy(buff, swzNick, bufflen);
+ return true;
+ }
+ else if (!_tcscmp(swzRawSpec, _T("meta_subuid"))) {
+ MCONTACT hSubContact = db_mc_getMostOnline(hContact);
+ if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND)
+ return false;
+ return Uid(hSubContact, 0, buff, bufflen);
+ }
+ else if (!_tcscmp(swzRawSpec, _T("meta_subproto"))) {
+ // get protocol of active subcontact
+ MCONTACT hSubContact = db_mc_getMostOnline(hContact);
+ if (!hSubContact || (INT_PTR)hSubContact == CALLSERVICE_NOTFOUND)
+ return false;
+ return GetSysSubstText(hSubContact, _T("account"), buff, bufflen);
+ }
+ else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg_time"))) || !_tcscmp(swzRawSpec, _T("last_msg_out_time"))) {
+ DWORD ts = LastMessageTimestamp(hContact, recv);
+ if (ts == 0) return false;
+ FormatTimestamp(ts, "t", buff, bufflen);
+ return true;
+ }
+ else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg_date"))) || !_tcscmp(swzRawSpec, _T("last_msg_out_date"))) {
+ DWORD ts = LastMessageTimestamp(hContact, recv);
+ if (ts == 0) return false;
+ FormatTimestamp(ts, "d", buff, bufflen);
+ return true;
+ }
+ else if ((recv = !_tcscmp(swzRawSpec, _T("last_msg_reltime"))) || !_tcscmp(swzRawSpec, _T("last_msg_out_reltime"))) {
+ DWORD ts = LastMessageTimestamp(hContact, recv);
+ if (ts == 0) return false;
+ DWORD t = (DWORD)time(0);
+ DWORD diff = (t - ts);
+ int d = (diff / 60 / 60 / 24);
+ int h = (diff - d * 60 * 60 * 24) / 60 / 60;
+ int m = (diff - d * 60 * 60 * 24 - h * 60 * 60) / 60;
+ if (d > 0) mir_sntprintf(buff, bufflen, TranslateT("%dd %dh %dm"), d, h, m);
+ else if (h > 0) mir_sntprintf(buff, bufflen, TranslateT("%dh %dm"), h, m);
+ else mir_sntprintf(buff, bufflen, TranslateT("%dm"), m);
+ return true;
+ }
+ else if (!_tcscmp(swzRawSpec, _T("msg_count_all")) || !_tcscmp(swzRawSpec, _T("msg_count_out")) || !_tcscmp(swzRawSpec, _T("msg_count_in"))) {
+ DWORD dwCountOut, dwCountIn;
+ DWORD dwMetaCountOut = 0, dwMetaCountIn = 0;
+ DWORD dwLastTs, dwNewTs, dwRecountTs;
+ DWORD dwTime, dwDiff;
+ int iNumber = 1;
+ MCONTACT hTmpContact = hContact;
+
+ char *szProto = GetContactProto(hContact);
+ if (szProto && !strcmp(szProto, META_PROTO)) {
+ iNumber = db_mc_getSubCount(hContact);
+ hTmpContact = db_mc_getSub(hContact, 0);
+ }
+
+ for (int i = 0; i < iNumber; i++) {
+ if (i > 0)
+ hTmpContact = db_mc_getSub(hContact, i);
+ dwRecountTs = db_get_dw(hTmpContact, MODULE, "LastCountTS", 0);
+ dwTime = (DWORD)time(0);
+ dwDiff = (dwTime - dwRecountTs);
+ if (dwDiff > (60 * 60 * 24 * 3)) {
+ db_set_dw(hTmpContact, MODULE, "LastCountTS", dwTime);
+ dwCountOut = dwCountIn = dwLastTs = 0;
+ }
+ else {
+ dwCountOut = db_get_dw(hTmpContact, MODULE, "MsgCountOut", 0);
+ dwCountIn = db_get_dw(hTmpContact, MODULE, "MsgCountIn", 0);
+ dwLastTs = db_get_dw(hTmpContact, MODULE, "LastMsgTS", 0);
+ }
+
+ dwNewTs = dwLastTs;
+
+ HANDLE dbe = db_event_last(hTmpContact);
+ while (dbe != NULL) {
+ DBEVENTINFO dbei = { sizeof(dbei) };
+ if (!db_event_get(dbe, &dbei)) {
+ if (dbei.eventType == EVENTTYPE_MESSAGE) {
+ dwNewTs = max(dwNewTs, dbei.timestamp);
+ if (dbei.timestamp > dwLastTs) {
+ if (dbei.flags & DBEF_SENT) dwCountOut++;
+ else dwCountIn++;
+ }
+ else break;
+ }
+ }
+ dbe = db_event_prev(hTmpContact, dbe);
+ }
+
+ if (dwNewTs > dwLastTs) {
+ db_set_dw(hTmpContact, MODULE, "MsgCountOut", dwCountOut);
+ db_set_dw(hTmpContact, MODULE, "MsgCountIn", dwCountIn);
+ db_set_dw(hTmpContact, MODULE, "LastMsgTS", dwNewTs);
+ }
+
+ dwMetaCountOut += dwCountOut;
+ dwMetaCountIn += dwCountIn;
+ }
+
+ if (!_tcscmp(swzRawSpec, _T("msg_count_out")))
+ mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountOut);
+ else if (!_tcscmp(swzRawSpec, _T("msg_count_in")))
+ mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountIn);
+ else
+ mir_sntprintf(buff, bufflen, _T("%d"), dwMetaCountOut + dwMetaCountIn);
+ return true;
+ }
+
+ return false;
+}
+
+bool GetSubstText(MCONTACT hContact, const DISPLAYSUBST &ds, TCHAR *buff, int bufflen)
+{
+ TranslateFunc *transFunc = 0;
+ for (int i = 0; i < iTransFuncsCount; i++)
+ if (translations[i].id == (DWORD)ds.iTranslateFuncId) {
+ transFunc = translations[i].transFunc;
+ break;
+ }
+
+ if (!transFunc)
+ return false;
+
+ switch (ds.type) {
+ case DVT_DB:
+ return transFunc(hContact, ds.szModuleName, ds.szSettingName, buff, bufflen) != 0;
+ case DVT_PROTODB:
+ char *szProto = GetContactProto(hContact);
+ if (szProto) {
+ if (transFunc(hContact, szProto, ds.szSettingName, buff, bufflen) != 0)
+ return true;
+ return transFunc(hContact, "UserInfo", ds.szSettingName, buff, bufflen) != 0;
+ }
+ break;
+ }
+ return false;
+}
+
+bool GetRawSubstText(MCONTACT hContact, char *szRawSpec, TCHAR *buff, int bufflen)
+{
+ size_t lenght = strlen(szRawSpec);
+ for (size_t i = 0; i < lenght; i++) {
+ if (szRawSpec[i] == '/') {
+ szRawSpec[i] = 0;
+ if (strlen(szRawSpec) == 0) {
+ char *szProto = GetContactProto(hContact);
+ if (szProto) {
+ if (translations[0].transFunc(hContact, szProto, &szRawSpec[i + 1], buff, bufflen) != 0)
+ return true;
+ return translations[0].transFunc(hContact, "UserInfo", &szRawSpec[i + 1], buff, bufflen) != 0;
+ }
+ return false;
+ }
+ return translations[0].transFunc(hContact, szRawSpec, &szRawSpec[i + 1], buff, bufflen) != 0;
+ }
+ }
+ return false;
+}
+
+bool ApplySubst(MCONTACT hContact, const TCHAR *swzSource, bool parseTipperVarsFirst, TCHAR *swzDest, int iDestLen)
+{
+ // hack - allow empty strings before passing to variables (note - zero length strings return false after this)
+ if (swzDest && swzSource && _tcslen(swzSource) == 0) {
+ swzDest[0] = 0;
+ return true;
+ }
+
+ // pass to variables plugin if available
+ TCHAR *swzVarSrc;
+ if (parseTipperVarsFirst)
+ swzVarSrc = mir_tstrdup(swzSource);
+ else
+ swzVarSrc = variables_parsedup((TCHAR *)swzSource, 0, hContact);
+
+ size_t iSourceLen = _tcslen(swzVarSrc);
+ size_t si = 0, di = 0, v = 0;
+
+ TCHAR swzVName[LABEL_LEN];
+ TCHAR swzRep[VALUE_LEN], swzAlt[VALUE_LEN];
+ while (si < iSourceLen && di < (size_t)iDestLen - 1) {
+ if (swzVarSrc[si] == _T('%')) {
+ si++;
+ v = 0;
+ while (si < iSourceLen && v < LABEL_LEN) {
+ if (swzVarSrc[si] == _T('%'))
+ break;
+
+ swzVName[v] = swzVarSrc[si];
+ v++; si++;
+ }
+
+ if (v == 0) // bSubst len is 0 - just a % symbol
+ swzDest[di] = _T('%');
+ else if (si < iSourceLen) // we found end %
+ {
+ swzVName[v] = 0;
+
+ bool bAltSubst = false;
+ bool bSubst = false;
+
+ // apply only to specific protocols
+ TCHAR *p = _tcsrchr(swzVName, _T('^')); // use last '^', so if you want a ^ in swzAlt text, you can just put a '^' on the end
+ if (p) {
+ *p = 0;
+ p++;
+ if (*p) {
+ char *cp = GetContactProto(hContact);
+ if (cp != NULL) {
+ PROTOACCOUNT *acc = ProtoGetAccount(cp);
+ if (acc != NULL) {
+ cp = acc->szProtoName;
+ }
+ }
+
+ if (cp == NULL)
+ goto empty;
+
+ bool negate = false;
+ if (*p == _T('!')) {
+ p++;
+ if (*p == 0) goto error;
+ negate = true;
+ }
+
+ char sproto[256];
+ bool spec = false;
+ int len;
+
+ TCHAR *last = _tcsrchr(p, _T(','));
+ if (!last) last = p;
+
+ while (p <= last + 1) {
+ len = (int)_tcscspn(p, _T(","));
+ t2a(p, sproto, len);
+ sproto[len] = 0;
+ p += len + 1;
+
+ if (_stricmp(cp, sproto) == 0) {
+ spec = true;
+ break;
+ }
+ }
+
+ if (negate ? spec : !spec)
+ goto empty;
+ }
+ }
+
+ // get alternate text, if bSubst fails
+ swzAlt[0] = 0;
+ p = _tcschr(swzVName, _T('|')); // use first '|' - so you can use the '|' symbol in swzAlt text
+ if (p) {
+ *p = 0; // clip swzAlt from swzVName
+ p++;
+ if (_tcslen(p) > 4 && _tcsncmp(p, _T("raw:"), 4) == 0) { // raw db substitution
+ char raw_spec[LABEL_LEN];
+ p += 4;
+ t2a(p, raw_spec, LABEL_LEN);
+ GetRawSubstText(hContact, raw_spec, swzAlt, VALUE_LEN);
+ }
+ else if (_tcslen(p) > 4 && _tcsncmp(p, _T("sys:"), 4) == 0) { // 'system' substitution
+ p += 4;
+ GetSysSubstText(hContact, p, swzAlt, VALUE_LEN);
+ }
+ else {
+ // see if we can find the bSubst
+ DSListNode *ds_node = opt.dsList;
+ while (ds_node) {
+ if (_tcscmp(ds_node->ds.swzName, p) == 0)
+ break;
+
+ ds_node = ds_node->next;
+ }
+
+ if (ds_node)
+ GetSubstText(hContact, ds_node->ds, swzAlt, VALUE_LEN);
+ else {
+ _tcsncpy(swzAlt, p, VALUE_LEN);
+ bAltSubst = true;
+ }
+ }
+ swzAlt[VALUE_LEN - 1] = 0;
+ if (_tcslen(swzAlt) != 0)
+ bAltSubst = true;
+ }
+
+ // get bSubst text
+ if (v > 4 && _tcsncmp(swzVName, _T("raw:"), 4) == 0) // raw db substitution
+ {
+ char raw_spec[LABEL_LEN];
+ t2a(&swzVName[4], raw_spec, LABEL_LEN);
+ bSubst = GetRawSubstText(hContact, raw_spec, swzRep, VALUE_LEN);
+ }
+ else if (v > 4 && _tcsncmp(swzVName, _T("sys:"), 4) == 0) // 'system' substitution
+ {
+ bSubst = GetSysSubstText(hContact, &swzVName[4], swzRep, VALUE_LEN);
+ }
+ else {
+ // see if we can find the bSubst
+ DSListNode *ds_node = opt.dsList;
+ while (ds_node) {
+ if (_tcscmp(ds_node->ds.swzName, swzVName) == 0)
+ break;
+
+ ds_node = ds_node->next;
+ }
+
+ if (!ds_node)
+ goto error; // no such bSubst
+
+ bSubst = GetSubstText(hContact, ds_node->ds, swzRep, VALUE_LEN);
+ }
+
+ if (bSubst) {
+ size_t rep_len = _tcslen(swzRep);
+ _tcsncpy(&swzDest[di], swzRep, min(rep_len, iDestLen - di));
+ di += rep_len - 1; // -1 because we inc at bottom of loop
+ }
+ else if (bAltSubst) {
+ size_t alt_len = _tcslen(swzAlt);
+ _tcsncpy(&swzDest[di], swzAlt, min(alt_len, iDestLen - di));
+ di += alt_len - 1; // -1 because we inc at bottom of loop
+ }
+ else goto empty; // empty value
+ }
+ else // no end % - error
+ goto error;
+ }
+ else swzDest[di] = swzVarSrc[si];
+
+ si++;
+ di++;
+ }
+
+ mir_free(swzVarSrc);
+ swzDest[di] = 0;
+
+ if (parseTipperVarsFirst) {
+ swzVarSrc = variables_parsedup((TCHAR *)swzDest, 0, hContact);
+ _tcscpy(swzDest, swzVarSrc);
+ mir_free(swzVarSrc);
+ }
+
+
+ // check for a 'blank' string - just spaces etc
+ for (si = 0; si <= di; si++) {
+ if (swzDest[si] != 0 && swzDest[si] != _T(' ') && swzDest[si] != _T('\t') && swzDest[si] != _T('\r') && swzDest[si] != _T('\n'))
+ return true;
+ }
+
+ return false;
+
+empty:
+ mir_free(swzVarSrc);
+ return false;
+
+error:
+ swzDest[0] = _T('*');
+ swzDest[1] = 0;
+ mir_free(swzVarSrc);
+ return true;
+}
+
+bool GetLabelText(MCONTACT hContact, const DISPLAYITEM &di, TCHAR *buff, int bufflen)
+{
+ return ApplySubst(hContact, di.swzLabel, false, buff, bufflen);
+}
+
+bool GetValueText(MCONTACT hContact, const DISPLAYITEM &di, TCHAR *buff, int bufflen)
+{
+ return ApplySubst(hContact, di.swzValue, di.bParseTipperVarsFirst, buff, bufflen);
+}
+
+void TruncateString(TCHAR *swzText)
+{
+ if (swzText && opt.iLimitCharCount > 3) {
+ if ((int)_tcslen(swzText) > opt.iLimitCharCount) {
+ swzText[opt.iLimitCharCount - 3] = 0;
+ _tcscat(swzText, _T("..."));
+ }
+ }
+}
+
+TCHAR *GetProtoStatusMessage(char *szProto, WORD wStatus)
+{
+ if (!szProto || wStatus == ID_STATUS_OFFLINE)
+ return NULL;
+
+ // check if protocol supports status message for status
+ int flags = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0);
+ if (!(flags & Proto_Status2Flag(wStatus)))
+ return NULL;
+
+ TCHAR *swzText = (TCHAR *)CallProtoService(szProto, PS_GETMYAWAYMSG, 0, SGMA_TCHAR);
+ if ((INT_PTR)swzText == CALLSERVICE_NOTFOUND)
+ swzText = (TCHAR*)CallService(MS_AWAYMSG_GETSTATUSMSGT, wStatus, 0);
+
+ else if (swzText == NULL) {
+ // try to use service without SGMA_TCHAR
+ char *tmpMsg = (char *)CallProtoService(szProto, PS_GETMYAWAYMSG, 0, 0);
+ if (tmpMsg && (INT_PTR)tmpMsg != CALLSERVICE_NOTFOUND) {
+ swzText = mir_a2t(tmpMsg);
+ mir_free(tmpMsg);
+ }
+ }
+
+
+ if (swzText && !swzText[0]) {
+ mir_free(swzText);
+ swzText = NULL;
+ }
+
+ if (swzText && opt.bLimitMsg)
+ TruncateString(swzText);
+
+ return swzText;
+}
+
+TCHAR *GetProtoExtraStatusTitle(char *szProto)
+{
+ DBVARIANT dbv;
+ TCHAR *swzText = NULL;
+
+ if (!szProto)
+ return NULL;
+
+ if (!db_get_ts(0, szProto, "XStatusName", &dbv)) {
+ if (_tcslen(dbv.ptszVal) != 0)
+ swzText = mir_tstrdup(dbv.ptszVal);
+ db_free(&dbv);
+ }
+
+ if (!swzText) {
+ TCHAR buff[256];
+ if (EmptyXStatusToDefaultName(0, szProto, 0, buff, 256))
+ swzText = mir_tstrdup(buff);
+ }
+
+ if (opt.bLimitMsg)
+ TruncateString(swzText);
+
+ return swzText;
+}
+
+TCHAR *GetProtoExtraStatusMessage(char *szProto)
+{
+ if (!szProto)
+ return NULL;
+
+ TCHAR *swzText = NULL;
+ DBVARIANT dbv;
+ if (!db_get_ts(0, szProto, "XStatusMsg", &dbv)) {
+ if (_tcslen(dbv.ptszVal) != 0)
+ swzText = mir_tstrdup(dbv.ptszVal);
+ db_free(&dbv);
+
+ if (ServiceExists(MS_VARS_FORMATSTRING)) {
+ MCONTACT hContact = db_find_first();
+ char *proto = GetContactProto(hContact);
+ while (!proto) {
+ hContact = db_find_next(hContact);
+ if (hContact)
+ proto = GetContactProto(hContact);
+ else {
+ hContact = NULL;
+ break;
+ }
+ }
+
+ TCHAR *tszParsed = variables_parse(swzText, NULL, hContact);
+ if (tszParsed)
+ replaceStrT(swzText, tszParsed);
+ }
+ }
+
+ if (opt.bLimitMsg)
+ TruncateString(swzText);
+
+ return swzText;
+}
+
+TCHAR *GetListeningTo(char *szProto)
+{
+ DBVARIANT dbv;
+ TCHAR *swzText = NULL;
+
+ if (!szProto)
+ return NULL;
+
+ if (!db_get_ts(0, szProto, "ListeningTo", &dbv)) {
+ if (_tcslen(dbv.ptszVal) != 0)
+ swzText = mir_tstrdup(dbv.ptszVal);
+ db_free(&dbv);
+ }
+
+ if (opt.bLimitMsg)
+ TruncateString(swzText);
+
+ return swzText;
+}
+
+TCHAR *GetJabberAdvStatusText(char *szProto, const char *szSlot, const char *szValue)
+{
+ DBVARIANT dbv;
+ TCHAR *swzText = NULL;
+
+ if (!szProto)
+ return NULL;
+
+ char szSetting[128];
+ mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, szSlot, szValue);
+ if (!db_get_ts(0, "AdvStatus", szSetting, &dbv)) {
+ if (_tcslen(dbv.ptszVal) != 0)
+ swzText = mir_tstrdup(dbv.ptszVal);
+ db_free(&dbv);
+ }
+
+ if (opt.bLimitMsg)
+ TruncateString(swzText);
+
+ return swzText;
+}
+
+HICON GetJabberActivityIcon(MCONTACT hContact, char *szProto)
+{
+ DBVARIANT dbv;
+ HICON hIcon = NULL;
+
+ if (!szProto)
+ return NULL;
+
+ char szSetting[128];
+ mir_snprintf(szSetting, SIZEOF(szSetting), "%s/%s/%s", szProto, "activity", "icon");
+ if (!db_get_s(hContact, "AdvStatus", szSetting, &dbv)) {
+ hIcon = Skin_GetIcon(dbv.pszVal);
+ db_free(&dbv);
+ }
+
+ return hIcon;
} \ No newline at end of file