/*
Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
Copyright (c) 2012-2013 Miranda NG Team
Copyright (c) 2006-2012 Boris Krasnovskiy.
Copyright (c) 2003-2005 George Hazan.
Copyright (c) 2002-2003 Richard Hughes (original version).
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "msn_global.h"
#include "msn_proto.h"
#include "m_smileyadd.h"
void CMsnProto::Lists_Init(void)
{
InitializeCriticalSection(&csLists);
}
void CMsnProto::Lists_Uninit(void)
{
Lists_Wipe();
DeleteCriticalSection(&csLists);
}
void CMsnProto::Lists_Wipe(void)
{
EnterCriticalSection(&csLists);
contList.destroy();
LeaveCriticalSection(&csLists);
}
bool CMsnProto::Lists_IsInList(int list, const char* email)
{
EnterCriticalSection(&csLists);
MsnContact* p = contList.find((MsnContact*)&email);
bool res = p != NULL;
if (res && list != -1)
res &= ((p->list & list) == list);
LeaveCriticalSection(&csLists);
return res;
}
MsnContact* CMsnProto::Lists_Get(const char* email)
{
EnterCriticalSection(&csLists);
MsnContact* p = contList.find((MsnContact*)&email);
LeaveCriticalSection(&csLists);
return p;
}
MsnContact* CMsnProto::Lists_Get(HANDLE hContact)
{
EnterCriticalSection(&csLists);
MsnContact* p = NULL;
for (int i = 0; i < contList.getCount(); ++i)
{
if (contList[i].hContact == hContact)
{
p = &contList[i];
break;
}
}
LeaveCriticalSection(&csLists);
return p;
}
MsnPlace* CMsnProto::Lists_GetPlace(const char* wlid)
{
EnterCriticalSection(&csLists);
char *szEmail, *szInst;
parseWLID(NEWSTR_ALLOCA(wlid), NULL, &szEmail, &szInst);
if (szInst == NULL) szInst = (char*)sttVoidUid;
MsnPlace* pl = NULL;
MsnContact* p = contList.find((MsnContact*)&szEmail);
if (p) pl = p->places.find((MsnPlace*)&szInst);
LeaveCriticalSection(&csLists);
return pl;
}
MsnPlace* CMsnProto::Lists_AddPlace(const char* email, const char* id, unsigned cap1, unsigned cap2)
{
EnterCriticalSection(&csLists);
MsnPlace* pl = NULL;
MsnContact* p = contList.find((MsnContact*)&email);
if (p)
{
pl = p->places.find((MsnPlace*)&id);
if (!pl) {
pl = new MsnPlace;
pl->id = mir_strdup(id);
pl->cap1 = cap1;
pl->cap2 = cap2;
pl->p2pMsgId = 0;
pl->p2pPktNum = 0;
p->places.insert(pl);
}
}
LeaveCriticalSection(&csLists);
return pl;
}
MsnContact* CMsnProto::Lists_GetNext(int& i)
{
MsnContact* p = NULL;
EnterCriticalSection(&csLists);
while (p == NULL && ++i < contList.getCount())
{
if (contList[i].hContact) p = &contList[i];
}
LeaveCriticalSection(&csLists);
return p;
}
int CMsnProto::Lists_GetMask(const char* email)
{
EnterCriticalSection(&csLists);
MsnContact* p = contList.find((MsnContact*)&email);
int res = p ? p->list : 0;
LeaveCriticalSection(&csLists);
return res;
}
int CMsnProto::Lists_GetNetId(const char* email)
{
if (email[0] == 0) return NETID_UNKNOWN;
EnterCriticalSection(&csLists);
MsnContact* p = contList.find((MsnContact*)&email);
int res = p ? p->netId : NETID_UNKNOWN;
LeaveCriticalSection(&csLists);
return res;
}
unsigned CMsnProto::p2p_getMsgId(const char* wlid, int inc)
{
EnterCriticalSection(&csLists);
MsnPlace* p = Lists_GetPlace(wlid);
unsigned res = p && p->p2pMsgId ? p->p2pMsgId : MSN_GenRandom();
if (p) p->p2pMsgId = res + inc;
LeaveCriticalSection(&csLists);
return res;
}
unsigned CMsnProto::p2p_getPktNum(const char* wlid)
{
EnterCriticalSection(&csLists);
MsnPlace* p = Lists_GetPlace(wlid);
unsigned res = p ? p->p2pPktNum++ : 0;
LeaveCriticalSection(&csLists);
return res;
}
int CMsnProto::Lists_Add(int list, int netId, const char* email, HANDLE hContact, const char* nick, const char* invite)
{
EnterCriticalSection(&csLists);
MsnContact* p = contList.find((MsnContact*)&email);
if (p == NULL)
{
p = new MsnContact;
p->list = list;
p->netId = netId;
p->email = _strlwr(mir_strdup(email));
p->invite = mir_strdup(invite);
p->nick = mir_strdup(nick);
p->hContact = hContact;
p->p2pMsgId = 0;
contList.insert(p);
}
else
{
p->list |= list;
if (invite) replaceStr(p->invite, invite);
if (hContact) p->hContact = hContact;
if (list & LIST_FL) p->netId = netId;
if (p->netId == NETID_UNKNOWN && netId != NETID_UNKNOWN)
p->netId = netId;
}
int result = p->list;
LeaveCriticalSection(&csLists);
return result;
}
void CMsnProto::Lists_Remove(int list, const char* email)
{
EnterCriticalSection(&csLists);
int i = contList.getIndex((MsnContact*)&email);
if (i != -1)
{
MsnContact& p = contList[i];
p.list &= ~list;
if (list & LIST_PL) { mir_free(p.invite); p.invite = NULL; }
if (p.list == 0 && p.hContact == NULL)
contList.remove(i);
}
LeaveCriticalSection(&csLists);
}
void CMsnProto::Lists_Populate(void)
{
HANDLE hContact = db_find_first();
while (hContact != NULL)
{
HANDLE hContactN = db_find_next(hContact);
if (MSN_IsMyContact(hContact))
{
char szEmail[MSN_MAX_EMAIL_LEN] = "";;
if (getStaticString(hContact, "wlid", szEmail, sizeof(szEmail)))
getStaticString(hContact, "e-mail", szEmail, sizeof(szEmail));
if (szEmail[0])
{
bool localList = getByte(hContact, "LocalList", 0) != 0;
if (localList)
Lists_Add(LIST_LL, NETID_MSN, szEmail, hContact);
else
Lists_Add(0, NETID_UNKNOWN, szEmail, hContact);
}
else
CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0);
}
hContact = hContactN;
}
}
void CMsnProto::MSN_CleanupLists(void)
{
for (int i=contList.getCount(); i--;) {
MsnContact& p = contList[i];
if (p.list & LIST_FL)
MSN_SetContactDb(p.hContact, p.email);
if (p.list & LIST_PL) {
if (p.list & (LIST_AL | LIST_BL))
MSN_AddUser(NULL, p.email, p.netId, LIST_PL + LIST_REMOVE);
else
MSN_AddAuthRequest(p.email, p.nick, p.invite);
}
if (p.hContact && !(p.list & (LIST_LL | LIST_FL | LIST_PL)) && p.list != LIST_RL) {
int count = db_event_count(p.hContact);
if (count) {
TCHAR text[256];
TCHAR *sze = mir_a2t(p.email);
mir_sntprintf(text, SIZEOF(text), TranslateT("Contact %s has been removed from the server.\nWould you like to keep it as \"Local Only\" contact to preserve history?"), sze);
mir_free(sze);
TCHAR title[128];
mir_sntprintf(title, SIZEOF(title), TranslateT("%s protocol"), m_tszUserName);
if (MessageBox(NULL, text, title, MB_YESNO | MB_ICONQUESTION | MB_SETFOREGROUND) == IDYES) {
MSN_AddUser(p.hContact, p.email, 0, LIST_LL);
setByte(p.hContact, "LocalList", 1);
continue;
}
}
if (!(p.list & (LIST_LL | LIST_FL))) {
CallService(MS_DB_CONTACT_DELETE, (WPARAM)p.hContact, 0);
p.hContact = NULL;
}
}
if (p.list & (LIST_LL | LIST_FL) && p.hContact) {
TCHAR path[MAX_PATH];
MSN_GetCustomSmileyFileName(p.hContact, path, SIZEOF(path), "", 0);
if (path[0]) {
SMADD_CONT cont;
cont.cbSize = sizeof(SMADD_CONT);
cont.hContact = p.hContact;
cont.type = 0;
cont.path = path;
CallService(MS_SMILEYADD_LOADCONTACTSMILEYS, 0, (LPARAM)&cont);
}
}
}
}
void CMsnProto::MSN_CreateContList(void)
{
bool *used = (bool*)mir_calloc(contList.getCount()*sizeof(bool));
char cxml[8192];
size_t sz;
sz = mir_snprintf(cxml , sizeof(cxml), "");
EnterCriticalSection(&csLists);
for (int i=0; i < contList.getCount(); i++)
{
if (used[i]) continue;
const char* lastds = strchr(contList[i].email, '@');
bool newdom = true;
for (int j=0; j < contList.getCount(); j++)
{
if (used[j]) continue;
const MsnContact& C = contList[j];
if (C.list == LIST_RL || C.list == LIST_PL || C.list == LIST_LL)
{
used[j] = true;
continue;
}
const char* dom = strchr(C.email, '@');
if (dom == NULL && lastds == NULL)
{
if (sz == 0) sz = mir_snprintf(cxml+sz, sizeof(cxml), "");
if (newdom)
{
sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, "");
newdom = false;
}
sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, "", C.email, C.list & ~(LIST_RL | LIST_LL));
used[j] = true;
}
else if (dom != NULL && lastds != NULL && _stricmp(lastds, dom) == 0)
{
if (sz == 0) sz = mir_snprintf(cxml, sizeof(cxml), "");
if (newdom)
{
sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, "", lastds+1);
newdom = false;
}
*(char*)dom = 0;
sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, "", C.email, C.list & ~(LIST_RL | LIST_LL), C.netId);
*(char*)dom = '@';
used[j] = true;
}
if (used[j] && sz > 7400)
{
sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, "%c>", lastds ? 'd' : 't');
msnNsThread->sendPacket("ADL", "%d\r\n%s", sz, cxml);
sz = 0;
newdom = true;
}
}
if (!newdom) sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, lastds ? "" : "");
}
LeaveCriticalSection(&csLists);
if (sz)
{
sz += mir_snprintf(cxml+sz, sizeof(cxml)-sz, "");
msnNsThread->sendPacket("ADL", "%d\r\n%s", sz, cxml);
}
mir_free(used);
}
/////////////////////////////////////////////////////////////////////////////////////////
// MSN Server List Manager dialog procedure
static void AddPrivacyListEntries(HWND hwndList, CMsnProto *proto)
{
CLCINFOITEM cii = {0};
cii.cbSize = sizeof(cii);
cii.flags = CLCIIF_BELOWCONTACTS;
// Delete old info
HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
while (hItem)
{
HANDLE hItemNext = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
if (IsHContactInfo(hItem))
SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
hItem = hItemNext;
}
// Add new info
for (int i=0; icontList.getCount(); ++i)
{
MsnContact &cont = proto->contList[i];
if (!(cont.list & (LIST_FL | LIST_LL)))
{
cii.pszText = (TCHAR*)cont.email;
HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_ADDINFOITEMA, 0, (LPARAM)&cii);
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0,(cont.list & LIST_LL)?1:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1,(cont.list & LIST_FL)?2:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2,(cont.list & LIST_AL)?3:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3,(cont.list & LIST_BL)?4:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(4,(cont.list & LIST_RL)?5:0));
}
}
}
static void ResetListOptions(HWND hwndList)
{
SendMessage(hwndList, CLM_SETBKBITMAP, 0, 0);
SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0);
SendMessage(hwndList, CLM_SETLEFTMARGIN, 2, 0);
SendMessage(hwndList, CLM_SETINDENT, 10, 0);
for (int i=0; i<=FONTID_MAX; i++)
SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT));
}
static void SetContactIcons(HANDLE hItem, HWND hwndList, CMsnProto* proto)
{
if (!proto->MSN_IsMyContact(hItem)) {
SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
return;
}
char szEmail[MSN_MAX_EMAIL_LEN];
if (proto->getStaticString(hItem, "e-mail", szEmail, sizeof(szEmail))) {
SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0);
return;
}
DWORD dwMask = proto->Lists_GetMask(szEmail);
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0,(dwMask & LIST_LL)?1:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1,(dwMask & LIST_FL)?2:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2,(dwMask & LIST_AL)?3:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3,(dwMask & LIST_BL)?4:0));
SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(4,(dwMask & LIST_RL)?5:0));
}
static void SetAllContactIcons(HANDLE hItem, HWND hwndList, CMsnProto* proto)
{
if (hItem == NULL)
hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
while (hItem)
{
HANDLE hItemN = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
if (IsHContactGroup(hItem))
{
HANDLE hItemT = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
if (hItemT) SetAllContactIcons(hItemT, hwndList, proto);
}
else if (IsHContactContact(hItem))
{
SetContactIcons(hItem, hwndList, proto);
}
hItem = hItemN;
}
}
static void SaveListItem(HANDLE hContact, const char* szEmail, int list, int iPrevValue, int iNewValue, CMsnProto* proto)
{
if (iPrevValue == iNewValue)
return;
if (iNewValue == 0)
{
if (list & LIST_FL)
{
DeleteParam param = { proto, hContact };
DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DELETECONTACT), NULL, DlgDeleteContactUI, (LPARAM)¶m);
return;
}
list |= LIST_REMOVE;
}
proto->MSN_AddUser(hContact, szEmail, proto->Lists_GetNetId(szEmail), list);
}
static void SaveSettings(HANDLE hItem, HWND hwndList, CMsnProto* proto)
{
if (hItem == NULL)
hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0);
while (hItem)
{
if (IsHContactGroup(hItem))
{
HANDLE hItemT = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
if (hItemT) SaveSettings(hItemT, hwndList, proto);
}
else
{
char szEmail[MSN_MAX_EMAIL_LEN];
if (IsHContactContact(hItem))
{
if (proto->getStaticString(hItem, "e-mail", szEmail, sizeof(szEmail))) continue;
}
else if (IsHContactInfo(hItem))
{
TCHAR buf[MSN_MAX_EMAIL_LEN];
SendMessage(hwndList, CLM_GETITEMTEXT, (WPARAM)hItem, (LPARAM)buf);
WideCharToMultiByte(CP_ACP, 0, buf, -1, szEmail, sizeof(szEmail), 0, 0);
}
int dwMask = proto->Lists_GetMask(szEmail);
SaveListItem(hItem, szEmail, LIST_LL, (dwMask & LIST_LL)?1:0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0,0)), proto);
SaveListItem(hItem, szEmail, LIST_FL, (dwMask & LIST_FL)?2:0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1,0)), proto);
SaveListItem(hItem, szEmail, LIST_AL, (dwMask & LIST_AL)?3:0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2,0)), proto);
SaveListItem(hItem, szEmail, LIST_BL, (dwMask & LIST_BL)?4:0, SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3,0)), proto);
int newMask = proto->Lists_GetMask(szEmail);
int xorMask = newMask ^ dwMask;
if (xorMask && newMask & (LIST_FL | LIST_LL))
{
HANDLE hContact = IsHContactInfo(hItem) ? proto->MSN_HContactFromEmail(szEmail, szEmail, true, false) : hItem;
proto->MSN_SetContactDb(hContact, szEmail);
}
if (xorMask & (LIST_FL | LIST_LL) && !(newMask & (LIST_FL | LIST_LL)))
{
if (!IsHContactInfo(hItem))
{
CallService(MS_DB_CONTACT_DELETE, (WPARAM)hItem, 0);
MsnContact* msc = proto->Lists_Get(szEmail);
if (msc) msc->hContact = NULL;
}
}
}
hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXT, (LPARAM)hItem);
}
}
INT_PTR CALLBACK DlgProcMsnServLists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_INITDIALOG:
TranslateDialogDefault(hwndDlg);
{
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
HIMAGELIST hIml = ImageList_Create(
GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 5, 5);
HICON hIcon = LoadSkinnedIcon(SKINICON_OTHER_SMALLDOT);
ImageList_AddIcon(hIml, hIcon);
Skin_ReleaseIcon(hIcon);
hIcon = LoadIconEx("list_lc");
ImageList_AddIcon(hIml, hIcon);
SendDlgItemMessage(hwndDlg, IDC_ICON_LC, STM_SETICON, (WPARAM)hIcon, 0);
hIcon = LoadIconEx("list_fl");
ImageList_AddIcon(hIml, hIcon);
SendDlgItemMessage(hwndDlg, IDC_ICON_FL, STM_SETICON, (WPARAM)hIcon, 0);
hIcon = LoadIconEx("list_al");
ImageList_AddIcon(hIml, hIcon);
SendDlgItemMessage(hwndDlg, IDC_ICON_AL, STM_SETICON, (WPARAM)hIcon, 0);
hIcon = LoadIconEx("list_bl");
ImageList_AddIcon(hIml, hIcon);
SendDlgItemMessage(hwndDlg, IDC_ICON_BL, STM_SETICON, (WPARAM)hIcon, 0);
hIcon = LoadIconEx("list_rl");
ImageList_AddIcon(hIml, hIcon);
SendDlgItemMessage(hwndDlg, IDC_ICON_RL, STM_SETICON, (WPARAM)hIcon, 0);
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST);
SendMessage(hwndList, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml);
SendMessage(hwndList, CLM_SETEXTRACOLUMNS, 5, 0);
ResetListOptions(hwndList);
EnableWindow(hwndList, ((CMsnProto*)lParam)->msnLoggedIn);
}
return TRUE;
// case WM_SETFOCUS:
// SetFocus(GetDlgItem(hwndDlg ,IDC_LIST));
// break;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_LISTREFRESH)
{
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST);
SendMessage(hwndList, CLM_AUTOREBUILD, 0, 0);
CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
EnableWindow(hwndList, proto->msnLoggedIn);
}
break;
case WM_NOTIFY:
{
CMsnProto* proto = (CMsnProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
NMCLISTCONTROL* nmc = (NMCLISTCONTROL*)lParam;
if (nmc->hdr.idFrom == 0 && nmc->hdr.code == (unsigned)PSN_APPLY)
{
HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST);
SaveSettings(NULL, hwndList, proto);
SendMessage(hwndList, CLM_AUTOREBUILD, 0, 0);
EnableWindow(hwndList, proto->msnLoggedIn);
}
else if (nmc->hdr.idFrom == IDC_LIST)
{
switch (nmc->hdr.code)
{
case CLN_NEWCONTACT:
if ((nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0)
SetContactIcons(nmc->hItem, nmc->hdr.hwndFrom, proto);
break;
case CLN_LISTREBUILT:
AddPrivacyListEntries(nmc->hdr.hwndFrom, proto);
SetAllContactIcons(NULL, nmc->hdr.hwndFrom, proto);
break;
case CLN_OPTIONSCHANGED:
ResetListOptions(nmc->hdr.hwndFrom);
break;
case NM_CLICK:
HANDLE hItem;
DWORD hitFlags;
int iImage;
// Make sure we have an extra column, also we can't change RL list
if (nmc->iColumn == -1 || nmc->iColumn == 4)
break;
// Find clicked item
hItem = (HANDLE)SendMessage(nmc->hdr.hwndFrom, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nmc->pt.x,nmc->pt.y));
// Nothing was clicked
if (hItem == NULL || !(IsHContactContact(hItem) || IsHContactInfo(hItem)))
break;
// It was not our extended icon
if (!(hitFlags & CLCHT_ONITEMEXTRA))
break;
// Get image in clicked column (0=none, 1=LL, 2=FL, 3=AL, 4=BL, 5=RL)
iImage = SendMessage(nmc->hdr.hwndFrom, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn, 0));
iImage = iImage ? 0 : nmc->iColumn + 1;
SendMessage(nmc->hdr.hwndFrom, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn, iImage));
if (iImage && SendMessage(nmc->hdr.hwndFrom, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn ^ 1, 0)) != EMPTY_EXTRA_ICON)
if (nmc->iColumn == 2 || nmc->iColumn == 3)
SendMessage(nmc->hdr.hwndFrom, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nmc->iColumn ^ 1, 0));
// Activate Apply button
SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
break;
}
}
}
break;
case WM_DESTROY:
HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
ImageList_Destroy(hIml);
ReleaseIconEx("list_fl");
ReleaseIconEx("list_al");
ReleaseIconEx("list_bl");
ReleaseIconEx("list_rl");
break;
}
return FALSE;
}