Beispiel #1
0
INT_PTR SendMessageCmd(MCONTACT hContact, char *msg, int isWchar)
{
	/* does the MCONTACT's protocol support IM messages? */
	char *szProto = GetContactProto(hContact);
	if (!szProto || (!CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND))
		return 1;

	hContact = db_mc_tryMeta(hContact);

	HWND hwnd = WindowList_Find(g_dat.hMessageWindowList, hContact);
	if (hwnd) {
		if (msg) {
			SendDlgItemMessage(hwnd, IDC_MESSAGE, EM_SETSEL, -1, SendDlgItemMessage(hwnd, IDC_MESSAGE, WM_GETTEXTLENGTH, 0, 0));
			if (isWchar)
				SendDlgItemMessageW(hwnd, IDC_MESSAGE, EM_REPLACESEL, FALSE, (LPARAM)msg);
			else
				SendDlgItemMessageA(hwnd, IDC_MESSAGE, EM_REPLACESEL, FALSE, (LPARAM)msg);
		}
		ShowWindow(hwnd, SW_RESTORE);
		SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
		SetForegroundWindow(hwnd);
	}
	else {
		NewMessageWindowLParam newData = { 0 };
		newData.hContact = hContact;
		newData.szInitialText = msg;
		newData.isWchar = isWchar;
		CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), NULL, DlgProcMessage, (LPARAM)&newData);
	}
	return 0;
}
Beispiel #2
0
void Nudge_ShowPopup(CNudgeElement*, MCONTACT hContact, TCHAR * Message)
{
	hContact = db_mc_tryMeta(hContact);
	TCHAR *lpzContactName = (TCHAR*)pcli->pfnGetContactDisplayName(hContact, 0);

	if (ServiceExists(MS_POPUP_ADDPOPUPCLASS)) {
		POPUPDATACLASS NudgePopup = { 0 };
		NudgePopup.cbSize = sizeof(NudgePopup);
		NudgePopup.hContact = hContact;
		NudgePopup.ptszText = Message;
		NudgePopup.ptszTitle = lpzContactName;
		NudgePopup.pszClassName = "nudge";
		CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&NudgePopup);
	}
	else if (ServiceExists(MS_POPUP_ADDPOPUPT)) {
		POPUPDATAT NudgePopup = { 0 };
		NudgePopup.lchContact = hContact;
		NudgePopup.lchIcon = IcoLib_GetIconByHandle(iconList[0].hIcolib);
		NudgePopup.colorBack = 0;
		NudgePopup.colorText = 0;
		NudgePopup.iSeconds = 0;
		NudgePopup.PluginWindowProc = NudgePopupProc;
		NudgePopup.PluginData = (void *)1;

		_tcscpy_s(NudgePopup.lptzText, Message);
		_tcscpy_s(NudgePopup.lptzContactName, lpzContactName);

		CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&NudgePopup, 0);
	}
	else MessageBox(NULL, Message, lpzContactName, 0);
}
Beispiel #3
0
static INT_PTR SendMessageCommandWorker(MCONTACT hContact, LPCSTR pszMsg, bool isWchar)
{
	hContact = db_mc_tryMeta(hContact);

	/* does the MCONTACT's protocol support IM messages? */
	char *szProto = GetContactProto(hContact);
	if (szProto == NULL)
		return 1; /* unknown contact */

	if (!CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IMSEND)
		return 1;

	HWND hwnd = WindowList_Find(g_dat.hMessageWindowList, hContact);
	if (hwnd != NULL) {
		if (pszMsg) {
			HWND hEdit = GetDlgItem(hwnd, IDC_MESSAGE);
			SendMessage(hEdit, EM_SETSEL, -1, GetWindowTextLength(hEdit));
			if (isWchar)
				SendMessageW(hEdit, EM_REPLACESEL, FALSE, (LPARAM)pszMsg);
			else
				SendMessageA(hEdit, EM_REPLACESEL, FALSE, (LPARAM)pszMsg);
		}
		SendMessage(GetParent(hwnd), CM_POPUPWINDOW, 0, (LPARAM)hwnd);
	}
	else {
		NewMessageWindowLParam newData = { 0 };
		newData.hContact = hContact;
		newData.szInitialText = pszMsg;
		newData.isWchar = isWchar;
		HWND hParent = GetParentWindow(newData.hContact, FALSE);
		CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), hParent, DlgProcMessage, (LPARAM)&newData);
	}
	return 0;
}
Beispiel #4
0
INT_PTR ShakeChat(WPARAM wParam, LPARAM lParam)
{
	if (((HANDLE)wParam) == NULL) return -1;

	//char srmmName[100];
	MessageWindowData mwd;
	MessageWindowInputData mwid;

	mwd.cbSize = sizeof(MessageWindowData);
	mwd.hContact = db_mc_tryMeta(wParam);
	mwd.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;

	mwid.cbSize = sizeof(MessageWindowInputData);
	mwid.hContact = mwd.hContact;
	mwid.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;


	CallService(MS_MSG_GETWINDOWDATA, (WPARAM)&mwid, (LPARAM)&mwd);
	//CallService(MS_MSG_GETWINDOWCLASS,(WPARAM)srmmName,(LPARAM)100 );

	HWND parent;
	HWND hWnd = mwd.hwndWindow;
	while ((parent = GetParent(hWnd)) != 0) hWnd = parent; // ensure we have the top level window (need parent window for scriver & tabsrmm)

	mir_forkthread(ShakeChatWindow, (void*)hWnd);
	return 0;
}
Beispiel #5
0
void setClistIcon(MCONTACT hContact)
{
	bool enabled = isContactSecured(hContact);
	extern HANDLE g_hCLIcon;
	MCONTACT hMC = db_mc_tryMeta(hContact);
	const char *szIconId = (enabled) ? "secured" : NULL;
	ExtraIcon_SetIcon(g_hCLIcon, hContact, szIconId);
	if(hMC != hContact)
		ExtraIcon_SetIcon(g_hCLIcon, hMC, szIconId);
}
Beispiel #6
0
static INT_PTR ReadMessageCommand(WPARAM, LPARAM lParam)
{
	CLISTEVENT *pcle = (CLISTEVENT*)lParam;
	MCONTACT hContact = db_mc_tryMeta(pcle->hContact);

	HWND hwndExisting = WindowList_Find(g_dat.hMessageWindowList, hContact);
	if (hwndExisting == NULL) {
		NewMessageWindowLParam newData = { 0 };
		newData.hContact = hContact;
		CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_MSG), GetParentWindow(hContact, FALSE), DlgProcMessage, (LPARAM)&newData);
	}
	else SendMessage(GetParent(hwndExisting), CM_POPUPWINDOW, 0, (LPARAM)hwndExisting);
	return 0;
}
Beispiel #7
0
static int TypingMessage(WPARAM hContact, LPARAM lParam)
{
	if (!(g_dat.flags2 & SMF2_SHOWTYPING))
		return 0;

	hContact = db_mc_tryMeta(hContact);

	SkinPlaySound((lParam) ? "TNStart" : "TNStop");

	HWND hwnd = WindowList_Find(g_dat.hMessageWindowList, hContact);
	if (hwnd)
		SendMessage(hwnd, DM_TYPING, 0, lParam);
	else if (lParam && (g_dat.flags2 & SMF2_SHOWTYPINGTRAY)) {
		TCHAR szTip[256];

		mir_sntprintf(szTip, TranslateT("%s is typing a message"), pcli->pfnGetContactDisplayName(hContact, 0));
		if ( ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && !(g_dat.flags2 & SMF2_SHOWTYPINGCLIST)) {
			MIRANDASYSTRAYNOTIFY tn;
			tn.szProto = NULL;
			tn.cbSize = sizeof(tn);
			tn.tszInfoTitle = TranslateT("Typing notification");
			tn.tszInfo = szTip;
			tn.dwInfoFlags = NIIF_INFO | NIIF_INTERN_UNICODE;
			tn.uTimeout = 1000 * 4;
			CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)&tn);
		}
		else {
			pcli->pfnRemoveEvent(hContact, 1);

			CLISTEVENT cle = {};
			cle.hContact = hContact;
			cle.hDbEvent = 1;
			cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
			cle.hIcon = GetCachedIcon("scriver_TYPING");
			cle.pszService = "SRMsg/TypingMessage";
			cle.ptszTooltip = szTip;
			pcli->pfnAddEvent(&cle);
		}
	}
	return 0;
}
Beispiel #8
0
static int TypingMessage(WPARAM hContact, LPARAM lParam)
{
	if (!(g_dat.flags & SMF_SHOWTYPING))
		return 0;

	hContact = db_mc_tryMeta(hContact);

	SkinPlaySound((lParam) ? "TNStart" : "TNStop");

	HWND hwnd = WindowList_Find(g_dat.hMessageWindowList, hContact);
	if (hwnd)
		SendMessage(hwnd, DM_TYPING, 0, lParam);
	else if (lParam && (g_dat.flags & SMF_SHOWTYPINGTRAY)) {
		TCHAR szTip[256];
		mir_sntprintf(szTip, TranslateT("%s is typing a message"), pcli->pfnGetContactDisplayName(hContact, 0));

		if (ServiceExists(MS_CLIST_SYSTRAY_NOTIFY) && !(g_dat.flags & SMF_SHOWTYPINGCLIST)) {
			MIRANDASYSTRAYNOTIFY tn = { sizeof(tn) };
			tn.tszInfoTitle = TranslateT("Typing notification");
			tn.tszInfo = szTip;
			tn.dwInfoFlags = NIIF_INFO;
			tn.dwInfoFlags |= NIIF_INTERN_UNICODE;
			tn.uTimeout = 1000 * 4;
			CallService(MS_CLIST_SYSTRAY_NOTIFY, 0, (LPARAM)& tn);
		}
		else {
			CLISTEVENT cle = { sizeof(cle) };
			cle.hContact = hContact;
			cle.hDbEvent = 1;
			cle.flags = CLEF_ONLYAFEW | CLEF_TCHAR;
			cle.hIcon = Skin_LoadIcon(SKINICON_OTHER_TYPING);
			cle.pszService = "SRMsg/ReadMessage";
			cle.ptszTooltip = szTip;
			CallServiceSync(MS_CLIST_REMOVEEVENT, hContact, 1);
			CallServiceSync(MS_CLIST_ADDEVENT, hContact, (LPARAM)&cle);
			IcoLib_ReleaseIcon(cle.hIcon);
		}
	}
	return 0;
}
Beispiel #9
0
void setSrmmIcon(MCONTACT h)
{
	MCONTACT hContact = db_mc_isMeta(h) ? metaGetMostOnline(h) : h;
	bool enabled = isContactSecured(hContact);	
	MCONTACT hMC = db_mc_tryMeta(hContact);

	StatusIconData sid = { sizeof(sid) };
	sid.szModule = szGPGModuleName;
	sid.hIcon = IcoLib_GetIcon("secured");
	sid.dwId = 1;
	sid.flags = enabled ? 0 : MBF_HIDDEN;
	Srmm_ModifyIcon(hContact, &sid);
	if(hMC != hContact)
		Srmm_ModifyIcon(hMC, &sid);

	sid.hIcon = IcoLib_GetIcon("unsecured");
	sid.dwId = 2;
	sid.flags = enabled ? MBF_HIDDEN : 0;
	Srmm_ModifyIcon(hContact, &sid);
	if(hMC != hContact)
		Srmm_ModifyIcon(hMC, &sid);
}
Beispiel #10
0
void GetContactReceivedFilesDir(MCONTACT hContact, TCHAR *szDir, int cchDir, BOOL patchVars)
{
	TCHAR tszTemp[MAX_PATH];

	ptrT tszRecvPath(db_get_tsa(NULL, "SRFile", "RecvFilesDirAdv"));
	if (tszRecvPath)
		_tcsncpy_s(tszTemp, tszRecvPath, _TRUNCATE);
	else
		mir_sntprintf(tszTemp, _T("%%mydocuments%%\\%s\\%%userid%%"), TranslateT("My received files"));

	if (hContact) {
		hContact = db_mc_tryMeta(hContact);

		REPLACEVARSARRAY rvaVarsToReplace[4];
		rvaVarsToReplace[0].key.t = _T("nick");
		rvaVarsToReplace[0].value.t = mir_tstrdup((TCHAR *)pcli->pfnGetContactDisplayName(hContact, 0));
		rvaVarsToReplace[1].key.t = _T("userid");
		rvaVarsToReplace[1].value.t = GetContactID(hContact);
		rvaVarsToReplace[2].key.t = _T("proto");
		rvaVarsToReplace[2].value.t = mir_a2t(GetContactProto(hContact));
		rvaVarsToReplace[3].key.t = NULL;
		rvaVarsToReplace[3].value.t = NULL;
		for (int i = 0; i < (_countof(rvaVarsToReplace) - 1); i++)
			RemoveInvalidFilenameChars(rvaVarsToReplace[i].value.t);

		TCHAR *result = Utils_ReplaceVarsT(tszTemp, hContact, rvaVarsToReplace);
		if (result) {
			_tcsncpy(tszTemp, result, _countof(tszTemp));
			mir_free(result);
			for (int i = 0; i < (_countof(rvaVarsToReplace) - 1); i++)
				mir_free(rvaVarsToReplace[i].value.t);
		}
	}

	if (patchVars)
		patchDir(tszTemp, _countof(tszTemp));
	RemoveInvalidPathChars(tszTemp);
	mir_tstrncpy(szDir, tszTemp, cchDir);
}
Beispiel #11
0
LRESULT CALLBACK ContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	ClcContact *contact;
	ClcGroup *group;
	BOOL frameHasTitlebar = FALSE;

	if (wndFrameCLC)
		frameHasTitlebar = wndFrameCLC->TitleBar.ShowTitleBar;

	ClcData *dat = (struct ClcData *)GetWindowLongPtr(hwnd, 0);
	if (msg >= CLM_FIRST && msg < CLM_LAST)
		return ProcessExternalMessages(hwnd, dat, msg, wParam, lParam);

	switch (msg) {
	case WM_CREATE:
		dat = (struct ClcData *)mir_calloc(sizeof(struct ClcData));
		SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat);

		RowHeight::Init(dat);
		dat->forceScroll = 0;
		dat->lastRepaint = 0;
		dat->hwndParent = GetParent(hwnd);
		dat->lastSort = GetTickCount();
		dat->needsResort = FALSE;
		{
			CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
			if (cs->lpCreateParams == (LPVOID)0xff00ff00) {
				dat->bisEmbedded = FALSE;
				dat->bHideSubcontacts = TRUE;
				cfg::clcdat = dat;
				if (cfg::dat.bShowLocalTime)
					SetTimer(hwnd, TIMERID_REFRESH, 65000, NULL);
			}
			else
				dat->bisEmbedded = TRUE;
		}
		break;

	case WM_SIZE:
		pcli->pfnEndRename(hwnd, dat, 1);
		KillTimer(hwnd, TIMERID_INFOTIP);
		KillTimer(hwnd, TIMERID_RENAME);
		pcli->pfnRecalcScrollBar(hwnd, dat);
LBL_Def:
		return DefWindowProc(hwnd, msg, wParam, lParam);

	case WM_NCCALCSIZE:
		return FrameNCCalcSize(hwnd, DefWindowProc, wParam, lParam, frameHasTitlebar);

		/*
		* scroll bar handling
		*/
	case WM_NCPAINT:
		return FrameNCPaint(hwnd, DefWindowProc, wParam, lParam, frameHasTitlebar);

	case INTM_GROUPCHANGED:
		{
			WORD iExtraImage[EXTRA_ICON_COUNT];
			BYTE flags = 0;
			if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
				memset(iExtraImage, 0xFF, sizeof(iExtraImage));
			else {
				memcpy(iExtraImage, contact->iExtraImage, sizeof(iExtraImage));
				flags = contact->flags;
			}
			pcli->pfnDeleteItemFromTree(hwnd, wParam);
			if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !CLVM_GetContactHiddenStatus(wParam, NULL, dat)) {
				pcli->pfnAddContactToTree(hwnd, dat, wParam, 1, 1);
				if (FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL)) {
					memcpy(contact->iExtraImage, iExtraImage, sizeof(iExtraImage));
					if (flags & CONTACTF_CHECKED)
						contact->flags |= CONTACTF_CHECKED;
				}

				NMCLISTCONTROL nm;
				nm.hdr.code = CLN_CONTACTMOVED;
				nm.hdr.hwndFrom = hwnd;
				nm.hdr.idFrom = GetDlgCtrlID(hwnd);
				nm.flags = 0;
				nm.hItem = (HANDLE)wParam;
				SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm);
			}
			dat->needsResort = TRUE;
			PostMessage(hwnd, INTM_SORTCLC, 0, 1);
		}
		goto LBL_Def;

	case INTM_ICONCHANGED:
		{
			int recalcScrollBar = 0;
			MCONTACT hContact = wParam;
			WORD status = ID_STATUS_OFFLINE;
			int  contactRemoved = 0;
			MCONTACT hSelItem = NULL;
			ClcContact *selcontact = NULL;

			char *szProto = GetContactProto(hContact);
			if (szProto == NULL)
				status = ID_STATUS_OFFLINE;
			else
				status = cfg::getWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);

			int shouldShow = (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN ||
				!CLVM_GetContactHiddenStatus(hContact, szProto, dat)) && ((cfg::dat.bFilterEffective ? TRUE : !pcli->pfnIsHiddenMode(dat, status)) ||
				pcli->pfnGetContactIcon(hContact) != lParam); // XXX CLVM changed - this means an offline msg is flashing, so the contact should be shown

			if (!FindItem(hwnd, dat, (HANDLE)hContact, &contact, &group, NULL)) {
				if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) {
					if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
						hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
					pcli->pfnAddContactToTree(hwnd, dat, hContact, 0, 0);
					recalcScrollBar = 1;
					FindItem(hwnd, dat, (HANDLE)hContact, &contact, NULL, NULL);
					if (contact) {
						contact->iImage = (WORD)lParam;
						pcli->pfnNotifyNewContact(hwnd, hContact);
					}
				}
			}
			else {
				//item in list already
				DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
				if (contact->iImage == (WORD)lParam)
					break;
				if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline || cfg::dat.bFilterEffective)) {        // CLVM changed
					if (dat->selection >= 0 && pcli->pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
						hSelItem = (MCONTACT)pcli->pfnContactToHItem(selcontact);
					pcli->pfnRemoveItemFromGroup(hwnd, group, contact, 0);
					contactRemoved = TRUE;
					recalcScrollBar = 1;
				}
				else {
					contact->iImage = (WORD)lParam;
					if (!pcli->pfnIsHiddenMode(dat, status))
						contact->flags |= CONTACTF_ONLINE;
					else
						contact->flags &= ~CONTACTF_ONLINE;
				}
			}
			if (hSelItem) {
				ClcGroup *selgroup;
				if (pcli->pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
					dat->selection = pcli->pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)& selgroup->cl, selcontact));
				else
					dat->selection = -1;
			}
			dat->needsResort = TRUE;
			PostMessage(hwnd, INTM_SORTCLC, 0, recalcScrollBar);
			PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contactRemoved ? 0 : wParam));
			if (recalcScrollBar)
				pcli->pfnRecalcScrollBar(hwnd, dat);
		}
		goto LBL_Def;

	case INTM_METACHANGED:
		if (!pcli->pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL))
			break;

		if (contact->bIsMeta && !(cfg::dat.dwFlags & CLUI_USEMETAICONS)) {
			contact->hSubContact = db_mc_getMostOnline(contact->hContact);
			contact->metaProto = GetContactProto(contact->hSubContact);
			contact->iImage = pcli->pfnGetContactIcon(contact->hSubContact);
			if (contact->pExtra) {
				TExtraCache *pSub = cfg::getCache(contact->hSubContact, contact->metaProto);
				ClcContact *subContact;
				if (!pcli->pfnFindItem(hwnd, dat, contact->hSubContact, &subContact, NULL, NULL))
					break;

				contact->pExtra->proto_status_item = GetProtocolStatusItem(contact->metaProto);
				if (pSub) {
					contact->pExtra->status_item = pSub->status_item;
					memcpy(contact->iExtraImage, subContact->iExtraImage, sizeof(contact->iExtraImage));
				}
			}
		}
		SendMessage(hwnd, INTM_NAMEORDERCHANGED, wParam, lParam);
		goto LBL_Def;

	case INTM_METACHANGEDEVENT:
		if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
			break;
		if (lParam == 0)
			pcli->pfnInitAutoRebuild(hwnd);
		goto LBL_Def;

	case INTM_NAMECHANGED:
		ClcContact *contact;
		if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
			break;
		mir_tstrncpy(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), SIZEOF(contact->szText));

		RTL_DetectAndSet(contact, 0);

		dat->needsResort = TRUE;
		PostMessage(hwnd, INTM_SORTCLC, 0, 0);
		goto LBL_Def;

	case INTM_CODEPAGECHANGED:
		if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
			break;
		contact->codePage = cfg::getDword(wParam, "Tab_SRMsg", "ANSIcodepage", cfg::getDword(wParam, "UserInfo", "ANSIcodepage", CP_ACP));
		PostMessage(hwnd, INTM_INVALIDATE, 0, 0);
		goto LBL_Def;

	case INTM_AVATARCHANGED:
		contact = NULL;
		{
			avatarCacheEntry *cEntry = (struct avatarCacheEntry *)lParam;

			if (wParam == 0) {
				//RemoveFromImgCache(0, cEntry);
				cfg::dat.bForceRefetchOnPaint = TRUE;
				RedrawWindow(hwnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
				cfg::dat.bForceRefetchOnPaint = FALSE;
				goto LBL_Def;
			}

			if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
				return 0;
			contact->ace = cEntry;
			if (cEntry == NULL)
				contact->cFlags &= ~ECF_AVATAR;
			else {
				DWORD dwFlags;

				if (contact->pExtra)
					dwFlags = contact->pExtra->dwDFlags;
				else
					dwFlags = cfg::getDword(contact->hContact, "CList", "CLN_Flags", 0);
				if (cfg::dat.dwFlags & CLUI_FRAME_AVATARS)
					contact->cFlags = (dwFlags & ECF_HIDEAVATAR ? contact->cFlags & ~ECF_AVATAR : contact->cFlags | ECF_AVATAR);
				else
					contact->cFlags = (dwFlags & ECF_FORCEAVATAR ? contact->cFlags | ECF_AVATAR : contact->cFlags & ~ECF_AVATAR);
			}
			PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)contact->hContact);
		}
		goto LBL_Def;

	case INTM_STATUSMSGCHANGED:
		{
			TExtraCache *p;
			char *szProto = NULL;

			if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
				p = cfg::getCache(wParam, NULL);
			else {
				p = contact->pExtra;
				szProto = contact->proto;
			}
			GetCachedStatusMsg(p, szProto);
			PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contact ? contact->hContact : 0));
		}
		goto LBL_Def;

	case INTM_STATUSCHANGED:
		if (FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL)) {
			WORD wStatus = cfg::getWord(wParam, contact->proto, "Status", ID_STATUS_OFFLINE);
			if (cfg::dat.bNoOfflineAvatars && wStatus != ID_STATUS_OFFLINE && contact->wStatus == ID_STATUS_OFFLINE) {
				contact->wStatus = wStatus;
				if (cfg::dat.bAvatarServiceAvail && contact->ace == NULL)
					LoadAvatarForContact(contact);
			}
			contact->wStatus = wStatus;
			goto LBL_Def;
		}
		break;

	case INTM_PROTOCHANGED:
		if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL))
			break;

		contact->proto = GetContactProto(wParam);
		CallService(MS_CLIST_INVALIDATEDISPLAYNAME, wParam, 0);
		mir_tstrncpy(contact->szText, pcli->pfnGetContactDisplayName(wParam, 0), SIZEOF(contact->szText));

		RTL_DetectAndSet(contact, 0);

		dat->needsResort = TRUE;
		PostMessage(hwnd, INTM_SORTCLC, 0, 0);
		goto LBL_Def;

	case INTM_INVALIDATE:
		if (!dat->bNeedPaint) {
			KillTimer(hwnd, TIMERID_PAINT);
			SetTimer(hwnd, TIMERID_PAINT, 100, NULL);
			dat->bNeedPaint = TRUE;
		}
		goto LBL_Def;

	case INTM_INVALIDATECONTACT:
		if (!FindItem(hwnd, dat, (HANDLE)wParam, &contact, &group, NULL))
			break;

		if (contact && group) {
			int iItem = pcli->pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*) & group->cl, contact));
			pcli->pfnInvalidateItem(hwnd, dat, iItem);
			goto LBL_Def;
		}
		break;

	case INTM_FORCESORT:
		dat->needsResort = TRUE;
		return SendMessage(hwnd, INTM_SORTCLC, wParam, lParam);

	case INTM_SORTCLC:
		if (dat->needsResort) {
			pcli->pfnSortCLC(hwnd, dat, TRUE);
			dat->needsResort = FALSE;
		}
		if (lParam)
			pcli->pfnRecalcScrollBar(hwnd, dat);
		goto LBL_Def;

	case INTM_IDLECHANGED:
		if (FindItem(hwnd, dat, (HANDLE)wParam, &contact, NULL, NULL)) {
			DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
			char *szProto = (char*)cws->szModule;
			if (szProto == NULL)
				break;

			contact->flags &= ~CONTACTF_IDLE;
			if (cfg::getDword(wParam, szProto, "IdleTS", 0)) {
				contact->flags |= CONTACTF_IDLE;
			}
			PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)contact->hContact);
			goto LBL_Def;
		}
		break;

	case INTM_XSTATUSCHANGED:
		{
			DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
			char *szProto = (char *)cws->szModule;
			MCONTACT hContact = wParam;
			TExtraCache *p;

			if (!FindItem(hwnd, dat, (HANDLE)hContact, &contact, NULL, NULL)) {
				p = cfg::getCache(hContact, szProto);
				if (!dat->bisEmbedded && szProto) {				// may be a subcontact, forward the xstatus
					MCONTACT hMasterContact = db_mc_tryMeta(hContact);
					if (hMasterContact != hContact)				// avoid recursive call of settings handler
						cfg::writeByte(hMasterContact, META_PROTO, "XStatusId", (BYTE)cfg::getByte(hContact, szProto, "XStatusId", 0));
					break;
				}
			}
			else {
				contact->xStatus = cfg::getByte(hContact, szProto, "XStatusId", 0);
				p = contact->pExtra;
			}

			if (szProto == NULL)
				break;

			if (contact) {
				if (ProtoServiceExists(szProto, PS_GETADVANCEDSTATUSICON)) {
					int iconId = ProtoCallService(szProto, PS_GETADVANCEDSTATUSICON, hContact, 0);
					if (iconId != -1)
						contact->xStatusIcon = iconId >> 16;
				}
			}

			GetCachedStatusMsg(p, szProto);
			PostMessage(hwnd, INTM_INVALIDATE, 0, (LPARAM)(contact ? contact->hContact : 0));
		}
		goto LBL_Def;

	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			HDC hdc = BeginPaint(hwnd, &ps);
			if (IsWindowVisible(hwnd) && !during_sizing && !cfg::shutDown) {
				PaintClc(hwnd, dat, hdc, &ps.rcPaint);
				dat->bNeedPaint = FALSE;
				dat->lastRepaint = GetTickCount();
			}
			EndPaint(hwnd, &ps);
			if (dat->selection != dat->oldSelection && !dat->bisEmbedded && g_ButtonItems != NULL) {
				SetDBButtonStates(0);
				dat->oldSelection = dat->selection;
			}
		}
		goto LBL_Def;

	case WM_MOUSEWHEEL:
		dat->forceScroll = TRUE;
		break;

	case WM_TIMER:
		if (wParam == TIMERID_PAINT) {
			KillTimer(hwnd, TIMERID_PAINT);
			InvalidateRect(hwnd, NULL, FALSE);
			goto LBL_Def;
		}

		if (wParam == TIMERID_REFRESH) {
			InvalidateRect(hwnd, NULL, FALSE);
			goto LBL_Def;
		}
		break;

	case WM_LBUTTONDBLCLK:
		ReleaseCapture();
		dat->iHotTrack = -1;
		pcli->pfnHideInfoTip(hwnd, dat);
		KillTimer(hwnd, TIMERID_RENAME);
		KillTimer(hwnd, TIMERID_INFOTIP);
		dat->szQuickSearch[0] = 0;
		{
			DWORD hitFlags;
			dat->selection = HitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
			if (hitFlags & CLCHT_ONITEMEXTRA)
				break;

			InvalidateRect(hwnd, NULL, FALSE);
			if (dat->selection != -1)
				pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
			if (hitFlags & CLCHT_ONAVATAR && cfg::dat.bDblClkAvatars) {
				CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)contact->hContact, 0);
				return TRUE;
			}
			if (hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMSPACE)) {
				UpdateWindow(hwnd);
				pcli->pfnDoSelectionDefaultAction(hwnd, dat);
			}
		}
		return TRUE;

	case WM_CONTEXTMENU:
		{
			HMENU hMenu = NULL;
			POINT pt;
			DWORD hitFlags;

			pcli->pfnEndRename(hwnd, dat, 1);
			pcli->pfnHideInfoTip(hwnd, dat);
			KillTimer(hwnd, TIMERID_RENAME);
			KillTimer(hwnd, TIMERID_INFOTIP);
			if (GetFocus() != hwnd)
				SetFocus(hwnd);
			dat->iHotTrack = -1;
			dat->szQuickSearch[0] = 0;
			pt.x = (short) LOWORD(lParam);
			pt.y = (short) HIWORD(lParam);
			if (pt.x == -1 && pt.y == -1) {
				dat->selection = pcli->pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
				if (dat->selection != -1)
					pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
				pt.x = dat->iconXSpace + 15;
				pt.y = RowHeight::getItemTopY(dat, dat->selection) - dat->yScroll + (int)(dat->row_heights[dat->selection] * .7);
				hitFlags = dat->selection == -1 ? CLCHT_NOWHERE : CLCHT_ONITEMLABEL;
			}
			else {
				ScreenToClient(hwnd, &pt);
				dat->selection = HitTest(hwnd, dat, pt.x, pt.y, &contact, NULL, &hitFlags);
			}
			InvalidateRect(hwnd, NULL, FALSE);
			if (dat->selection != -1)
				pcli->pfnEnsureVisible(hwnd, dat, dat->selection, 0);
			UpdateWindow(hwnd);

			if (dat->selection != -1 && hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMCHECK | CLCHT_ONITEMLABEL)) {
				if (contact->type == CLCIT_GROUP) {
					hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDSUBGROUP, (WPARAM)contact->group, 0);
					ClientToScreen(hwnd, &pt);
					TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, pcli->hwndContactList, NULL);
					CheckMenuItem(hMenu, POPUP_GROUPHIDEOFFLINE, contact->group->hideOffline ? MF_CHECKED : MF_UNCHECKED);
					DestroyMenu(hMenu);
					return 0;
				} else if (contact->type == CLCIT_CONTACT)
					hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) contact->hContact, 0);
			} else {
				//call parent for new group/hide offline menu
				PostMessage(GetParent(hwnd), WM_CONTEXTMENU, wParam, lParam);
				return 0;
			}
			if (hMenu != NULL) {
				ClientToScreen(hwnd, &pt);
				TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
				DestroyMenu(hMenu);
			}
		}
		return 0;

	case WM_COMMAND:
		if (LOWORD(wParam) == POPUP_NEWGROUP)
			SendMessage(GetParent(hwnd), msg, wParam, lParam);
		break;

	case WM_NCHITTEST:
		{
			LRESULT lr = SendMessage(GetParent(hwnd), WM_NCHITTEST, wParam, lParam);
			if (lr == HTLEFT || lr == HTRIGHT || lr == HTBOTTOM || lr == HTTOP || lr == HTTOPLEFT || lr == HTTOPRIGHT
				|| lr == HTBOTTOMLEFT || lr == HTBOTTOMRIGHT)
				return HTTRANSPARENT;
		}
		break;

	case WM_DESTROY:
		RowHeight::Free(dat);
		break;
	}

	return coreCli.pfnContactListControlWndProc(hwnd, msg, wParam, lParam);
}