From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- icqj_mod/icqosc_svcs.c | 2306 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2306 insertions(+) create mode 100644 icqj_mod/icqosc_svcs.c (limited to 'icqj_mod/icqosc_svcs.c') diff --git a/icqj_mod/icqosc_svcs.c b/icqj_mod/icqosc_svcs.c new file mode 100644 index 0000000..9cd7b9f --- /dev/null +++ b/icqj_mod/icqosc_svcs.c @@ -0,0 +1,2306 @@ +// ---------------------------------------------------------------------------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,2003,2004 Martin Öberg, Sam Kothari, Robert Rainwater +// Copyright © 2004,2005,2006 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- +// +// File name : $Source: /cvsroot/miranda/miranda/protocols/IcqOscarJ/icqosc_svcs.c,v $ +// Revision : $Revision: 3237 $ +// Last change on : $Date: 2006-06-27 19:57:56 +0200 (Tue, 27 Jun 2006) $ +// Last change by : $Author: jokusoftware $ +// +// DESCRIPTION: +// +// High-level code for exported API services +// +// ----------------------------------------------------------------------------- + +#include "icqoscar.h" + + + +int gbIdleAllow; +int icqGoingOnlineStatus; + +extern WORD wListenPort; + +extern char* calcMD5Hash(char* szFile); +extern filetransfer *CreateFileTransfer(HANDLE hContact, DWORD dwUin, int nVersion); + + +int IcqGetCaps(WPARAM wParam, LPARAM lParam) +{ + int nReturn = 0; + + + switch (wParam) + { + + case PFLAGNUM_1: + nReturn = PF1_IM | PF1_URL | PF1_AUTHREQ | PF1_BASICSEARCH | PF1_ADDSEARCHRES | + PF1_VISLIST | PF1_INVISLIST | PF1_MODEMSG | PF1_FILE | PF1_EXTSEARCH | + PF1_EXTSEARCHUI | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | + PF1_ADDED | PF1_CONTACT; + if (!gbAimEnabled) + nReturn |= PF1_NUMERICUSERID; + if (gbSsiEnabled && ICQGetContactSettingByte(NULL, "ServerAddRemove", DEFAULT_SS_ADDSERVER)) + nReturn |= PF1_SERVERCLIST; + break; + + case PFLAGNUM_2: + nReturn = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT | PF2_INVISIBLE; + break; + + case PFLAGNUM_3: + nReturn = PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | + PF2_FREECHAT; + break; + + case PFLAGNUM_4: + nReturn = PF4_SUPPORTIDLE; + if (gbAvatarsEnabled) + nReturn |= PF4_AVATARS; +#ifdef DBG_CAPMTN + nReturn |= PF4_SUPPORTTYPING; +#endif + break; + + case PFLAG_UNIQUEIDTEXT: + nReturn = (int)ICQTranslate("User ID"); + break; + + case PFLAG_UNIQUEIDSETTING: + nReturn = (int)UNIQUEIDSETTING; + break; + + case PFLAG_MAXCONTACTSPERPACKET: + nReturn = MAX_CONTACTSSEND; + break; + + case PFLAG_MAXLENOFMESSAGE: + nReturn = MAX_MESSAGESNACSIZE-102; + } + + return nReturn; +} + + + +int IcqGetName(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + strncpy((char *)lParam, ICQTranslate(gpszICQProtoName), wParam); + + return 0; // Success + } + + return 1; // Failure +} + + + +int IcqLoadIcon(WPARAM wParam, LPARAM lParam) +{ + UINT id; + + + switch (wParam & 0xFFFF) + { + case PLI_PROTOCOL: + id = IDI_ICQ; + break; + + default: + return 0; // Failure + } + + return (int)LoadImage(hInst, MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam&PLIF_SMALL?SM_CXSMICON:SM_CXICON), GetSystemMetrics(wParam&PLIF_SMALL?SM_CYSMICON:SM_CYICON), 0); +} + + + +int IcqIdleChanged(WPARAM wParam, LPARAM lParam) +{ + int bIdle = (lParam&IDF_ISIDLE); + int bPrivacy = (lParam&IDF_PRIVACY); + + if (bPrivacy) return 0; + + ICQWriteContactSettingDword(NULL, "IdleTS", bIdle ? time(0) : 0); + + if (gbTempVisListEnabled) // remove temporary visible users + clearTemporaryVisibleList(); + + icq_setidle(bIdle ? 1 : 0); + + return 0; +} + + + +int IcqGetAvatarInfo(WPARAM wParam, LPARAM lParam) +{ + PROTO_AVATAR_INFORMATION* pai = (PROTO_AVATAR_INFORMATION*)lParam; + DWORD dwUIN; + uid_str szUID; + DBVARIANT dbv; + int dwPaFormat; + + if (!gbAvatarsEnabled) return GAIR_NOAVATAR; + + if (ICQGetContactSetting(pai->hContact, "AvatarHash", &dbv) || dbv.cpbVal != 0x14) + return GAIR_NOAVATAR; // we did not found avatar hash or hash invalid - no avatar available + + if (ICQGetContactSettingUID(pai->hContact, &dwUIN, &szUID)) + { + ICQFreeVariant(&dbv); + + return GAIR_NOAVATAR; // we do not support avatars for invalid contacts + } + + dwPaFormat = ICQGetContactSettingByte(pai->hContact, "AvatarType", PA_FORMAT_UNKNOWN); + if (dwPaFormat != PA_FORMAT_UNKNOWN) + { // we know the format, test file + GetFullAvatarFileName(dwUIN, szUID, dwPaFormat, pai->filename, MAX_PATH); + + pai->format = dwPaFormat; + + if (!IsAvatarSaved(pai->hContact, dbv.pbVal)) + { // hashes are the same + if (access(pai->filename, 0) == 0) + { + ICQFreeVariant(&dbv); + + return GAIR_SUCCESS; // we have found the avatar file, whoala + } + } + } + + if (IsAvatarSaved(pai->hContact, dbv.pbVal)) + { // we didn't received the avatar before - this ensures we will not request avatar again and again + if ((wParam & GAIF_FORCE) != 0 && pai->hContact != 0) + { // request avatar data + GetAvatarFileName(dwUIN, szUID, pai->filename, MAX_PATH); + GetAvatarData(pai->hContact, dwUIN, szUID, dbv.pbVal, dbv.cpbVal, pai->filename); + ICQFreeVariant(&dbv); + + return GAIR_WAITFOR; + } + } + ICQFreeVariant(&dbv); + + return GAIR_NOAVATAR; +} + + + +int IcqGetMaxAvatarSize(WPARAM wParam, LPARAM lParam) +{ + if (wParam) *((int*)wParam) = 64; + if (lParam) *((int*)lParam) = 64; + + return 0; +} + + + +int IcqAvatarFormatSupported(WPARAM wParam, LPARAM lParam) +{ + if (lParam == PA_FORMAT_JPEG || lParam == PA_FORMAT_GIF) + return -2; + else + return 0; +} + + + +int IcqGetMyAvatar(WPARAM wParam, LPARAM lParam) +{ + char* file; + + if (!gbAvatarsEnabled) return -2; + + if (!wParam) return -3; + + file = loadMyAvatarFileName(); + if (file) strncpy((char*)wParam, file, (int)lParam); + SAFE_FREE(&file); + if (!access((char*)wParam, 0)) return 0; + return -1; +} + + + +int IcqSetMyAvatar(WPARAM wParam, LPARAM lParam) +{ + char* szFile = (char*)lParam; + int iRet = -1; + + if (!gbAvatarsEnabled || !gbSsiEnabled) return -2; + + if (szFile) + { // set file for avatar + char szMyFile[MAX_PATH+1]; + int dwPaFormat = DetectAvatarFormat(szFile); + char* hash; + HBITMAP avt; + + if (dwPaFormat != PA_FORMAT_XML) + { // if it should be image, check if it is valid + avt = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szFile); + if (!avt) return iRet; + DeleteObject(avt); + } + GetFullAvatarFileName(0, NULL, dwPaFormat, szMyFile, MAX_PATH); + if (!CopyFile(szFile, szMyFile, FALSE)) + { + NetLog_Server("Failed to copy our avatar to local storage."); + return iRet; + } + + hash = calcMD5Hash(szMyFile); + if (hash) + { + char* ihash = (char*)_alloca(0x14); + // upload hash to server + ihash[0] = 0; //unknown + ihash[1] = dwPaFormat == PA_FORMAT_XML ? 8 : 1; //hash type + ihash[2] = 1; //hash status + ihash[3] = 0x10; //hash len + memcpy(ihash+4, hash, 0x10); + updateServAvatarHash(ihash, 0x14); + + if (ICQWriteContactSettingBlob(NULL, "AvatarHash", ihash, 0x14)) + { + NetLog_Server("Failed to save avatar hash."); + } + + storeMyAvatarFileName(szMyFile); + iRet = 0; + + SAFE_FREE(&hash); + } + } + else + { // delete user avatar + BYTE bEmptyAvatar[9] = {0x00, 0x01, 0x00,0x05,0x02,0x01,0xD2,0x04,0x72}; + + ICQDeleteContactSetting(NULL, "AvatarFile"); + ICQDeleteContactSetting(NULL, "AvatarHash"); + updateServAvatarHash(bEmptyAvatar, 9); // clear hash on server + iRet = 0; + } + + return iRet; +} + + + +void updateAimAwayMsg() +{ + char** szMsg = MirandaStatusToAwayMsg(gnCurrentStatus); + + EnterCriticalSection(&modeMsgsMutex); + if (szMsg) + icq_sendSetAimAwayMsgServ(*szMsg); + LeaveCriticalSection(&modeMsgsMutex); +} + + + +int IcqSetStatus(WPARAM wParam, LPARAM lParam) +{ + int nNewStatus = MirandaStatusToSupported(wParam); + + // check if netlib handles are ready + if (!ghServerNetlibUser) + return 0; + + if (gbTempVisListEnabled) // remove temporary visible users + clearTemporaryVisibleList(); + + if (nNewStatus != gnCurrentStatus) + { + if (ICQGetContactSettingByte(NULL, "XStatusReset", DEFAULT_XSTATUS_RESET)) + { // clear custom status on status change + IcqSetXStatus(0, 0); + } + + // New status is OFFLINE + if (nNewStatus == ID_STATUS_OFFLINE) + { + // for quick logoff + icqGoingOnlineStatus = nNewStatus; + + // Send disconnect packet + icq_sendCloseConnection(); + + icq_serverDisconnect(FALSE); + + SetCurrentStatus(ID_STATUS_OFFLINE); + + NetLog_Server("Logged off."); + } + else + { + switch (gnCurrentStatus) + { + + // We are offline and need to connect + case ID_STATUS_OFFLINE: + { + char *pszPwd; + + // Update user connection settings + UpdateGlobalSettings(); + + // Read UIN from database + dwLocalUIN = ICQGetContactSettingUIN(NULL); + if (dwLocalUIN == 0) + { + SetCurrentStatus(ID_STATUS_OFFLINE); + + icq_LogMessage(LOG_FATAL, "You have not entered a ICQ number.\nConfigure this in Options->Network->ICQ and try again."); + return 0; + } + + // Set status to 'Connecting' + icqGoingOnlineStatus = nNewStatus; + SetCurrentStatus(ID_STATUS_CONNECTING); + + // Read password from database + pszPwd = GetUserPassword(FALSE); + + if (pszPwd) + icq_login(pszPwd); + else + RequestPassword(); + + break; + } + + // We are connecting... We only need to change the going online status + case ID_STATUS_CONNECTING: + { + icqGoingOnlineStatus = nNewStatus; + break; + } + + // We are already connected so we should just change status + default: + { + + SetCurrentStatus(nNewStatus); + + if (gnCurrentStatus == ID_STATUS_INVISIBLE) + { + if (gbSsiEnabled) + updateServVisibilityCode(3); + icq_setstatus(MirandaStatusToIcq(gnCurrentStatus)); + // Tell whos on our visible list + icq_sendEntireVisInvisList(0); + if (gbAimEnabled) + updateAimAwayMsg(); + } + else + { + icq_setstatus(MirandaStatusToIcq(gnCurrentStatus)); + if (gbSsiEnabled) + updateServVisibilityCode(4); + // Tell whos on our invisible list + + icq_sendEntireVisInvisList(1); + if (gbAimEnabled) + updateAimAwayMsg(); + } + } + + } + } + } + + return 0; +} + + + +int IcqGetStatus(WPARAM wParam, LPARAM lParam) +{ + return gnCurrentStatus; +} + + + +int IcqSetAwayMsg(WPARAM wParam, LPARAM lParam) +{ + char** ppszMsg = NULL; + char* szNewUtf = NULL; + + + EnterCriticalSection(&modeMsgsMutex); + + ppszMsg = MirandaStatusToAwayMsg(wParam); + if (!ppszMsg) + { + LeaveCriticalSection(&modeMsgsMutex); + return 1; // Failure + } + + // Prepare UTF-8 status message + szNewUtf = ansi_to_utf8((char*)lParam); + + if (strcmpnull(szNewUtf, *ppszMsg)) + { + // Free old message + SAFE_FREE(ppszMsg); + + // Set new message + *ppszMsg = szNewUtf; + szNewUtf = NULL; + + if (gbAimEnabled && (gnCurrentStatus == (int)wParam)) + icq_sendSetAimAwayMsgServ(*ppszMsg); + } + SAFE_FREE(&szNewUtf); + + LeaveCriticalSection(&modeMsgsMutex); + + return 0; // Success +} + + + +static HANDLE HContactFromAuthEvent(WPARAM hEvent) +{ + DBEVENTINFO dbei; + DWORD body[2]; + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = sizeof(DWORD)*2; + dbei.pBlob = (PBYTE)&body; + + if (CallService(MS_DB_EVENT_GET, hEvent, (LPARAM)&dbei)) + return INVALID_HANDLE_VALUE; + + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) + return INVALID_HANDLE_VALUE; + + if (strcmpnull(dbei.szModule, gpszICQProtoName)) + return INVALID_HANDLE_VALUE; + + return (HANDLE)body[1]; // this is bad - needs new auth system +} + + + +int IcqAuthAllow(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline && wParam) + { + DWORD uin; + uid_str uid; + HANDLE hContact; + + hContact = HContactFromAuthEvent(wParam); + if (hContact == INVALID_HANDLE_VALUE) + return 1; + + if (ICQGetContactSettingUID(hContact, &uin, &uid)) + return 1; + + icq_sendAuthResponseServ(uin, uid, 1, ""); + + return 0; // Success + } + + return 1; // Failure +} + + + +int IcqAuthDeny(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline && wParam) + { + DWORD uin; + uid_str uid; + HANDLE hContact; + + + hContact = HContactFromAuthEvent(wParam); + if (hContact == INVALID_HANDLE_VALUE) + return 1; + + if (ICQGetContactSettingUID(hContact, &uin, &uid)) + return 1; + + icq_sendAuthResponseServ(uin, uid, 0, (char *)lParam); + + return 0; // Success + } + + return 1; // Failure +} + + + +static int cheekySearchId = -1; +static DWORD cheekySearchUin; +static char* cheekySearchUid; +static VOID CALLBACK CheekySearchTimerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) +{ + ICQSEARCHRESULT isr = {0}; + + KillTimer(hwnd, idEvent); + + isr.hdr.cbSize = sizeof(isr); + if (cheekySearchUin) + { + isr.hdr.nick = ""; + isr.uid = NULL; + } + else + { + isr.hdr.nick = cheekySearchUid; + isr.uid = cheekySearchUid; + } + isr.hdr.firstName = ""; + isr.hdr.lastName = ""; + isr.hdr.email = ""; + isr.uin = cheekySearchUin; + + ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)cheekySearchId, (LPARAM)&isr); + ICQBroadcastAck(NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)cheekySearchId, 0); + + cheekySearchId = -1; +} + + +int IcqBasicSearch(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + char* pszSearch = (char*)lParam; + DWORD dwUin; + + if (strlennull(pszSearch)) + { + char pszUIN[255]; + int nHandle = 0; + unsigned int i, j; + + if (!gbAimEnabled) + { + for (i=j=0; (i=0x30) && (pszSearch[i]<=0x39)) + { + pszUIN[j] = pszSearch[i]; + j++; + } + } + } + else + { + for (i=j=0; (i 0)) + { + DWORD dwSearchId, dwSecId; + + // Success + dwSearchId = SearchByEmail((char *)lParam); + if (gbAimEnabled) + dwSecId = icq_searchAimByEmail((char *)lParam, dwSearchId); + else + dwSecId = 0; + if (dwSearchId) + return dwSearchId; + else + return dwSecId; + } + + return 0; // Failure +} + + +int IcqSearchByDetails(WPARAM wParam, LPARAM lParam) +{ + if (lParam && icqOnline) + { + PROTOSEARCHBYNAME *psbn=(PROTOSEARCHBYNAME*)lParam; + + + if (psbn->pszNick || psbn->pszFirstName || psbn->pszLastName) + { + // Success + return SearchByNames(psbn->pszNick, psbn->pszFirstName, psbn->pszLastName); + } + } + + return 0; // Failure +} + + +int IcqCreateAdvSearchUI(WPARAM wParam, LPARAM lParam) +{ + if (lParam && hInst) + { + // Success + return (int)CreateDialogUtf(hInst, MAKEINTRESOURCE(IDD_ICQADVANCEDSEARCH), (HWND)lParam, AdvancedSearchDlgProc); + } + + return 0; // Failure +} + + +int IcqSearchByAdvanced(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline && IsWindow((HWND)lParam)) + { + int nDataLen; + BYTE* bySearchData; + + if (bySearchData = createAdvancedSearchStructure((HWND)lParam, &nDataLen)) + { + int result; + + result = icq_sendAdvancedSearchServ(bySearchData, nDataLen); + SAFE_FREE(&bySearchData); + + return result; // Success + } + } + + return 0; // Failure +} + + + +// TODO: Adding needs some more work in general +static HANDLE AddToListByUIN(DWORD dwUin, DWORD dwFlags) +{ + HANDLE hContact; + int bAdded; + + hContact = HContactFromUIN(dwUin, &bAdded); + + if (hContact) + { + if ((!dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 1)) + { + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + SetContactHidden(hContact, 0); + } + + return hContact; // Success + } + + return NULL; // Failure +} + + +static HANDLE AddToListByUID(char *szUID, DWORD dwFlags) +{ + HANDLE hContact; + int bAdded; + + hContact = HContactFromUID(0, szUID, &bAdded); + + if (hContact) + { + if ((!dwFlags & PALF_TEMPORARY) && DBGetContactSettingByte(hContact, "CList", "NotOnList", 1)) + { + DBDeleteContactSetting(hContact, "CList", "NotOnList"); + SetContactHidden(hContact, 0); + } + + return hContact; // Success + } + + return NULL; // Failure +} + + + +int IcqAddToList(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { // this should be only from search + ICQSEARCHRESULT *isr = (ICQSEARCHRESULT*)lParam; + + if (isr->hdr.cbSize == sizeof(ICQSEARCHRESULT)) + { + if (!isr->uin) + return (int)AddToListByUID(isr->hdr.nick, wParam); + else + return (int)AddToListByUIN(isr->uin, wParam); + } + } + + return 0; // Failure +} + + + +int IcqAddToListByEvent(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei = {0}; + DWORD uin = 0; + uid_str uid = {0}; + + + dbei.cbSize = sizeof(dbei); + + if ((dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, lParam, 0)) == -1) + return 0; + + dbei.pBlob = (PBYTE)_alloca(dbei.cbBlob + 1); + dbei.pBlob[dbei.cbBlob] = '\0'; + + if (CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei)) + return 0; // failed to get event + + if (strcmpnull(dbei.szModule, gpszICQProtoName)) + return 0; // this event is not ours + + if (dbei.eventType == EVENTTYPE_CONTACTS) + { + int i, ci = HIWORD(wParam); + char* pbOffset, *pbEnd; + + for (i = 0, pbOffset = (char*)dbei.pBlob, pbEnd = pbOffset + dbei.cbBlob; i <= ci; i++) + { + pbOffset += strlennull((char*)pbOffset) + 1; // Nick + if (pbOffset >= pbEnd) break; + if (i == ci) + { // we found the contact, get uid + if (IsStringUIN((char*)pbOffset)) + uin = atoi((char*)pbOffset); + else + { + uin = 0; + strcpy(uid, (char*)pbOffset); + } + } + pbOffset += strlennull((char*)pbOffset) + 1; // Uin + if (pbOffset >= pbEnd) break; + } + } + else if (dbei.eventType != EVENTTYPE_AUTHREQUEST && dbei.eventType != EVENTTYPE_ADDED) + { + return 0; + } + else // auth req or added event + { + HANDLE hContact = ((HANDLE*)dbei.pBlob)[1]; // this sucks - awaiting new auth system + + if (ICQGetContactSettingUID(hContact, &uin, &uid)) + return 0; + } + + if (uin != 0) + { + return (int)AddToListByUIN(uin, LOWORD(wParam)); // Success + } + else if (strlennull(uid)) + { // add aim contact + return (int)AddToListByUID(uid, LOWORD(wParam)); // Success + } + + return 0; // Failure +} + + + +int IcqSetNickName(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline) + { + ICQWriteContactSettingString(NULL, "Nick", (char*)lParam); + + return IcqChangeInfoEx(CIXT_BASIC, 0); + } + + return 0; // Failure +} + + + +int IcqChangeInfoEx(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline && wParam) + { + PBYTE buf = NULL; + int buflen = 0; + BYTE b; + + // userinfo + ppackTLVWord(&buf, &buflen, (WORD)GetACP(), TLV_CODEPAGE, 0); + + if (wParam & CIXT_CONTACT) + { // contact information + b = !ICQGetContactSettingByte(NULL, "PublishPrimaryEmail", 0); + ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail", b, TLV_EMAIL); + ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail0", 0, TLV_EMAIL); + ppackTLVLNTSBytefromDB(&buf, &buflen, "e-mail1", 0, TLV_EMAIL); + + ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "AllowSpam", 0), TLV_ALLOWSPAM, 1); + + ppackTLVLNTSfromDB(&buf, &buflen, "Phone", TLV_PHONE); + ppackTLVLNTSfromDB(&buf, &buflen, "Fax", TLV_FAX); + ppackTLVLNTSfromDB(&buf, &buflen, "Cellular", TLV_MOBILE); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyPhone", TLV_WORKPHONE); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyFax", TLV_WORKFAX); + } + + if (wParam & CIXT_BASIC) + { // upload basic user info + ppackTLVLNTSfromDB(&buf, &buflen, "Nick", TLV_NICKNAME); + ppackTLVLNTSfromDB(&buf, &buflen, "FirstName", TLV_FIRSTNAME); + ppackTLVLNTSfromDB(&buf, &buflen, "LastName", TLV_LASTNAME); + ppackTLVLNTSfromDB(&buf, &buflen, "About", TLV_ABOUT); + } + + if (wParam & CIXT_MORE) + { + ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "Age", 0), TLV_AGE, 1); + b = ICQGetContactSettingByte(NULL, "Gender", 0); + ppackTLVByte(&buf, &buflen, (BYTE)(b ? (b == 'M' ? 2 : 1) : 0), TLV_GENDER, 1); + ppackLEWord(&buf, &buflen, TLV_BIRTH); + ppackLEWord(&buf, &buflen, 0x06); + ppackLEWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "BirthYear", 0)); + ppackLEWord(&buf, &buflen, (WORD)ICQGetContactSettingByte(NULL, "BirthMonth", 0)); + ppackLEWord(&buf, &buflen, (WORD)ICQGetContactSettingByte(NULL, "BirthDay", 0)); + + ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language1", 0), TLV_LANGUAGE, 1); + ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language2", 0), TLV_LANGUAGE, 1); + ppackTLVWord(&buf, &buflen, (WORD)StringToListItemId("Language3", 0), TLV_LANGUAGE, 1); + + ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "MaritalStatus", 0), TLV_MARITAL, 1); + } + + if (wParam & CIXT_WORK) + { + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyDepartment", TLV_DEPARTMENT); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyPosition", TLV_POSITION); + ppackTLVLNTSfromDB(&buf, &buflen, "Company", TLV_COMPANY); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyStreet", TLV_WORKSTREET); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyState", TLV_WORKSTATE); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyCity", TLV_WORKCITY); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyHomepage", TLV_WORKURL); + ppackTLVLNTSfromDB(&buf, &buflen, "CompanyZIP", TLV_WORKZIPCODE); + ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "CompanyCountry", 0), TLV_WORKCOUNTRY, 1); + ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "CompanyOccupation", 0), TLV_OCUPATION, 1); + } + + if (wParam & CIXT_LOCATION) + { + ppackTLVLNTSfromDB(&buf, &buflen, "City", TLV_CITY); + ppackTLVLNTSfromDB(&buf, &buflen, "State", TLV_STATE); + ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "Country", 0), TLV_COUNTRY, 1); + ppackTLVLNTSfromDB(&buf, &buflen, "OriginCity", TLV_ORGCITY); + ppackTLVLNTSfromDB(&buf, &buflen, "OriginState", TLV_ORGSTATE); + ppackTLVWord(&buf, &buflen, ICQGetContactSettingWord(NULL, "OriginCountry", 0), TLV_ORGCOUNTRY, 1); + ppackTLVLNTSfromDB(&buf, &buflen, "Street", TLV_STREET); + ppackTLVLNTSfromDB(&buf, &buflen, "ZIP", TLV_ZIPCODE); + + ppackTLVLNTSfromDB(&buf, &buflen, "Homepage", TLV_URL); + + ppackTLVByte(&buf, &buflen, ICQGetContactSettingByte(NULL, "Timezone", 0), TLV_TIMEZONE, 1); + } + + if (wParam & CIXT_BACKGROUND) + { + WORD w; + + w = StringToListItemId("Interest0Cat", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest0Text", TLV_INTERESTS); + w = StringToListItemId("Interest1Cat", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest1Text", TLV_INTERESTS); + w = StringToListItemId("Interest2Cat", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest2Text", TLV_INTERESTS); + w = StringToListItemId("Interest3Cat", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Interest3Text", TLV_INTERESTS); + + w = StringToListItemId("Past0", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past0Text", TLV_PASTINFO); + w = StringToListItemId("Past1", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past1Text", TLV_PASTINFO); + w = StringToListItemId("Past2", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Past2Text", TLV_PASTINFO); + + w = StringToListItemId("Affiliation0", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation0Text", TLV_AFFILATIONS); + w = StringToListItemId("Affiliation1", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation1Text", TLV_AFFILATIONS); + w = StringToListItemId("Affiliation2", 0); + ppackTLVWordLNTSfromDB(&buf, &buflen, w, "Affiliation2Text", TLV_AFFILATIONS); + } + + return icq_changeUserDetailsServ(META_SET_FULLINFO_REQ, buf, (WORD)buflen); + } + + return 0; // Failure +} + + + +static int messageRate = 0; +static DWORD lastMessageTick = 0; +int IcqGetInfo(WPARAM wParam, LPARAM lParam) +{ + if (lParam && icqOnline) + { // TODO: add checking for SGIF_ONOPEN, otherwise max one per 10sec + CCSDATA* ccs = (CCSDATA*)lParam; + DWORD dwUin; + uid_str szUid; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid)) + { + return 0; // Invalid contact + } + + messageRate -= (GetTickCount() - lastMessageTick)/10; + if (messageRate<0) // TODO: this is bad, needs centralising + messageRate = 0; + lastMessageTick = GetTickCount(); + messageRate += 67; // max 1.5 msgs/sec when rate is high + + // server kicks if 100 msgs sent instantly, so send max 50 instantly + if (messageRate < 67*50) + { + if (dwUin) + icq_sendGetInfoServ(dwUin, (ccs->wParam & SGIF_MINIMAL) != 0); + else + icq_sendGetAimProfileServ(ccs->hContact, szUid); + + return 0; // Success + } + } + + return 1; // Failure +} + + + +int IcqFileAllow(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + CCSDATA* ccs = (CCSDATA*)lParam; + DWORD dwUin; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL)) + return 0; // Invalid contact + + if (dwUin && icqOnline && ccs->hContact && ccs->lParam && ccs->wParam) + { + filetransfer* ft = ((filetransfer *)ccs->wParam); + + ft->szSavePath = null_strdup((char *)ccs->lParam); + AddExpectedFileRecv(ft); + + // Was request received thru DC and have we a open DC, send through that + if (ft->bDC && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + icq_sendFileAcceptDirect(ccs->hContact, ft); + else + icq_sendFileAcceptServ(dwUin, ft, 0); + + return ccs->wParam; // Success + } + } + + return 0; // Failure +} + + + +int IcqFileDeny(WPARAM wParam, LPARAM lParam) +{ + int nReturnValue = 1; + + if (lParam) + { + CCSDATA *ccs = (CCSDATA *)lParam; + filetransfer *ft = (filetransfer*)ccs->wParam; + DWORD dwUin; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL)) + return 1; // Invalid contact + + if (icqOnline && dwUin && ccs->wParam && ccs->hContact) + { + // Was request received thru DC and have we a open DC, send through that + if (ft->bDC && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + icq_sendFileDenyDirect(ccs->hContact, ft, (char*)ccs->lParam); + else + icq_sendFileDenyServ(dwUin, ft, (char*)ccs->lParam, 0); + + nReturnValue = 0; // Success + } + /* FIXME: ft leaks (but can get double freed?) */ + } + + return nReturnValue; +} + + + +int IcqFileCancel(WPARAM wParam, LPARAM lParam) +{ + if (lParam /*&& icqOnline*/) + { + CCSDATA* ccs = (CCSDATA*)lParam; + DWORD dwUin; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL)) + return 1; // Invalid contact + + if (ccs->hContact && dwUin && ccs->wParam) + { + filetransfer * ft = (filetransfer * ) ccs->wParam; + + icq_CancelFileTransfer(ccs->hContact, ft); + + return 0; // Success + } + } + + return 1; // Failure +} + + + +int IcqFileResume(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline && wParam) + { + PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam; + + icq_sendFileResume((filetransfer *)wParam, pfr->action, pfr->szFilename); + + return 0; // Success + } + + return 1; // Failure +} + + + +int IcqSendSms(WPARAM wParam, LPARAM lParam) +{ + if (icqOnline && wParam && lParam) + return icq_sendSMSServ((const char *)wParam, (const char *)lParam); + + return 0; // Failure +} + + + +// Maybe we should be saving these up for batch changing, but I can't be bothered yet +int IcqSetApparentMode(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + CCSDATA* ccs = (CCSDATA*)lParam; + DWORD uin; + uid_str uid; + + if (ICQGetContactSettingUID(ccs->hContact, &uin, &uid)) + return 1; // Invalid contact + + if (ccs->hContact) + { + // Only 3 modes are supported + if (ccs->wParam == 0 || ccs->wParam == ID_STATUS_ONLINE || ccs->wParam == ID_STATUS_OFFLINE) + { + int oldMode = ICQGetContactSettingWord(ccs->hContact, "ApparentMode", 0); + + // Don't send redundant updates + if ((int)ccs->wParam != oldMode) + { + ICQWriteContactSettingWord(ccs->hContact, "ApparentMode", (WORD)ccs->wParam); + + // Not being online is only an error when in SS mode. This is not handled + // yet so we just ignore this for now. + if (icqOnline) + { + if (oldMode != 0) // Remove from old list + icq_sendChangeVisInvis(ccs->hContact, uin, uid, oldMode==ID_STATUS_OFFLINE, 0); + if (ccs->wParam != 0) // Add to new list + icq_sendChangeVisInvis(ccs->hContact, uin, uid, ccs->wParam==ID_STATUS_OFFLINE, 1); + if (oldMode==ID_STATUS_OFFLINE) + sendVisContactServ(uin, 1); + else + if (ccs->wParam==ID_STATUS_OFFLINE) + sendVisContactServ(uin, 0); + } + + return 0; // Success + } + } + } + } + + return 1; // Failure +} + + + +int IcqGetAwayMsg(WPARAM wParam,LPARAM lParam) +{ + if (lParam && icqOnline) + { + CCSDATA* ccs = (CCSDATA*)lParam; + DWORD dwUin; + uid_str szUID; + WORD wStatus; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUID)) + return 0; // Invalid contact + + wStatus = ICQGetContactStatus(ccs->hContact); + + if (dwUin) + { + int wMessageType = 0; + + switch(wStatus) + { + + case ID_STATUS_AWAY: + wMessageType = MTYPE_AUTOAWAY; + break; + + case ID_STATUS_NA: + wMessageType = MTYPE_AUTONA; + break; + + case ID_STATUS_OCCUPIED: + wMessageType = MTYPE_AUTOBUSY; + break; + + case ID_STATUS_DND: + wMessageType = MTYPE_AUTODND; + break; + + case ID_STATUS_FREECHAT: + wMessageType = MTYPE_AUTOFFC; + break; + + default: + break; + } + + if (wMessageType) + { + if (gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + { + int iRes = icq_sendGetAwayMsgDirect(ccs->hContact, wMessageType); + if (iRes) return iRes; // we succeded, return + } + return icq_sendGetAwayMsgServ(dwUin, wMessageType, + (WORD)(ICQGetContactSettingWord(ccs->hContact, "Version", 0)==9?9:ICQ_VERSION)); // Success + } + } + else + { + if (wStatus == ID_STATUS_AWAY) + { + return icq_sendGetAimAwayMsgServ(szUID, MTYPE_AUTOAWAY); + } + } + } + + return 0; // Failure +} + + + +static message_cookie_data* CreateMsgCookieData(BYTE bMsgType, HANDLE hContact, DWORD dwUin) +{ + BYTE bAckType; + WORD wStatus = ICQGetContactStatus(hContact); + + if (!ICQGetContactSettingByte(NULL, "SlowSend", DEFAULT_SLOWSEND)) + bAckType = ACKTYPE_NONE; + else if ((!dwUin) || (!CheckContactCapabilities(hContact, CAPF_SRV_RELAY)) || + (wStatus == ID_STATUS_OFFLINE) || ICQGetContactSettingByte(NULL, "OnlyServerAcks", DEFAULT_ONLYSERVERACKS)) + bAckType = ACKTYPE_SERVER; + else + bAckType = ACKTYPE_CLIENT; + + return CreateMessageCookie(bMsgType, bAckType); +} + + + +int IcqSendMessage(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + CCSDATA* ccs = (CCSDATA*)lParam; + + if (ccs->hContact && ccs->lParam) + { + WORD wRecipientStatus; + DWORD dwCookie; + DWORD dwUin; + uid_str szUID; + char* pszText; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUID)) + { // Invalid contact + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("The receiver has an invalid user ID.")); + return dwCookie; + } + + if (dwUin && gbTempVisListEnabled && gnCurrentStatus == ID_STATUS_INVISIBLE) + makeContactTemporaryVisible(ccs->hContact); // make us temporarily visible to contact + + pszText = (char*)ccs->lParam; + + wRecipientStatus = ICQGetContactStatus(ccs->hContact); + + // Failure scenarios + if (!icqOnline) + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("You cannot send messages when you are offline.")); + } + else if ((wRecipientStatus == ID_STATUS_OFFLINE) && (strlennull(pszText) > 450)) + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("Messages to offline contacts must be shorter than 450 characters.")); + } + // Looks OK + else + { + message_cookie_data* pCookieData; + + if (wRecipientStatus != ID_STATUS_OFFLINE && gbUtfEnabled==2 && !IsUSASCII(pszText, strlennull(pszText)) + && CheckContactCapabilities(ccs->hContact, CAPF_UTF) && ICQGetContactSettingByte(ccs->hContact, "UnicodeSend", 1)) + { // text contains national chars and we should send all this as Unicode, so do it + char* pszUtf = NULL; + int nStrSize = MultiByteToWideChar(CP_ACP, 0, pszText, strlennull(pszText), (wchar_t*)pszUtf, 0); + int nRes; + + pszUtf = (char*)SAFE_MALLOC((nStrSize + 2)*sizeof(wchar_t)); + // we omit ansi string - not used... + MultiByteToWideChar(CP_ACP, 0, pszText, strlennull(pszText), (wchar_t*)(pszUtf+1), nStrSize); + *(WORD*)(pszUtf + 1 + nStrSize*sizeof(wchar_t)) = '\0'; // trailing zeros + + ccs->lParam = (LPARAM)pszUtf; // yeah, this is quite a hack, BE AWARE OF THAT !!! + ccs->wParam |= PREF_UNICODE; + + nRes = IcqSendMessageW(wParam, lParam); + ccs->lParam = (LPARAM)pszText; + + SAFE_FREE(&pszUtf); // release memory + + return nRes; + } + + if (!dwUin) + { // prepare AIM Html message + char *mng = MangleXml(pszText, strlennull(pszText)); + char *tmp = (char*)SAFE_MALLOC(strlennull(mng) + 28); + + strcpy(tmp, ""); + strcat(tmp, mng); + SAFE_FREE(&mng); + strcat(tmp, ""); + pszText = tmp; + } + + // Set up the ack type + pCookieData = CreateMsgCookieData(MTYPE_PLAIN, ccs->hContact, dwUin); + +#ifdef _DEBUG + NetLog_Server("Send message - Message cap is %u", CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY)); + NetLog_Server("Send message - Contact status is %u", wRecipientStatus); +#endif + if (dwUin && gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + { + int iRes = icq_SendDirectMessage(dwUin, ccs->hContact, pszText, strlennull(pszText), 1, pCookieData, NULL); + if (iRes) return iRes; // we succeded, return + } + + if ((!dwUin || !CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY)) || (wRecipientStatus == ID_STATUS_OFFLINE)) + { + dwCookie = icq_SendChannel1Message(dwUin, szUID, ccs->hContact, pszText, pCookieData); + } + else + { + WORD wPriority; + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + dwCookie = icq_SendChannel2Message(dwUin, pszText, strlennull(pszText), wPriority, pCookieData, NULL); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_MESSAGE, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + if (!dwUin) SAFE_FREE(&pszText); + } + + return dwCookie; // Success + } + } + + return 0; // Failure +} + + + +static char* convertMsgToUserSpecificAnsi(HANDLE hContact, const char* szMsg) +{ // this needs valid "Unicode" buffer from SRMM !!! + WORD wCP = ICQGetContactSettingWord(hContact, "CodePage", gwAnsiCodepage); + int nMsgLen = strlennull(szMsg); + wchar_t* usMsg = (wchar_t*)(szMsg + nMsgLen + 1); + char* szAnsi = NULL; + + if (wCP != CP_ACP) + { + int nStrSize = WideCharToMultiByte(wCP, 0, usMsg, nMsgLen, szAnsi, 0, NULL, NULL); + + szAnsi = (char*)SAFE_MALLOC(nStrSize + 1); + WideCharToMultiByte(wCP, 0, usMsg, nMsgLen, szAnsi, nStrSize, NULL, NULL); + szAnsi[nStrSize] = '\0'; + } + return szAnsi; +} + + + +int IcqSendMessageW(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + CCSDATA* ccs = (CCSDATA*)lParam; + + if (ccs->hContact && ccs->lParam) + { + WORD wRecipientStatus; + DWORD dwCookie; + DWORD dwUin; + uid_str szUID; + wchar_t* pszText; + // TODO: this was not working, removed check + if (!gbUtfEnabled || /*(ccs->wParam & PREF_UNICODE == PREF_UNICODE) ||*/ + (!CheckContactCapabilities(ccs->hContact, CAPF_UTF)) || (!ICQGetContactSettingByte(ccs->hContact, "UnicodeSend", 1))) + { // send as unicode only if marked as unicode & unicode enabled + char* szAnsi = convertMsgToUserSpecificAnsi(ccs->hContact, (char*)ccs->lParam); + int nRes; + + if (szAnsi) ccs->lParam = (LPARAM)szAnsi; + nRes = IcqSendMessage(wParam, lParam); + SAFE_FREE(&szAnsi); + + return nRes; + } + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUID)) + { // Invalid contact + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("The receiver has an invalid user ID.")); + return dwCookie; + } + + if (dwUin && gbTempVisListEnabled && gnCurrentStatus == ID_STATUS_INVISIBLE) + makeContactTemporaryVisible(ccs->hContact); // make us temporarily visible to contact + + pszText = (wchar_t*)((char*)ccs->lParam+strlennull((char*)ccs->lParam)+1); // get the UTF-16 part + + wRecipientStatus = ICQGetContactStatus(ccs->hContact); + + // Failure scenarios + if (!icqOnline) + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_MESSAGE, ICQTranslate("You cannot send messages when you are offline.")); + } + // Looks OK + else + { + message_cookie_data* pCookieData; + BOOL plain_ascii = IsUnicodeAscii(pszText, wcslen(pszText)); + + if ((wRecipientStatus == ID_STATUS_OFFLINE) || plain_ascii) + { // send as plain if no special char or user offline + char* szAnsi; + int nRes; + + if (!plain_ascii) + { + szAnsi = convertMsgToUserSpecificAnsi(ccs->hContact, (char*)ccs->lParam); + if (szAnsi) ccs->lParam = (LPARAM)szAnsi; + } + nRes = IcqSendMessage(wParam, lParam); + if (!plain_ascii) + SAFE_FREE(&szAnsi); + + return nRes; + }; + + // Set up the ack type + pCookieData = CreateMsgCookieData(MTYPE_PLAIN, ccs->hContact, dwUin); + +#ifdef _DEBUG + NetLog_Server("Send unicode message - Message cap is %u", CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY)); + NetLog_Server("Send unicode message - Contact status is %u", wRecipientStatus); +#endif + if (dwUin && gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + { + char* utf8msg = make_utf8_string(pszText); + int iRes; + + iRes = icq_SendDirectMessage(dwUin, ccs->hContact, utf8msg, strlennull(utf8msg), 1, pCookieData, CAP_UTF8MSGS); + SAFE_FREE(&utf8msg); + + if (iRes) return iRes; // we succeded, return + } + + if (!dwUin || !CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY)) + { + char* utmp; + char* mng; + char* tmp; + + if (!dwUin) + { + utmp = make_utf8_string(pszText); + mng = MangleXml(utmp, strlennull(utmp)); + SAFE_FREE(&utmp); + tmp = (char*)SAFE_MALLOC(strlennull(mng) + 28); + strcpy(tmp, ""); + strcat(tmp, mng); + SAFE_FREE(&mng); + strcat(tmp, ""); + pszText = make_unicode_string(tmp); + SAFE_FREE(&tmp); + } + + dwCookie = icq_SendChannel1MessageW(dwUin, szUID, ccs->hContact, pszText, pCookieData); + + if (!dwUin) SAFE_FREE(&pszText); + } + else + { + WORD wPriority; + char* utf8msg; + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + utf8msg = make_utf8_string(pszText); + dwCookie = icq_SendChannel2Message(dwUin, utf8msg, strlennull(utf8msg), wPriority, pCookieData, CAP_UTF8MSGS); + + SAFE_FREE(&utf8msg); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_MESSAGE, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + + } + return dwCookie; // Success + } + } + return 0; // Failure +} + + + +int IcqSendUrl(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + CCSDATA* ccs = (CCSDATA*)lParam; + + if (ccs->hContact && ccs->lParam) + { + DWORD dwCookie; + WORD wRecipientStatus; + DWORD dwUin; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL)) + { // Invalid contact + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_URL, ICQTranslate("The receiver has an invalid user ID.")); + return dwCookie; + } + + wRecipientStatus = ICQGetContactStatus(ccs->hContact); + + // Failure + if (!icqOnline) + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_URL, ICQTranslate("You cannot send messages when you are offline.")); + } + // Looks OK + else + { + message_cookie_data* pCookieData; + char* szDesc; + char* szUrl; + char* szBody; + int nBodyLen; + int nDescLen; + int nUrlLen; + + + // Set up the ack type + pCookieData = CreateMsgCookieData(MTYPE_URL, ccs->hContact, dwUin); + + // Format the body + szUrl = (char*)ccs->lParam; + nUrlLen = strlennull(szUrl); + szDesc = (char *)ccs->lParam + nUrlLen + 1; + nDescLen = strlennull(szDesc); + nBodyLen = nUrlLen + nDescLen + 2; + szBody = (char *)_alloca(nBodyLen); + strcpy(szBody, szDesc); + szBody[nDescLen] = (char)0xFE; // Separator + strcpy(szBody + nDescLen + 1, szUrl); + + + if (gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + { + int iRes = icq_SendDirectMessage(dwUin, ccs->hContact, szBody, nBodyLen, 1, pCookieData, NULL); + if (iRes) return iRes; // we succeded, return + } + + // Select channel and send + if (!CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY) || + wRecipientStatus == ID_STATUS_OFFLINE) + { + dwCookie = icq_SendChannel4Message(dwUin, MTYPE_URL, + (WORD)nBodyLen, szBody, pCookieData); + } + else + { + WORD wPriority; + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + dwCookie = icq_SendChannel2Message(dwUin, szBody, nBodyLen, wPriority, pCookieData, NULL); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_URL, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + } + + return dwCookie; // Success + } + } + + return 0; // Failure +} + + + +int IcqSendContacts(WPARAM wParam, LPARAM lParam) +{ + if (lParam) + { + CCSDATA* ccs = (CCSDATA*)lParam; + + if (ccs->hContact && ccs->lParam) + { + int nContacts; + int i; + HANDLE* hContactsList = (HANDLE*)ccs->lParam; + DWORD dwUin; + WORD wRecipientStatus; + DWORD dwCookie; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL)) + { // Invalid contact + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("The receiver has an invalid user ID.")); + return dwCookie; + } + + wRecipientStatus = ICQGetContactStatus(ccs->hContact); + nContacts = HIWORD(ccs->wParam); + + // Failures + if (!icqOnline) + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("You cannot send messages when you are offline.")); + } + else if (!hContactsList || (nContacts < 1) || (nContacts > MAX_CONTACTSSEND)) + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("Bad data (internal error #1)")); + } + // OK + else + { + int nBodyLength; + char szUin[UINMAXLEN]; + char szCount[17]; + struct icq_contactsend_s* contacts = NULL; + uid_str szUid; + + + // Format the body + // This is kinda messy, but there is no simple way to do it. First + // we need to calculate the length of the packet. + if (contacts = (struct icq_contactsend_s*)SAFE_MALLOC(sizeof(struct icq_contactsend_s)*nContacts)) + { + nBodyLength = 0; + for (i = 0; i < nContacts; i++) + { + if (!IsICQContact(hContactsList[i])) + break; // Abort if a non icq contact is found + if (ICQGetContactSettingUID(hContactsList[i], &contacts[i].uin, &szUid)) + break; // Abort if invalid contact + contacts[i].uid = contacts[i].uin?NULL:null_strdup(szUid); + contacts[i].szNick = NickFromHandle(hContactsList[i]); + // Compute this contact's length + nBodyLength += getUIDLen(contacts[i].uin, contacts[i].uid) + 1; + nBodyLength += strlennull(contacts[i].szNick) + 1; + } + + if (i == nContacts) + { + message_cookie_data* pCookieData; + char* pBody; + char* pBuffer; + +#ifdef _DEBUG + NetLog_Server("Sending contacts to %d.", dwUin); +#endif + // Compute count record's length + _itoa(nContacts, szCount, 10); + nBodyLength += strlennull(szCount) + 1; + + // Finally we need to copy the contact data into the packet body + pBuffer = pBody = (char *)SAFE_MALLOC(nBodyLength); + strncpy(pBuffer, szCount, nBodyLength); + pBuffer += strlennull(pBuffer); + *pBuffer++ = (char)0xFE; + for (i = 0; i < nContacts; i++) + { + if (contacts[i].uin) + { + _itoa(contacts[i].uin, szUin, 10); + strcpy(pBuffer, szUin); + } + else + strcpy(pBuffer, contacts[i].uid); + pBuffer += strlennull(pBuffer); + *pBuffer++ = (char)0xFE; + strcpy(pBuffer, contacts[i].szNick); + pBuffer += strlennull(pBuffer); + *pBuffer++ = (char)0xFE; + } + + // Set up the ack type + pCookieData = CreateMsgCookieData(MTYPE_CONTACTS, ccs->hContact, dwUin); + + if (gbDCMsgEnabled && IsDirectConnectionOpen(ccs->hContact, DIRECTCONN_STANDARD)) + { + int iRes = icq_SendDirectMessage(dwUin, ccs->hContact, pBody, nBodyLength, 1, pCookieData, NULL); + + if (iRes) + { + SAFE_FREE(&pBody); + + for(i = 0; i < nContacts; i++) + { // release memory + SAFE_FREE(&contacts[i].szNick); + SAFE_FREE(&contacts[i].uid); + } + + SAFE_FREE(&contacts); + + return iRes; // we succeded, return + } + } + + // Select channel and send + if (!CheckContactCapabilities(ccs->hContact, CAPF_SRV_RELAY) || + wRecipientStatus == ID_STATUS_OFFLINE) + { + dwCookie = icq_SendChannel4Message(dwUin, MTYPE_CONTACTS, + (WORD)nBodyLength, pBody, pCookieData); + } + else + { + WORD wPriority; + + if (wRecipientStatus == ID_STATUS_ONLINE || wRecipientStatus == ID_STATUS_FREECHAT) + wPriority = 0x0001; + else + wPriority = 0x0021; + + dwCookie = icq_SendChannel2Message(dwUin, pBody, nBodyLength, wPriority, pCookieData, NULL); + } + + // This will stop the message dialog from waiting for the real message delivery ack + if (pCookieData->nAckType == ACKTYPE_NONE) + { + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_SUCCESS, ACKTYPE_CONTACTS, NULL); + // We need to free this here since we will never see the real ack + // The actual cookie value will still have to be returned to the message dialog though + ReleaseCookie(dwCookie); + } + SAFE_FREE(&pBody); + } + else + { + dwCookie = GenerateCookie(0); + icq_SendProtoAck(ccs->hContact, dwCookie, ACKRESULT_FAILED, ACKTYPE_CONTACTS, ICQTranslate("Bad data (internal error #2)")); + } + + for(i = 0; i < nContacts; i++) + { + SAFE_FREE(&contacts[i].szNick); + SAFE_FREE(&contacts[i].uid); + } + + SAFE_FREE(&contacts); + } + else + { + dwCookie = 0; + } + } + + return dwCookie; + } + } + + // Exit with Failure + return 0; +} + + + +int IcqSendFile(WPARAM wParam, LPARAM lParam) +{ + if (lParam && icqOnline) + { + CCSDATA* ccs = (CCSDATA*)lParam; + + if (ccs->hContact && ccs->lParam && ccs->wParam) + { + HANDLE hContact = ccs->hContact; + char** files = (char**)ccs->lParam; + char* pszDesc = (char*)ccs->wParam; + DWORD dwUin; + + if (ICQGetContactSettingUID(hContact, &dwUin, NULL)) + return 0; // Invalid contact + + if (dwUin) + { + if (ICQGetContactStatus(hContact) != ID_STATUS_OFFLINE) + { + WORD wClientVersion; + + wClientVersion = ICQGetContactSettingWord(ccs->hContact, "Version", 7); + if (wClientVersion < 7) + { + NetLog_Server("IcqSendFile() can't send to version %u", wClientVersion); + } + else + { + int i; + filetransfer* ft; + struct _stat statbuf; + + // Initialize filetransfer struct + ft = CreateFileTransfer(hContact, dwUin, (wClientVersion == 7) ? 7: 8); + + for (ft->dwFileCount = 0; files[ft->dwFileCount]; ft->dwFileCount++); + ft->files = (char **)SAFE_MALLOC(sizeof(char *) * ft->dwFileCount); + ft->dwTotalSize = 0; + for (i = 0; i < (int)ft->dwFileCount; i++) + { + ft->files[i] = null_strdup(files[i]); + + if (_stat(files[i], &statbuf)) + NetLog_Server("IcqSendFile() was passed invalid filename(s)"); + else + ft->dwTotalSize += statbuf.st_size; + } + ft->szDescription = null_strdup(pszDesc); + ft->dwTransferSpeed = 100; + ft->sending = 1; + ft->fileId = -1; + ft->iCurrentFile = 0; + ft->dwCookie = AllocateCookie(CKT_FILE, 0, dwUin, ft); + ft->hConnection = NULL; + + // Send file transfer request + { + char szFiles[64]; + char* pszFiles; + + + NetLog_Server("Init file send"); + + if (ft->dwFileCount == 1) + { + pszFiles = strrchr(ft->files[0], '\\'); + if (pszFiles) + pszFiles++; + else + pszFiles = ft->files[0]; + } + else + { + null_snprintf(szFiles, 64, ICQTranslate("%d Files"), ft->dwFileCount); + pszFiles = szFiles; + } + + // Send packet + { + if (ft->nVersion == 7) + { + if (gbDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD)) + { + int iRes = icq_sendFileSendDirectv7(ft, pszFiles); + if (iRes) return (int)(HANDLE)ft; // Success + } + NetLog_Server("Sending v%u file transfer request through server", 7); + icq_sendFileSendServv7(ft, pszFiles); + } + else + { + if (gbDCMsgEnabled && IsDirectConnectionOpen(hContact, DIRECTCONN_STANDARD)) + { + int iRes = icq_sendFileSendDirectv8(ft, pszFiles); + if (iRes) return (int)(HANDLE)ft; // Success + } + NetLog_Server("Sending v%u file transfer request through server", 8); + icq_sendFileSendServv8(ft, pszFiles, ACKTYPE_NONE); + } + } + } + + return (int)(HANDLE)ft; // Success + } + } + } + } + } + + return 0; // Failure +} + + +int IcqSendAuthRequest(WPARAM wParam, LPARAM lParam) +{ + if (lParam && icqOnline) + { + CCSDATA* ccs = (CCSDATA*)lParam; + DWORD dwUin; + uid_str szUid; + + if (ccs->hContact) + { + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, &szUid)) + return 1; // Invalid contact + + if (dwUin && ccs->lParam) + { + char *text = (char *)ccs->lParam; + char *utf; + + utf = ansi_to_utf8(text); // Miranda is ANSI only here + + icq_sendAuthReqServ(dwUin, szUid, utf); + + SAFE_FREE(&utf); + + return 0; // Success + } + } + } + + return 1; // Failure +} + + + +int IcqSendYouWereAdded(WPARAM wParam, LPARAM lParam) +{ + if (lParam && icqOnline) + { + CCSDATA* ccs = (CCSDATA*)lParam; + + if (ccs->hContact) + { + DWORD dwUin, dwMyUin; + + if (ICQGetContactSettingUID(ccs->hContact, &dwUin, NULL)) + return 1; // Invalid contact + + dwMyUin = ICQGetContactSettingUIN(NULL); + + if (dwUin) + { + icq_sendYouWereAddedServ(dwUin, dwMyUin); + + return 0; // Success + } + } + } + + return 1; // Failure +} + + + +int IcqGrantAuthorization(WPARAM wParam, LPARAM lParam) +{ + if (gnCurrentStatus != ID_STATUS_OFFLINE && gnCurrentStatus != ID_STATUS_CONNECTING && wParam != 0) + { + DWORD dwUin; + uid_str szUid; + + if (ICQGetContactSettingUID((HANDLE)wParam, &dwUin, &szUid)) + return 0; // Invalid contact + + // send without reason, do we need any ? + icq_sendGrantAuthServ(dwUin, szUid, NULL); + } + + return 0; +} + + + +int IcqRevokeAuthorization(WPARAM wParam, LPARAM lParam) +{ + if (gnCurrentStatus != ID_STATUS_OFFLINE && gnCurrentStatus != ID_STATUS_CONNECTING && wParam != 0) + { + DWORD dwUin; + uid_str szUid; + char str[MAX_PATH], cap[MAX_PATH]; + + if (ICQGetContactSettingUID((HANDLE)wParam, &dwUin, &szUid)) + return 0; // Invalid contact + + if (MessageBoxUtf(NULL, ICQTranslateUtfStatic("Are you sure you want to revoke user's autorisation (this will remove you from his/her list on some clients) ?", str), ICQTranslateUtfStatic("Confirmation", cap), MB_ICONQUESTION | MB_YESNO) != IDYES) + return 0; + + icq_sendRevokeAuthServ(dwUin, szUid); + } + + return 0; +} + + + +int IcqSendUserIsTyping(WPARAM wParam, LPARAM lParam) +{ + int nResult = 1; + HANDLE hContact = (HANDLE)wParam; + + + if (hContact && icqOnline) + { + if (CheckContactCapabilities(hContact, CAPF_TYPING)) + { + switch (lParam) + { + case PROTOTYPE_SELFTYPING_ON: + sendTypingNotification(hContact, MTN_BEGUN); + nResult = 0; + break; + + case PROTOTYPE_SELFTYPING_OFF: + sendTypingNotification(hContact, MTN_FINISHED); + nResult = 0; + break; + + default: + break; + } + } + } + + return nResult; +} + + + +/* + --------------------------------- + | Receiving | + --------------------------------- +*/ + +int IcqRecvAwayMsg(WPARAM wParam,LPARAM lParam) +{ + CCSDATA* ccs = (CCSDATA*)lParam; + PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; + + + ICQBroadcastAck(ccs->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, + (HANDLE)pre->lParam, (LPARAM)pre->szMessage); + + return 0; +} + + + +int IcqRecvMessage(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA* ccs = (CCSDATA*)lParam; + PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; + + + SetContactHidden(ccs->hContact, 0); + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = gpszICQProtoName; + dbei.timestamp = pre->timestamp; + dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = strlennull(pre->szMessage) + 1; + if ( pre->flags & PREF_UNICODE ) + dbei.cbBlob *= ( sizeof( wchar_t )+1 ); + dbei.pBlob = (PBYTE)pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei); + + // stop contact from typing - some clients do not sent stop notify + if (CheckContactCapabilities(ccs->hContact, CAPF_TYPING)) + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)ccs->hContact, PROTOTYPE_CONTACTTYPING_OFF); + + return 0; +} + + + +int IcqRecvUrl(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA* ccs = (CCSDATA*)lParam; + PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; + char* szDesc; + + + SetContactHidden(ccs->hContact, 0); + + szDesc = pre->szMessage + strlennull(pre->szMessage) + 1; + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = gpszICQProtoName; + dbei.timestamp = pre->timestamp; + dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; + dbei.eventType = EVENTTYPE_URL; + dbei.cbBlob = strlennull(pre->szMessage) + strlennull(szDesc) + 2; + dbei.pBlob = (PBYTE)pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei); + + return 0; +} + + + +int IcqRecvContacts(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei = {0}; + CCSDATA* ccs = (CCSDATA*)lParam; + PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; + ICQSEARCHRESULT** isrList = (ICQSEARCHRESULT**)pre->szMessage; + int i; + char szUin[UINMAXLEN]; + PBYTE pBlob; + + + SetContactHidden(ccs->hContact, 0); + + for (i = 0; i < pre->lParam; i++) + { + dbei.cbBlob += strlennull(isrList[i]->hdr.nick) + 2; // both trailing zeros + if (isrList[i]->uin) + dbei.cbBlob += getUINLen(isrList[i]->uin); + else + dbei.cbBlob += strlennull(isrList[i]->uid); + } + dbei.cbSize = sizeof(dbei); + dbei.szModule = gpszICQProtoName; + dbei.timestamp = pre->timestamp; + dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; + dbei.eventType = EVENTTYPE_CONTACTS; + dbei.pBlob = (PBYTE)_alloca(dbei.cbBlob); + for (i = 0, pBlob = dbei.pBlob; i < pre->lParam; i++) + { + strcpy(pBlob, isrList[i]->hdr.nick); + pBlob += strlennull(pBlob) + 1; + if (isrList[i]->uin) + { + _itoa(isrList[i]->uin, szUin, 10); + strcpy(pBlob, szUin); + } + else // aim contact + strcpy(pBlob, isrList[i]->uid); + pBlob += strlennull(pBlob) + 1; + } + + CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei); + + return 0; +} + + + +int IcqRecvFile(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA* ccs = (CCSDATA*)lParam; + PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; + char* szDesc; + char* szFile; + + + SetContactHidden(ccs->hContact, 0); + + szFile = pre->szMessage + sizeof(DWORD); + szDesc = szFile + strlennull(szFile) + 1; + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = gpszICQProtoName; + dbei.timestamp = pre->timestamp; + dbei.flags = (pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; + dbei.eventType = EVENTTYPE_FILE; + dbei.cbBlob = sizeof(DWORD) + strlennull(szFile) + strlennull(szDesc) + 2; + dbei.pBlob = (PBYTE)pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei); + + return 0; +} + + + +int IcqRecvAuth(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA* ccs = (CCSDATA*)lParam; + PROTORECVEVENT* pre = (PROTORECVEVENT*)ccs->lParam; + + + SetContactHidden(ccs->hContact, 0); + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = gpszICQProtoName; + dbei.timestamp = pre->timestamp; + dbei.flags=(pre->flags & PREF_CREATEREAD) ? DBEF_READ : 0; + dbei.eventType = EVENTTYPE_AUTHREQUEST; + dbei.cbBlob = pre->lParam; + dbei.pBlob = (PBYTE)pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM)NULL, (LPARAM)&dbei); + + return 0; +} -- cgit v1.2.3