// ---------------------------------------------------------------------------80
// ICQ plugin for Miranda Instant Messenger
// ________________________________________
//
// Copyright © 2000-2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede
// Copyright © 2001-2002 Jon Keating, Richard Hughes
// Copyright © 2002-2004 Martin Öberg, Sam Kothari, Robert Rainwater
// Copyright © 2004-2010 Angeli-Ka, Joe Kucera
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// -----------------------------------------------------------------------------
// DESCRIPTION:
//
// Support for Custom Statuses
//
// -----------------------------------------------------------------------------
#include "icqoscar.h"
#include "m_extraicons.h"
extern HANDLE hExtraXStatus;
void CListShowMenuItem(HANDLE hMenuItem, BYTE bShow);
BYTE CIcqProto::getContactXStatus(HANDLE hContact)
{
if (!m_bXStatusEnabled && !m_bMoodsEnabled)
return 0;
BYTE bXStatus = getSettingByte(hContact, DBSETTING_XSTATUS_ID, 0);
if (bXStatus < 1 || bXStatus > XSTATUS_COUNT) return 0;
return bXStatus;
}
DWORD CIcqProto::sendXStatusDetailsRequest(HANDLE hContact, int bForced)
{
DWORD dwCookie = 0;
if (m_bXStatusEnabled && getContactXStatus(hContact) != 0)
{ // only request custom status detail when the contact has one
int nNotifyLen = 94 + UINMAXLEN;
char *szNotify = (char*)_alloca(nNotifyLen);
null_snprintf(szNotify, nNotifyLen, "cAwaySrvAwayStat1%d", m_dwLocalUIN);
dwCookie = SendXtrazNotifyRequest(hContact, "srvMng
", szNotify, bForced);
}
return dwCookie;
}
DWORD CIcqProto::requestXStatusDetails(HANDLE hContact, BOOL bAllowDelay)
{
if (!validateStatusMessageRequest(hContact, MTYPE_SCRIPT_NOTIFY))
return 0; // apply privacy rules
if (!CheckContactCapabilities(hContact, CAPF_XSTATUS))
return 0; // contact does not have xstatus
// delay is disabled only if fired from dialog
if (!CheckContactCapabilities(hContact, CAPF_XTRAZ) && bAllowDelay)
return 0; // Contact does not support xtraz, do not request details
struct rates_xstatus_request: public rates_queue_item {
protected:
virtual rates_queue_item* copyItem(rates_queue_item *aDest = NULL) {
rates_xstatus_request *pDest = (rates_xstatus_request*)aDest;
if (!pDest)
pDest = new rates_xstatus_request(ppro, wGroup);
pDest->bForced = bForced;
return rates_queue_item::copyItem(pDest);
};
public:
rates_xstatus_request(CIcqProto *ppro, WORD wGroup): rates_queue_item(ppro, wGroup) { };
virtual ~rates_xstatus_request() { };
virtual void execute() {
dwCookie = ppro->sendXStatusDetailsRequest(hContact, bForced);
};
BOOL bForced;
DWORD dwCookie;
};
m_ratesMutex->Enter();
WORD wGroup = m_rates->getGroupFromSNAC(ICQ_MSG_FAMILY, ICQ_MSG_SRV_SEND);
m_ratesMutex->Leave();
rates_xstatus_request rr(this, wGroup);
rr.bForced = !bAllowDelay;
rr.hContact = hContact;
// delay at least one sec if allowed
if (!handleRateItem(&rr, RQT_REQUEST, 1000, bAllowDelay))
return rr.dwCookie;
return -1; // delayed
}
static HANDLE LoadXStatusIconLibrary(TCHAR *path, const TCHAR *sub)
{
TCHAR* p = _tcsrchr(path, '\\');
HANDLE hLib;
_tcscpy(p, sub);
_tcscat(p, _T("\\xstatus_ICQ.dll"));
if (hLib = LoadLibrary(path)) return hLib;
_tcscpy(p, sub);
_tcscat(p, _T("\\xstatus_icons.dll"));
if (hLib = LoadLibrary(path)) return hLib;
_tcscpy(p, _T("\\"));
return hLib;
}
static TCHAR *InitXStatusIconLibrary(TCHAR *buf, size_t buf_size)
{
TCHAR path[2*MAX_PATH];
HMODULE hXStatusIconsDLL;
// get miranda's exe path
GetModuleFileName(NULL, path, MAX_PATH);
hXStatusIconsDLL = (HMODULE)LoadXStatusIconLibrary(path, _T("\\Icons"));
if (!hXStatusIconsDLL) // TODO: add "Custom Folders" support
hXStatusIconsDLL = (HMODULE)LoadXStatusIconLibrary(path, _T("\\Plugins"));
if (hXStatusIconsDLL)
{
null_strcpy(buf, path, buf_size - 1);
char ident[MAX_PATH];
if (LoadStringA(hXStatusIconsDLL, IDS_IDENTIFY, ident, sizeof(ident)) == 0 || strcmpnull(ident, "# Custom Status Icons #"))
{ // library is invalid
*buf = 0;
}
FreeLibrary(hXStatusIconsDLL);
}
else
*buf = 0;
return buf;
}
HICON CIcqProto::getXStatusIcon(int bStatus, UINT flags)
{
HICON icon = NULL;
if (bStatus > 0 && bStatus <= XSTATUS_COUNT)
icon = hXStatusIcons[bStatus - 1]->GetIcon((flags & LR_BIGICON) != 0);
if (flags & LR_SHARED || !icon)
return icon;
else
return CopyIcon(icon);
}
void CIcqProto::releaseXStatusIcon(int bStatus, UINT flags)
{
if (bStatus > 0 && bStatus <= XSTATUS_COUNT) {
IcqIconHandle p = hXStatusIcons[bStatus - 1];
if (p)
p->ReleaseIcon((flags & LR_BIGICON) != 0);
}
}
void CIcqProto::setContactExtraIcon(HANDLE hContact, int xstatus)
{
HANDLE hIcon;
if (hExtraXStatus == NULL)
{
if (xstatus > 0 && bXStatusExtraIconsReady < 2)
CListMW_ExtraIconsRebuild(0, 0);
hIcon = (xstatus <= 0 ? (HANDLE)-1 : hXStatusExtraIcons[xstatus-1]);
IconExtraColumn iec;
iec.cbSize = sizeof(iec);
iec.hImage = hIcon;
iec.ColumnType = EXTRA_ICON_ADV1;
CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)hContact, (LPARAM)&iec);
}
else
{
hIcon = (HANDLE) -1;
if (xstatus <= 0)
{
ExtraIcon_SetIcon(hExtraXStatus, hContact, (char *) NULL);
}
else
{
char szTemp[MAX_PATH];
null_snprintf(szTemp, sizeof(szTemp), "%s_xstatus%d", m_szModuleName, xstatus-1);
ExtraIcon_SetIcon(hExtraXStatus, hContact, szTemp);
}
}
NotifyEventHooks(hxstatusiconchanged, (WPARAM)hContact, (LPARAM)hIcon);
}
int CIcqProto::CListMW_ExtraIconsRebuild(WPARAM wParam, LPARAM lParam)
{
if ((m_bXStatusEnabled || m_bMoodsEnabled) && ServiceExists(MS_CLIST_EXTRA_ADD_ICON))
{
for (int i = 0; i < XSTATUS_COUNT; i++)
{
hXStatusExtraIcons[i] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)getXStatusIcon(i + 1, LR_SHARED), 0);
releaseXStatusIcon(i + 1, 0);
}
if (!bXStatusExtraIconsReady)
{ // try to hook the events again if they did not existed during init
HookProtoEvent(ME_CLIST_EXTRA_LIST_REBUILD, &CIcqProto::CListMW_ExtraIconsRebuild);
HookProtoEvent(ME_CLIST_EXTRA_IMAGE_APPLY, &CIcqProto::CListMW_ExtraIconsApply);
}
bXStatusExtraIconsReady = 2;
}
return 0;
}
int CIcqProto::CListMW_ExtraIconsApply(WPARAM wParam, LPARAM lParam)
{
if ((m_bXStatusEnabled || m_bMoodsEnabled) && ServiceExists(MS_CLIST_EXTRA_SET_ICON))
{
if (IsICQContact((HANDLE)wParam))
{
// only apply icons to our contacts, do not mess others
DWORD bXStatus = getContactXStatus((HANDLE)wParam);
if ((m_bXStatusEnabled && CheckContactCapabilities((HANDLE)wParam, CAPF_XSTATUS)) ||
(m_bMoodsEnabled && CheckContactCapabilities((HANDLE)wParam, CAPF_STATUS_MOOD)))
setContactExtraIcon((HANDLE)wParam, bXStatus);
}
}
return 0;
}
#define NULLCAP {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
capstr capXStatus[XSTATUS_COUNT] = {
{0x01, 0xD8, 0xD7, 0xEE, 0xAC, 0x3B, 0x49, 0x2A, 0xA5, 0x8D, 0xD3, 0xD8, 0x77, 0xE6, 0x6B, 0x92},
{0x5A, 0x58, 0x1E, 0xA1, 0xE5, 0x80, 0x43, 0x0C, 0xA0, 0x6F, 0x61, 0x22, 0x98, 0xB7, 0xE4, 0xC7},
{0x83, 0xC9, 0xB7, 0x8E, 0x77, 0xE7, 0x43, 0x78, 0xB2, 0xC5, 0xFB, 0x6C, 0xFC, 0xC3, 0x5B, 0xEC},
{0xE6, 0x01, 0xE4, 0x1C, 0x33, 0x73, 0x4B, 0xD1, 0xBC, 0x06, 0x81, 0x1D, 0x6C, 0x32, 0x3D, 0x81},
{0x8C, 0x50, 0xDB, 0xAE, 0x81, 0xED, 0x47, 0x86, 0xAC, 0xCA, 0x16, 0xCC, 0x32, 0x13, 0xC7, 0xB7},
{0x3F, 0xB0, 0xBD, 0x36, 0xAF, 0x3B, 0x4A, 0x60, 0x9E, 0xEF, 0xCF, 0x19, 0x0F, 0x6A, 0x5A, 0x7F},
{0xF8, 0xE8, 0xD7, 0xB2, 0x82, 0xC4, 0x41, 0x42, 0x90, 0xF8, 0x10, 0xC6, 0xCE, 0x0A, 0x89, 0xA6},
{0x80, 0x53, 0x7D, 0xE2, 0xA4, 0x67, 0x4A, 0x76, 0xB3, 0x54, 0x6D, 0xFD, 0x07, 0x5F, 0x5E, 0xC6},
{0xF1, 0x8A, 0xB5, 0x2E, 0xDC, 0x57, 0x49, 0x1D, 0x99, 0xDC, 0x64, 0x44, 0x50, 0x24, 0x57, 0xAF},
{0x1B, 0x78, 0xAE, 0x31, 0xFA, 0x0B, 0x4D, 0x38, 0x93, 0xD1, 0x99, 0x7E, 0xEE, 0xAF, 0xB2, 0x18},
{0x61, 0xBE, 0xE0, 0xDD, 0x8B, 0xDD, 0x47, 0x5D, 0x8D, 0xEE, 0x5F, 0x4B, 0xAA, 0xCF, 0x19, 0xA7},
{0x48, 0x8E, 0x14, 0x89, 0x8A, 0xCA, 0x4A, 0x08, 0x82, 0xAA, 0x77, 0xCE, 0x7A, 0x16, 0x52, 0x08},
{0x10, 0x7A, 0x9A, 0x18, 0x12, 0x32, 0x4D, 0xA4, 0xB6, 0xCD, 0x08, 0x79, 0xDB, 0x78, 0x0F, 0x09},
{0x6F, 0x49, 0x30, 0x98, 0x4F, 0x7C, 0x4A, 0xFF, 0xA2, 0x76, 0x34, 0xA0, 0x3B, 0xCE, 0xAE, 0xA7},
{0x12, 0x92, 0xE5, 0x50, 0x1B, 0x64, 0x4F, 0x66, 0xB2, 0x06, 0xB2, 0x9A, 0xF3, 0x78, 0xE4, 0x8D},
{0xD4, 0xA6, 0x11, 0xD0, 0x8F, 0x01, 0x4E, 0xC0, 0x92, 0x23, 0xC5, 0xB6, 0xBE, 0xC6, 0xCC, 0xF0},
{0x60, 0x9D, 0x52, 0xF8, 0xA2, 0x9A, 0x49, 0xA6, 0xB2, 0xA0, 0x25, 0x24, 0xC5, 0xE9, 0xD2, 0x60},
{0x63, 0x62, 0x73, 0x37, 0xA0, 0x3F, 0x49, 0xFF, 0x80, 0xE5, 0xF7, 0x09, 0xCD, 0xE0, 0xA4, 0xEE},
{0x1F, 0x7A, 0x40, 0x71, 0xBF, 0x3B, 0x4E, 0x60, 0xBC, 0x32, 0x4C, 0x57, 0x87, 0xB0, 0x4C, 0xF1},
{0x78, 0x5E, 0x8C, 0x48, 0x40, 0xD3, 0x4C, 0x65, 0x88, 0x6F, 0x04, 0xCF, 0x3F, 0x3F, 0x43, 0xDF},
{0xA6, 0xED, 0x55, 0x7E, 0x6B, 0xF7, 0x44, 0xD4, 0xA5, 0xD4, 0xD2, 0xE7, 0xD9, 0x5C, 0xE8, 0x1F},
{0x12, 0xD0, 0x7E, 0x3E, 0xF8, 0x85, 0x48, 0x9E, 0x8E, 0x97, 0xA7, 0x2A, 0x65, 0x51, 0xE5, 0x8D},
{0xBA, 0x74, 0xDB, 0x3E, 0x9E, 0x24, 0x43, 0x4B, 0x87, 0xB6, 0x2F, 0x6B, 0x8D, 0xFE, 0xE5, 0x0F},
{0x63, 0x4F, 0x6B, 0xD8, 0xAD, 0xD2, 0x4A, 0xA1, 0xAA, 0xB9, 0x11, 0x5B, 0xC2, 0x6D, 0x05, 0xA1},
{0x2C, 0xE0, 0xE4, 0xE5, 0x7C, 0x64, 0x43, 0x70, 0x9C, 0x3A, 0x7A, 0x1C, 0xE8, 0x78, 0xA7, 0xDC},
{0x10, 0x11, 0x17, 0xC9, 0xA3, 0xB0, 0x40, 0xF9, 0x81, 0xAC, 0x49, 0xE1, 0x59, 0xFB, 0xD5, 0xD4},
{0x16, 0x0C, 0x60, 0xBB, 0xDD, 0x44, 0x43, 0xF3, 0x91, 0x40, 0x05, 0x0F, 0x00, 0xE6, 0xC0, 0x09},
{0x64, 0x43, 0xC6, 0xAF, 0x22, 0x60, 0x45, 0x17, 0xB5, 0x8C, 0xD7, 0xDF, 0x8E, 0x29, 0x03, 0x52},
{0x16, 0xF5, 0xB7, 0x6F, 0xA9, 0xD2, 0x40, 0x35, 0x8C, 0xC5, 0xC0, 0x84, 0x70, 0x3C, 0x98, 0xFA},
{0x63, 0x14, 0x36, 0xff, 0x3f, 0x8a, 0x40, 0xd0, 0xa5, 0xcb, 0x7b, 0x66, 0xe0, 0x51, 0xb3, 0x64},
{0xb7, 0x08, 0x67, 0xf5, 0x38, 0x25, 0x43, 0x27, 0xa1, 0xff, 0xcf, 0x4c, 0xc1, 0x93, 0x97, 0x97},
{0xdd, 0xcf, 0x0e, 0xa9, 0x71, 0x95, 0x40, 0x48, 0xa9, 0xc6, 0x41, 0x32, 0x06, 0xd6, 0xf2, 0x80},
NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP,
NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP,
NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP,
NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP,
NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP, NULLCAP,
NULLCAP, NULLCAP, NULLCAP, NULLCAP};
const char *nameXStatus[XSTATUS_COUNT] = {
LPGEN("Angry"), // 23
LPGEN("Taking a bath"), // 1
LPGEN("Tired"), // 2
LPGEN("Birthday"), // 3
LPGEN("Drinking beer"), // 4
LPGEN("Thinking"), // 5
LPGEN("Eating"), // 80
LPGEN("Watching TV"), // 7
LPGEN("Meeting"), // 8
LPGEN("Coffee"), // 9
LPGEN("Listening to music"),// 10
LPGEN("Business"), // 11
LPGEN("Shooting"), // 12
LPGEN("Having fun"), // 13
LPGEN("On the phone"), // 14
LPGEN("Gaming"), // 15
LPGEN("Studying"), // 16
LPGEN("Shopping"), // 0
LPGEN("Feeling sick"), // 17
LPGEN("Sleeping"), // 18
LPGEN("Surfing"), // 19
LPGEN("Internet"), // 20
LPGEN("Working"), // 21
LPGEN("Typing"), // 22
LPGEN("Picnic"), // 66
LPGEN("Cooking"),
LPGEN("Smoking"),
LPGEN("I'm high"),
LPGEN("On WC"), // 68
LPGEN("To be or not to be"),// 77
LPGEN("Watching pro7 on TV"),
LPGEN("Love"), // 61
LPGEN("Hot Dog"), //6
LPGEN("Rough"), //24
LPGEN("Rock On"), //25
LPGEN("Baby"), //26
LPGEN("Soccer"), //27
LPGEN("Pirate"), //28
LPGEN("Cyclop"), //29
LPGEN("Monkey"), //30
LPGEN("Birdie"), //31
LPGEN("Cool"), //32
LPGEN("Evil"), //33
LPGEN("Alien"), //34
LPGEN("Scooter"), //35
LPGEN("Mask"), //36
LPGEN("Money"), //37
LPGEN("Pilot"), //38
LPGEN("Afro"), //39
LPGEN("St. Patrick"), //40
LPGEN("Headmaster"), //41
LPGEN("Lips"), //42
LPGEN("Ice-Cream"), //43
LPGEN("Pink Lady"), //44
LPGEN("Up yours"), //45
LPGEN("Laughing"), //46
LPGEN("Dog"), //47
LPGEN("Candy"), //48
LPGEN("Crazy Professor"),//50
LPGEN("Ninja"), //51
LPGEN("Cocktail"), //52
LPGEN("Punch"), //53
LPGEN("Donut"), //54
LPGEN("Feeling Good"), //55
LPGEN("Lollypop"), //56
LPGEN("Oink Oink"), //57
LPGEN("Kitty"), //58
LPGEN("Sumo"), //59
LPGEN("Broken hearted"),//60
LPGEN("Free for Chat"), //62
LPGEN("@home"), //63
LPGEN("@work"), //64
LPGEN("Strawberry"), //65
LPGEN("Angel"), //67
LPGEN("Pizza"), //69
LPGEN("Snoring"), //70
LPGEN("On my mobile"), //71
LPGEN("Depressed"), //72
LPGEN("Beetle"), //73
LPGEN("Double Rainbow"),//74
LPGEN("Basketball"), //75
LPGEN("Cupid shot me"), //76
LPGEN("Celebrating"), //78
LPGEN("Sushi"), //79
LPGEN("Playing"), //81
LPGEN("Writing") //84
};
const int moodXStatus[XSTATUS_COUNT] = {
23,
1,
2,
3,
4,
5,
80,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
0,
17,
18,
19,
20,
21,
22,
66,
-1,
-1,
-1,
68,
77,
-1,
61,
6,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
50,
51,
52,
53,
54,
55,
56,
57,
58,
59,
60,
62,
63,
64,
65,
67,
69,
70,
71,
72,
73,
74,
75,
76,
78,
79,
81,
84};
void CIcqProto::handleXStatusCaps(DWORD dwUIN, char *szUID, HANDLE hContact, BYTE *caps, int capsize, char *moods, int moodsize)
{
int bChanged = FALSE;
int nCustomStatusID = 0, nMoodID = 0;
if (!m_bXStatusEnabled && !m_bMoodsEnabled)
{
ClearContactCapabilities(hContact, CAPF_STATUS_MOOD | CAPF_XSTATUS);
return;
}
int nOldXStatusID = getContactXStatus(hContact);
if (m_bXStatusEnabled)
{
if (caps)
{ // detect custom status capabilities
if (capsize > 0)
for (int i = 0; i < XSTATUS_COUNT; i++)
{
if (MatchCapability(caps, capsize, (const capstr*)capXStatus[i], BINARY_CAP_SIZE))
{
BYTE bXStatusId = (BYTE)(i+1);
char str[MAX_PATH];
SetContactCapabilities(hContact, CAPF_XSTATUS);
if (nOldXStatusID != bXStatusId)
{ // only write default name when it is really needed, i.e. on Custom Status change
setSettingByte(hContact, DBSETTING_XSTATUS_ID, bXStatusId);
setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
deleteSetting(hContact, DBSETTING_XSTATUS_MSG);
NetLog_Server("%s changed custom status to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
bChanged = TRUE;
}
#ifdef _DEBUG
else
NetLog_Server("%s has custom status %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
#endif
if (getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO))
requestXStatusDetails(hContact, TRUE);
nCustomStatusID = bXStatusId;
break;
}
}
if (nCustomStatusID == 0)
{
#ifdef _DEBUG
if (m_iStatus != ID_STATUS_OFFLINE && CheckContactCapabilities(hContact, CAPF_XSTATUS))
NetLog_Server("%s has removed custom status.", strUID(dwUIN, szUID));
#endif
ClearContactCapabilities(hContact, CAPF_XSTATUS);
}
}
#ifdef _DEBUG
else if (CheckContactCapabilities(hContact, CAPF_XSTATUS))
{
char str[MAX_PATH];
NetLog_Server("%s has custom status %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[nOldXStatusID-1], str, MAX_PATH));
}
#endif
}
if (m_bMoodsEnabled)
{
if (moods && moodsize < 32)
{ // process custom statuses (moods) from ICQ6
if (moodsize > 0)
for (int i = 0; i < XSTATUS_COUNT; i++)
{
char szMoodId[32], szMoodData[32];
null_strcpy(szMoodData, moods, moodsize);
if (moodXStatus[i] == -1) continue;
null_snprintf(szMoodId, SIZEOF(szMoodId), "0icqmood%d", moodXStatus[i]);
if (!strcmpnull(szMoodId, szMoodData))
{
BYTE bXStatusId = (BYTE)(i+1);
char str[MAX_PATH];
SetContactCapabilities(hContact, CAPF_STATUS_MOOD);
if (nCustomStatusID == 0 && nOldXStatusID != bXStatusId)
{ // only write default name when it is really needed, i.e. on Custom Status change
setSettingByte(hContact, DBSETTING_XSTATUS_ID, bXStatusId);
setSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
deleteSetting(hContact, DBSETTING_XSTATUS_MSG);
NetLog_Server("%s changed mood to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
bChanged = TRUE;
}
#ifdef _DEBUG
else if (nOldXStatusID != bXStatusId)
NetLog_Server("%s changed mood to %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
else
NetLog_Server("%s has mood %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[i], str, MAX_PATH));
#endif
// cannot retrieve mood details here - need to be processed with new user details
nMoodID = bXStatusId;
break;
}
}
if (nMoodID == 0 && moods)
{
#ifdef _DEBUG
if (m_iStatus != ID_STATUS_OFFLINE && CheckContactCapabilities(hContact, CAPF_STATUS_MOOD))
NetLog_Server("%s has removed mood.", strUID(dwUIN, szUID));
#endif
ClearContactCapabilities(hContact, CAPF_STATUS_MOOD);
}
}
#ifdef _DEBUG
else if (CheckContactCapabilities(hContact, CAPF_STATUS_MOOD))
{ // Mood was not changed, but contact has one, add a small log notice
char str[MAX_PATH];
NetLog_Server("%s has mood %s.", strUID(dwUIN, szUID), ICQTranslateUtfStatic(nameXStatus[nOldXStatusID-1], str, MAX_PATH));
}
#endif
}
if (nCustomStatusID != 0 && nMoodID != 0 && nCustomStatusID != nMoodID)
NetLog_Server("Warning: Diverse custom statuses detected, using custom status.");
if ((nCustomStatusID == 0 && (caps || !m_bXStatusEnabled)) && (nMoodID == 0 && (moods || !m_bMoodsEnabled)))
{
if (getSettingByte(hContact, DBSETTING_XSTATUS_ID, -1) != -1)
bChanged = TRUE;
deleteSetting(hContact, DBSETTING_XSTATUS_ID);
deleteSetting(hContact, DBSETTING_XSTATUS_NAME);
deleteSetting(hContact, DBSETTING_XSTATUS_MSG);
}
if (m_bXStatusEnabled != 10 && m_bMoodsEnabled != 10)
{
setContactExtraIcon(hContact, nCustomStatusID ? nCustomStatusID : (nMoodID ? nMoodID : (moods ? 0 : nOldXStatusID)));
if (bChanged)
NotifyEventHooks(hxstatuschanged, (WPARAM)hContact, 0);
}
}
void CIcqProto::updateServerCustomStatus(int fullUpdate)
{
BYTE bXStatus = getContactXStatus(NULL);
if (fullUpdate)
{ // update client capabilities
if (m_bXStatusEnabled)
setUserInfo();
char szMoodData[32];
// prepare mood id
if (m_bMoodsEnabled && bXStatus && moodXStatus[bXStatus-1] != -1)
null_snprintf(szMoodData, SIZEOF(szMoodData), "0icqmood%d", moodXStatus[bXStatus-1]);
else
szMoodData[0] = '\0';
SetStatusMood(szMoodData, 1500);
}
char *szStatusNote = NULL;
if (bXStatus && (m_bXStatusEnabled || m_bMoodsEnabled))
{ // use custom status message as status note
szStatusNote = getSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, "");
}
else
{ // retrieve standard status message (e.g. custom status set to none)
char **pszMsg = MirandaStatusToAwayMsg(m_iStatus);
m_modeMsgsMutex->Enter();
if (pszMsg)
szStatusNote = null_strdup(*pszMsg);
m_modeMsgsMutex->Leave();
// no default status message, set empty
if (!szStatusNote)
szStatusNote = null_strdup("");
}
if (szStatusNote)
SetStatusNote(szStatusNote, 1500, FALSE);
SAFE_FREE(&szStatusNote);
}
static WNDPROC OldMessageEditProc;
static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
switch(msg) {
case WM_CHAR:
if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000)
{
PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
return 0;
}
if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000)
{ // ctrl-a
SendMessage(hwnd, EM_SETSEL, 0, -1);
return 0;
}
if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000)
{ // ctrl-w
SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
return 0;
}
if (wParam == 127 && GetKeyState(VK_CONTROL) & 0x8000)
{ // ctrl-backspace
DWORD start, end;
WCHAR *text;
SendMessage(hwnd, EM_GETSEL, (WPARAM) & end, (LPARAM) (PDWORD) NULL);
SendMessage(hwnd, WM_KEYDOWN, VK_LEFT, 0);
SendMessage(hwnd, EM_GETSEL, (WPARAM) & start, (LPARAM) (PDWORD) NULL);
text = GetWindowTextUcs(hwnd);
MoveMemory(text + start, text + end, sizeof(WCHAR) * (strlennull(text) + 1 - end));
SetWindowTextUcs(hwnd, text);
SAFE_FREE(&text);
SendMessage(hwnd, EM_SETSEL, start, start);
SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM) hwnd);
return 0;
}
break;
}
return CallWindowProc(OldMessageEditProc,hwnd,msg,wParam,lParam);
}
struct SetXStatusData
{
CIcqProto* ppro;
BYTE bAction;
BYTE bXStatus;
HANDLE hContact;
HANDLE hEvent;
DWORD iEvent;
int countdown;
char* okButtonFormat;
};
struct InitXStatusData
{
CIcqProto* ppro;
BYTE bAction;
BYTE bXStatus;
char* szXStatusName;
char* szXStatusMsg;
HANDLE hContact;
};
#define HM_PROTOACK (WM_USER+10)
static INT_PTR CALLBACK SetXStatusDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
{
SetXStatusData *dat = (SetXStatusData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
char str[MAX_PATH];
switch(message) {
case HM_PROTOACK:
{
ACKDATA *ack = (ACKDATA*)lParam;
if (ack->type != ICQACKTYPE_XSTATUS_RESPONSE) break;
if (ack->hContact != dat->hContact) break;
if ((DWORD)ack->hProcess != dat->iEvent) break;
ShowDlgItem(hwndDlg, IDC_RETRXSTATUS, SW_HIDE);
ShowDlgItem(hwndDlg, IDC_XMSG, SW_SHOW);
ShowDlgItem(hwndDlg, IDC_XTITLE, SW_SHOW);
SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH));
UnhookEvent(dat->hEvent); dat->hEvent = NULL;
char *szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_NAME, "");
SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText);
SAFE_FREE(&szText);
szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_MSG, "");
SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText);
SAFE_FREE(&szText);
}
break;
case WM_INITDIALOG:
{
InitXStatusData *init = (InitXStatusData*)lParam;
TranslateDialogDefault(hwndDlg);
dat = (SetXStatusData*)SAFE_MALLOC(sizeof(SetXStatusData));
dat->ppro = init->ppro;
SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat);
dat->bAction = init->bAction;
if (!init->bAction)
{ // set our xStatus
dat->bXStatus = init->bXStatus;
SendDlgItemMessage(hwndDlg, IDC_XMSG, EM_LIMITTEXT, 1024, 0);
OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XMSG),GWLP_WNDPROC,(LONG_PTR)MessageEditSubclassProc);
SetDlgItemTextUtf(hwndDlg, IDC_XMSG, init->szXStatusMsg);
if (dat->ppro->m_bXStatusEnabled)
{ // custom status enabled, prepare title edit
SendDlgItemMessage(hwndDlg, IDC_XTITLE, EM_LIMITTEXT, 256, 0);
OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XTITLE),GWLP_WNDPROC,(LONG_PTR)MessageEditSubclassProc);
SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, init->szXStatusName);
}
else
{ // only moods enabled, hide title, resize message edit control
ShowDlgItem(hwndDlg, IDC_XTITLE_STATIC, SW_HIDE);
ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE);
MoveDlgItem(hwndDlg, IDC_XMSG_STATIC, 5, 0, 179, 8);
MoveDlgItem(hwndDlg, IDC_XMSG, 5, 9, 179, 65);
}
dat->okButtonFormat = GetDlgItemTextUtf(hwndDlg,IDOK);
dat->countdown = 5;
SendMessage(hwndDlg, WM_TIMER, 0, 0);
SetTimer(hwndDlg,1,1000,0);
}
else
{ // retrieve contact's xStatus
dat->hContact = init->hContact;
dat->bXStatus = dat->ppro->getContactXStatus(dat->hContact);
dat->okButtonFormat = NULL;
SendMessage(GetDlgItem(hwndDlg, IDC_XTITLE), EM_SETREADONLY, 1, 0);
SendMessage(GetDlgItem(hwndDlg, IDC_XMSG), EM_SETREADONLY, 1, 0);
if (dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_XSTATUS) && !dat->ppro->getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO))
{
SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Cancel"), str, MAX_PATH));
dat->hEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_PROTOACK);
ShowDlgItem(hwndDlg, IDC_RETRXSTATUS, SW_SHOW);
ShowDlgItem(hwndDlg, IDC_XMSG, SW_HIDE);
ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE);
dat->iEvent = dat->ppro->requestXStatusDetails(dat->hContact, FALSE);
}
else
{
SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("Close"), str, MAX_PATH));
dat->hEvent = NULL;
char *szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_NAME, "");
SetDlgItemTextUtf(hwndDlg, IDC_XTITLE, szText);
SAFE_FREE(&szText);
if (dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_STATUS_MOOD) && !dat->ppro->CheckContactCapabilities(dat->hContact, CAPF_XSTATUS))
{ // only for clients supporting just moods and not custom status
szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_STATUS_NOTE, "");
// hide title, resize message edit control
ShowDlgItem(hwndDlg, IDC_XTITLE_STATIC, SW_HIDE);
ShowDlgItem(hwndDlg, IDC_XTITLE, SW_HIDE);
MoveDlgItem(hwndDlg, IDC_XMSG_STATIC, 5, 0, 179, 8);
MoveDlgItem(hwndDlg, IDC_XMSG, 5, 9, 179, 65);
}
else
szText = dat->ppro->getSettingStringUtf(dat->hContact, DBSETTING_XSTATUS_MSG, "");
SetDlgItemTextUtf(hwndDlg, IDC_XMSG, szText);
SAFE_FREE(&szText);
}
}
if (dat->bXStatus)
{
SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)dat->ppro->getXStatusIcon(dat->bXStatus, LR_SHARED | LR_BIGICON));
SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)dat->ppro->getXStatusIcon(dat->bXStatus, LR_SHARED));
}
char buf[MAX_PATH];
char *format = GetWindowTextUtf(hwndDlg);
null_snprintf(str, sizeof(str), format, dat->bXStatus?ICQTranslateUtfStatic(nameXStatus[dat->bXStatus-1], buf, MAX_PATH):"");
SetWindowTextUtf(hwndDlg, str);
SAFE_FREE(&format);
return TRUE;
}
case WM_TIMER:
if(dat->countdown==-1)
{
DestroyWindow(hwndDlg);
break;
}
{
null_snprintf(str,sizeof(str),dat->okButtonFormat,dat->countdown);
SetDlgItemTextUtf(hwndDlg,IDOK,str);
}
dat->countdown--;
break;
case WM_COMMAND:
switch(LOWORD(wParam)) {
case IDOK:
DestroyWindow(hwndDlg);
break;
case IDC_XTITLE:
case IDC_XMSG:
if (!dat->bAction)
{ // set our xStatus
KillTimer(hwndDlg,1);
SetDlgItemTextUtf(hwndDlg,IDOK,ICQTranslateUtfStatic(LPGEN("OK"), str, MAX_PATH));
}
break;
}
break;
case WM_DESTROY:
if (!dat->bAction)
{ // set our xStatus
char szSetting[64];
char *szValue;
dat->ppro->setSettingByte(NULL, DBSETTING_XSTATUS_ID, dat->bXStatus);
szValue = GetDlgItemTextUtf(hwndDlg,IDC_XMSG);
null_snprintf(szSetting, 64, "XStatus%dMsg", dat->bXStatus);
dat->ppro->setSettingStringUtf(NULL, szSetting, szValue);
dat->ppro->setSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, szValue);
SAFE_FREE(&szValue);
if (dat->ppro->m_bXStatusEnabled)
{
szValue = GetDlgItemTextUtf(hwndDlg,IDC_XTITLE);
null_snprintf(szSetting, 64, "XStatus%dName", dat->bXStatus);
dat->ppro->setSettingStringUtf(NULL, szSetting, szValue);
dat->ppro->setSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, szValue);
SAFE_FREE(&szValue);
if (dat->bXStatus)
{
dat->ppro->releaseXStatusIcon(dat->bXStatus, LR_BIGICON);
dat->ppro->releaseXStatusIcon(dat->bXStatus, 0);
}
}
dat->ppro->updateServerCustomStatus(TRUE);
SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XMSG),GWLP_WNDPROC,(LONG_PTR)OldMessageEditProc);
if (dat->ppro->m_bXStatusEnabled)
SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_XTITLE),GWLP_WNDPROC,(LONG_PTR)OldMessageEditProc);
}
if (dat->hEvent) UnhookEvent(dat->hEvent);
SAFE_FREE(&dat->okButtonFormat);
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, NULL);
SAFE_FREE((void**)&dat);
break;
case WM_CLOSE:
DestroyWindow(hwndDlg);
break;
}
return FALSE;
}
void CIcqProto::setXStatusEx(BYTE bXStatus, BYTE bQuiet)
{
CLISTMENUITEM mi = {0};
BYTE bOldXStatus = getSettingByte(NULL, DBSETTING_XSTATUS_ID, 0);
mi.cbSize = sizeof(mi);
if (!m_bHideXStatusUI)
{
if (bOldXStatus <= XSTATUS_COUNT)
{
mi.flags = CMIM_FLAGS;
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bOldXStatus], (LPARAM)&mi);
}
mi.flags = CMIM_FLAGS | CMIF_CHECKED;
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hXStatusItems[bXStatus], (LPARAM)&mi);
}
if (bXStatus)
{
char szSetting[64];
char str[MAX_PATH];
char *szName = NULL, *szMsg = NULL;
if (m_bXStatusEnabled)
{
null_snprintf(szSetting, 64, "XStatus%dName", bXStatus);
szName = getSettingStringUtf(NULL, szSetting, ICQTranslateUtfStatic(nameXStatus[bXStatus-1], str, MAX_PATH));
}
null_snprintf(szSetting, 64, "XStatus%dMsg", bXStatus);
szMsg = getSettingStringUtf(NULL, szSetting, "");
null_snprintf(szSetting, 64, "XStatus%dStat", bXStatus);
if (!bQuiet && !getSettingByte(NULL, szSetting, 0))
{
InitXStatusData init;
init.ppro = this;
init.bAction = 0; // set
init.bXStatus = bXStatus;
init.szXStatusName = szName;
init.szXStatusMsg = szMsg;
CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init);
}
else
{
setSettingByte(NULL, DBSETTING_XSTATUS_ID, bXStatus);
if (m_bXStatusEnabled)
setSettingStringUtf(NULL, DBSETTING_XSTATUS_NAME, szName);
setSettingStringUtf(NULL, DBSETTING_XSTATUS_MSG, szMsg);
updateServerCustomStatus(TRUE);
}
SAFE_FREE(&szName);
SAFE_FREE(&szMsg);
}
else
{
setSettingByte(NULL, DBSETTING_XSTATUS_ID, bXStatus);
deleteSetting(NULL, DBSETTING_XSTATUS_NAME);
deleteSetting(NULL, DBSETTING_XSTATUS_MSG);
updateServerCustomStatus(TRUE);
}
}
INT_PTR CIcqProto::menuXStatus(WPARAM wParam,LPARAM lParam,LPARAM fParam)
{
setXStatusEx((BYTE)fParam, 0);
return 0;
}
void CIcqProto::InitXStatusItems(BOOL bAllowStatus)
{
CLISTMENUITEM mi;
int i = 0, len = strlennull(m_szModuleName);
char srvFce[MAX_PATH + 64];
char szItem[MAX_PATH + 64];
int bXStatusMenuBuilt = 0;
BYTE bXStatus = getContactXStatus(NULL);
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return;
if (!bAllowStatus) return;
// Custom Status UI is disabled, no need to continue items' init
if (m_bHideXStatusUI || m_bHideXStatusMenu) return;
null_snprintf(szItem, sizeof(szItem), Translate("%s Custom Status"), m_szModuleName);
mi.cbSize = sizeof(mi);
mi.pszPopupName = szItem;
mi.popupPosition = 500084000;
mi.position = 2000040000;
for (i = 0; i <= XSTATUS_COUNT; i++)
{
null_snprintf(srvFce, sizeof(srvFce), "%s/menuXStatus%d", m_szModuleName, i);
mi.position++;
if (!i)
bXStatusMenuBuilt = ServiceExists(srvFce);
if (!bXStatusMenuBuilt)
CreateProtoServiceParam(srvFce+len, &CIcqProto::menuXStatus, i);
mi.flags = (i ? CMIF_ICONFROMICOLIB : 0) | (bXStatus == i?CMIF_CHECKED:0);
mi.icolibItem = i ? hXStatusIcons[i-1]->Handle() : NULL;
mi.pszName = i ? (char*)nameXStatus[i-1] : (char *)LPGEN("None");
mi.pszService = srvFce;
mi.pszContactOwner = m_szModuleName;
hXStatusItems[i] = Menu_AddStatusMenuItem(&mi);
// CMIF_HIDDEN does not work for adding services
CListShowMenuItem(hXStatusItems[i], !(m_bHideXStatusUI || m_bHideXStatusMenu));
}
}
void CIcqProto::InitXStatusIcons()
{
if (!m_bXStatusEnabled && !m_bMoodsEnabled)
return;
TCHAR lib[2*MAX_PATH] = {0};
TCHAR *icon_lib = InitXStatusIconLibrary(lib, SIZEOF(lib));
char szSection[MAX_PATH + 64], *szAccountName = tchar_to_utf8(m_tszUserName);
null_snprintf(szSection, sizeof(szSection), "Status Icons/%s/Custom Status", szAccountName);
SAFE_FREE(&szAccountName);
for (int i = 0; i < XSTATUS_COUNT; i++)
{
char szTemp[64];
null_snprintf(szTemp, sizeof(szTemp), "xstatus%d", i);
hXStatusIcons[i] = IconLibDefine(nameXStatus[i], szSection, m_szModuleName, szTemp, icon_lib, -(IDI_XSTATUS1+i));
}
// initialize arrays for CList custom status icons
memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid));
memset(hXStatusCListIcons, -1, sizeof(hXStatusCListIcons));
}
void CIcqProto::UninitXStatusIcons()
{
for (int i = 0; i < XSTATUS_COUNT; i++)
IconLibRemove(&hXStatusIcons[i]);
// clear clist icon state indicators
memset(bXStatusCListIconsValid, 0, sizeof(bXStatusCListIconsValid));
}
INT_PTR CIcqProto::ShowXStatusDetails(WPARAM wParam, LPARAM lParam)
{
InitXStatusData init;
init.ppro = this;
init.bAction = 1; // retrieve
init.hContact = (HANDLE)wParam;
CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SETXSTATUS), NULL, SetXStatusDlgProc, (LPARAM)&init);
return 0;
}
INT_PTR CIcqProto::SetXStatus(WPARAM wParam, LPARAM lParam)
{ // obsolete (TODO: remove in next version)
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0;
if (wParam >= 0 && wParam <= XSTATUS_COUNT)
{
setXStatusEx((BYTE)wParam, 1);
return wParam;
}
return 0;
}
INT_PTR CIcqProto::GetXStatus(WPARAM wParam, LPARAM lParam)
{ // obsolete (TODO: remove in next version)
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0;
if (!icqOnline()) return 0;
BYTE status = getContactXStatus(NULL);
if (wParam) *((char**)wParam) = m_bXStatusEnabled ? DBSETTING_XSTATUS_NAME : NULL;
if (lParam) *((char**)lParam) = DBSETTING_XSTATUS_MSG;
return status;
}
INT_PTR CIcqProto::SetXStatusEx(WPARAM wParam, LPARAM lParam)
{
ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam;
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 1;
if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure
if (pData->flags & CSSF_MASK_STATUS)
{ // set custom status
int status = *pData->status;
if (status >= 0 && status <= XSTATUS_COUNT)
setXStatusEx((BYTE)status, 1);
else
return 1; // Failure
}
if (pData->flags & (CSSF_MASK_NAME | CSSF_MASK_MESSAGE))
{
BYTE status = getContactXStatus(NULL);
if (!status) return 1; // Failure
if (m_bXStatusEnabled && (pData->flags & CSSF_MASK_NAME))
{ // set custom status name
if (pData->flags & CSSF_UNICODE)
setSettingStringW(NULL, DBSETTING_XSTATUS_NAME, pData->pwszName);
else
setSettingString(NULL, DBSETTING_XSTATUS_NAME, pData->pszName);
}
if (pData->flags & CSSF_MASK_MESSAGE)
{ // set custom status message
if (pData->flags & CSSF_UNICODE)
setSettingStringW(NULL, DBSETTING_XSTATUS_MSG, pData->pwszMessage);
else
setSettingString(NULL, DBSETTING_XSTATUS_MSG, pData->pszMessage);
// update status note if used for custom status message
updateServerCustomStatus(FALSE);
}
}
if (pData->flags & CSSF_DISABLE_UI)
{ // hide menu items + contact menu item
m_bHideXStatusUI = (*pData->wParam) ? 0 : 1;
}
if (pData->flags & CSSF_DISABLE_MENU)
{ // hide menu items only
m_bHideXStatusMenu = (*pData->wParam) ? 0 : 1;
}
return 0; // Success
}
INT_PTR CIcqProto::GetXStatusEx(WPARAM wParam, LPARAM lParam)
{
ICQ_CUSTOM_STATUS *pData = (ICQ_CUSTOM_STATUS*)lParam;
HANDLE hContact = (HANDLE)wParam;
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 1;
if (pData->cbSize < sizeof(ICQ_CUSTOM_STATUS)) return 1; // Failure
if (pData->flags & CSSF_MASK_STATUS)
{ // fill status member
*pData->status = getContactXStatus(hContact);
}
if (pData->flags & CSSF_MASK_NAME)
{ // fill status name member
if (pData->flags & CSSF_DEFAULT_NAME)
{
int status = *pData->wParam;
if (status < 1 || status > XSTATUS_COUNT) return 1; // Failure
if (pData->flags & CSSF_UNICODE)
{
char *text = (char*)nameXStatus[status -1];
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, text, -1, pData->pwszName, MAX_PATH);
}
else
strcpy(pData->pszName, (char*)nameXStatus[status - 1]);
}
else
{ // moods does not support status title
if (!m_bXStatusEnabled) return 1;
if (pData->flags & CSSF_UNICODE)
{
char *str = getSettingStringUtf(hContact, DBSETTING_XSTATUS_NAME, "");
WCHAR *wstr = make_unicode_string(str);
wcscpy(pData->pwszName, wstr);
SAFE_FREE(&str);
SAFE_FREE(&wstr);
}
else
{
DBVARIANT dbv = {0};
if (!getSettingString(hContact, DBSETTING_XSTATUS_NAME, &dbv) && dbv.pszVal)
strcpy(pData->pszName, dbv.pszVal);
else
strcpy(pData->pszName, "");
ICQFreeVariant(&dbv);
}
}
}
if (pData->flags & CSSF_MASK_MESSAGE)
{ // fill status message member
if (pData->flags & CSSF_UNICODE)
{
char *str = getSettingStringUtf(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, "");
WCHAR *wstr = make_unicode_string(str);
wcscpy(pData->pwszMessage, wstr);
SAFE_FREE(&str);
SAFE_FREE(&wstr);
}
else
{
DBVARIANT dbv = {0};
if (!getSettingString(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, &dbv) && dbv.pszVal)
strcpy(pData->pszMessage, dbv.pszVal);
else
strcpy(pData->pszMessage, "");
ICQFreeVariant(&dbv);
}
}
if (pData->flags & CSSF_DISABLE_UI)
{
if (pData->wParam) *pData->wParam = !m_bHideXStatusUI;
}
if (pData->flags & CSSF_DISABLE_MENU)
{
if (pData->wParam) *pData->wParam = !m_bHideXStatusMenu;
}
if (pData->flags & CSSF_STATUSES_COUNT)
{
if (pData->wParam) *pData->wParam = XSTATUS_COUNT;
}
if (pData->flags & CSSF_STR_SIZES)
{
DBVARIANT dbv = {DBVT_DELETED};
if (pData->wParam)
{
if (m_bXStatusEnabled && !getSettingString(hContact, DBSETTING_XSTATUS_NAME, &dbv))
*pData->wParam = strlennull(dbv.pszVal);
else
*pData->wParam = 0;
ICQFreeVariant(&dbv);
}
if (pData->lParam)
{
if (!getSettingString(hContact, CheckContactCapabilities(hContact, CAPF_STATUS_MOOD) ? DBSETTING_STATUS_NOTE : DBSETTING_XSTATUS_MSG, &dbv))
*pData->lParam = strlennull(dbv.pszVal);
else
*pData->lParam = 0;
ICQFreeVariant(&dbv);
}
}
return 0; // Success
}
INT_PTR CIcqProto::GetXStatusIcon(WPARAM wParam, LPARAM lParam)
{
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return 0;
if (!wParam)
wParam = getContactXStatus(NULL);
if (wParam >= 1 && wParam <= XSTATUS_COUNT)
{
return (INT_PTR)getXStatusIcon((BYTE)wParam, lParam);
}
return 0;
}
INT_PTR CIcqProto::RequestXStatusDetails(WPARAM wParam, LPARAM lParam)
{
HANDLE hContact = (HANDLE)wParam;
if (!m_bXStatusEnabled) return 0;
if (hContact && !getSettingByte(NULL, "XStatusAuto", DEFAULT_XSTATUS_AUTO) &&
getContactXStatus(hContact) && CheckContactCapabilities(hContact, CAPF_XSTATUS))
{ // user has xstatus, no auto-retrieve details, valid contact, request details
return requestXStatusDetails(hContact, TRUE);
}
return 0;
}
INT_PTR CIcqProto::RequestAdvStatusIconIdx(WPARAM wParam, LPARAM lParam)
{
if (!m_bXStatusEnabled && !m_bMoodsEnabled) return -1;
BYTE bXStatus = getContactXStatus((HANDLE)wParam);
if (bXStatus)
{
int idx=-1;
if (!bXStatusCListIconsValid[bXStatus-1])
{ // adding icon
int idx = hXStatusCListIcons[bXStatus-1];
HIMAGELIST hCListImageList = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST,0,0);
if (hCListImageList)
{
HICON hXStatusIcon = getXStatusIcon(bXStatus, LR_SHARED);
if (idx > 0)
ImageList_ReplaceIcon(hCListImageList, idx, hXStatusIcon);
else
hXStatusCListIcons[bXStatus-1] = ImageList_AddIcon(hCListImageList, hXStatusIcon);
// mark icon index in the array as valid
bXStatusCListIconsValid[bXStatus-1] = TRUE;
releaseXStatusIcon(bXStatus, 0);
}
}
idx = bXStatusCListIconsValid[bXStatus-1] ? hXStatusCListIcons[bXStatus-1] : -1;
if (idx > 0)
return (idx & 0xFFFF) << 16;
}
return -1;
}