From c015ec458520935c407aa1b2ce1d004c5c5c8a61 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 Apr 2014 08:46:04 +0000 Subject: ICQCorp adopted - needs Unicode fixes git-svn-id: http://svn.miranda-ng.org/main/trunk@8980 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/ICQCorp/ICQCorp_10.vcxproj | 219 +++ protocols/ICQCorp/ICQCorp_10.vcxproj.filters | 97 ++ protocols/ICQCorp/ICQCorp_12.vcxproj | 221 +++ protocols/ICQCorp/ICQCorp_12.vcxproj.filters | 97 ++ protocols/ICQCorp/res/corp.ico | Bin 0 -> 318 bytes protocols/ICQCorp/res/resource.rc | 147 ++ protocols/ICQCorp/res/version.rc | 38 + protocols/ICQCorp/src/corp.cpp | 118 ++ protocols/ICQCorp/src/corp.h | 71 + protocols/ICQCorp/src/event.cpp | 111 ++ protocols/ICQCorp/src/event.h | 52 + protocols/ICQCorp/src/options.cpp | 90 + protocols/ICQCorp/src/options.h | 29 + protocols/ICQCorp/src/packet.cpp | 217 +++ protocols/ICQCorp/src/packet.h | 62 + protocols/ICQCorp/src/protocol.cpp | 2339 ++++++++++++++++++++++++++ protocols/ICQCorp/src/protocol.h | 223 +++ protocols/ICQCorp/src/resource.h | 46 + protocols/ICQCorp/src/services.cpp | 589 +++++++ protocols/ICQCorp/src/socket.cpp | 399 +++++ protocols/ICQCorp/src/socket.h | 85 + protocols/ICQCorp/src/stdafx.cpp | 18 + protocols/ICQCorp/src/transfer.cpp | 505 ++++++ protocols/ICQCorp/src/transfer.h | 75 + protocols/ICQCorp/src/user.cpp | 160 ++ protocols/ICQCorp/src/user.h | 52 + protocols/ICQCorp/src/version.h | 14 + 27 files changed, 6074 insertions(+) create mode 100644 protocols/ICQCorp/ICQCorp_10.vcxproj create mode 100644 protocols/ICQCorp/ICQCorp_10.vcxproj.filters create mode 100644 protocols/ICQCorp/ICQCorp_12.vcxproj create mode 100644 protocols/ICQCorp/ICQCorp_12.vcxproj.filters create mode 100644 protocols/ICQCorp/res/corp.ico create mode 100644 protocols/ICQCorp/res/resource.rc create mode 100644 protocols/ICQCorp/res/version.rc create mode 100644 protocols/ICQCorp/src/corp.cpp create mode 100644 protocols/ICQCorp/src/corp.h create mode 100644 protocols/ICQCorp/src/event.cpp create mode 100644 protocols/ICQCorp/src/event.h create mode 100644 protocols/ICQCorp/src/options.cpp create mode 100644 protocols/ICQCorp/src/options.h create mode 100644 protocols/ICQCorp/src/packet.cpp create mode 100644 protocols/ICQCorp/src/packet.h create mode 100644 protocols/ICQCorp/src/protocol.cpp create mode 100644 protocols/ICQCorp/src/protocol.h create mode 100644 protocols/ICQCorp/src/resource.h create mode 100644 protocols/ICQCorp/src/services.cpp create mode 100644 protocols/ICQCorp/src/socket.cpp create mode 100644 protocols/ICQCorp/src/socket.h create mode 100644 protocols/ICQCorp/src/stdafx.cpp create mode 100644 protocols/ICQCorp/src/transfer.cpp create mode 100644 protocols/ICQCorp/src/transfer.h create mode 100644 protocols/ICQCorp/src/user.cpp create mode 100644 protocols/ICQCorp/src/user.h create mode 100644 protocols/ICQCorp/src/version.h diff --git a/protocols/ICQCorp/ICQCorp_10.vcxproj b/protocols/ICQCorp/ICQCorp_10.vcxproj new file mode 100644 index 0000000000..ecc9ef71cb --- /dev/null +++ b/protocols/ICQCorp/ICQCorp_10.vcxproj @@ -0,0 +1,219 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AD0D0500-CE7D-417D-9C36-3620D56CA6D4} + ICQCorp + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Plugins\ + $(SolutionDir)$(Configuration)64\Plugins\ + $(SolutionDir)$(Configuration)\Plugins\ + $(SolutionDir)$(Configuration)\Plugins\ + true + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + MultiThreadedDebugDLL + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + true + Windows + $(ProfileDir)..\..\bin12\lib + false + $(IntDir)$(TargetName).lib + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + MultiThreadedDebugDLL + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + true + Windows + $(ProfileDir)..\..\bin12\lib + false + $(IntDir)$(TargetName).lib + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + Full + OnlyExplicitInline + Size + ..\..\include;%(AdditionalIncludeDirectories) + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + Windows + $(ProfileDir)..\..\bin12\lib + true + true + true + false + $(IntDir)$(TargetName).lib + /PDBALTPATH:%_PDB% %(AdditionalOptions) + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + Full + OnlyExplicitInline + Size + ..\..\include;%(AdditionalIncludeDirectories) + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + Windows + $(ProfileDir)..\..\bin12\lib + true + true + true + false + $(IntDir)$(TargetName).lib + /PDBALTPATH:%_PDB% %(AdditionalOptions) + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/protocols/ICQCorp/ICQCorp_10.vcxproj.filters b/protocols/ICQCorp/ICQCorp_10.vcxproj.filters new file mode 100644 index 0000000000..a0f5be6393 --- /dev/null +++ b/protocols/ICQCorp/ICQCorp_10.vcxproj.filters @@ -0,0 +1,97 @@ + + + + + {69c79660-1836-402a-9ec2-3b75f4396bc2} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2873240-bfbb-49ad-b400-228addec6702} + h;hpp;hxx;hm;inl;inc + + + {41cb7826-be3c-4d3a-9f8d-1ba6b379207b} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;r + + + {3e399225-12c1-4207-95d1-b5adc3407673} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + + + Resource Files\Icons + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/protocols/ICQCorp/ICQCorp_12.vcxproj b/protocols/ICQCorp/ICQCorp_12.vcxproj new file mode 100644 index 0000000000..ce09d216c3 --- /dev/null +++ b/protocols/ICQCorp/ICQCorp_12.vcxproj @@ -0,0 +1,221 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {AD0D0500-CE7D-417D-9C36-3620D56CA6D4} + ICQCorp + + + + DynamicLibrary + v120_xp + MultiByte + true + + + DynamicLibrary + v120_xp + MultiByte + true + + + DynamicLibrary + v120_xp + MultiByte + + + DynamicLibrary + v120_xp + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60610.1 + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\ + $(SolutionDir)$(Configuration)64\Plugins\ + $(SolutionDir)$(Configuration)64\Plugins\ + $(SolutionDir)$(Configuration)\Plugins\ + $(SolutionDir)$(Configuration)\Plugins\ + true + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + MultiThreadedDebugDLL + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + true + Windows + $(ProfileDir)..\..\bin12\lib + false + $(IntDir)$(TargetName).lib + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + Disabled + ..\..\include;%(AdditionalIncludeDirectories) + _DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + MultiThreadedDebugDLL + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + true + Windows + $(ProfileDir)..\..\bin12\lib + false + $(IntDir)$(TargetName).lib + + + _DEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + Full + OnlyExplicitInline + Size + ..\..\include;%(AdditionalIncludeDirectories) + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + Windows + $(ProfileDir)..\..\bin12\lib + true + true + true + false + $(IntDir)$(TargetName).lib + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + Full + OnlyExplicitInline + Size + ..\..\include;%(AdditionalIncludeDirectories) + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + false + Level3 + corp.h + Use + + + ws2_32.lib;%(AdditionalDependencies) + Windows + $(ProfileDir)..\..\bin12\lib + true + true + true + false + $(IntDir)$(TargetName).lib + + + NDEBUG;%(PreprocessorDefinitions) + ..\..\include;..\..\include\msapi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + + + + + \ No newline at end of file diff --git a/protocols/ICQCorp/ICQCorp_12.vcxproj.filters b/protocols/ICQCorp/ICQCorp_12.vcxproj.filters new file mode 100644 index 0000000000..a0f5be6393 --- /dev/null +++ b/protocols/ICQCorp/ICQCorp_12.vcxproj.filters @@ -0,0 +1,97 @@ + + + + + {69c79660-1836-402a-9ec2-3b75f4396bc2} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2873240-bfbb-49ad-b400-228addec6702} + h;hpp;hxx;hm;inl;inc + + + {41cb7826-be3c-4d3a-9f8d-1ba6b379207b} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;r + + + {3e399225-12c1-4207-95d1-b5adc3407673} + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + + + Resource Files\Icons + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/protocols/ICQCorp/res/corp.ico b/protocols/ICQCorp/res/corp.ico new file mode 100644 index 0000000000..5421e31fdf Binary files /dev/null and b/protocols/ICQCorp/res/corp.ico differ diff --git a/protocols/ICQCorp/res/resource.rc b/protocols/ICQCorp/res/resource.rc new file mode 100644 index 0000000000..f68b019090 --- /dev/null +++ b/protocols/ICQCorp/res/resource.rc @@ -0,0 +1,147 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian (Russia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) + + +/////////////////////////////////////////////////////////////////////////////// +// +// Icon's +// +/////////////////////////////////////////////////////////////////////////////// + +IDI_ICQCORP ICON "corp.ico" + +/////////////////////////////////////////////////////////////////////////////// +// +// Dialog's +// +/////////////////////////////////////////////////////////////////////////////// + +IDD_INFO_ICQCORP DIALOGEX 0, 0, 222, 132 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + LTEXT "UIN:",IDC_STATIC,5,5,56,8 + EDITTEXT IDC_INFO_UIN,61,5,156,8,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "External IP:",IDC_STATIC,5,18,56,8 + EDITTEXT IDC_INFO_IP,61,18,83,8,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "Internal IP:",IDC_STATIC,5,31,56,8 + EDITTEXT IDC_INFO_REALIP,61,31,156,8,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "Port:",IDC_STATIC,5,44,56,8 + EDITTEXT IDC_INFO_PORT,61,44,156,8,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "ICQ Version:",IDC_STATIC,5,57,56,8 + EDITTEXT IDC_INFO_VERSION,61,57,156,8,ES_AUTOHSCROLL | + ES_READONLY | NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "Miranda Version:",IDC_STATIC,5,70,56,8 + EDITTEXT IDC_INFO_MIRVER,61,70,156,8,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP + LTEXT "Ping:",IDC_STATIC,147,18,34,8 + EDITTEXT IDC_INFO_PING,182,18,35,8,ES_AUTOHSCROLL | ES_READONLY | + NOT WS_BORDER | NOT WS_TABSTOP +END + +/////////////////////////////////////////////////////////////////////////////// + +IDD_OPT_ICQCORP DIALOGEX 0, 0, 261, 160 +STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + GROUPBOX "ICQ Corp",IDC_STATIC,4,4,253,147 + RTEXT "Login Server:",IDC_STATIC,12,34,44,8 + EDITTEXT IDC_OPT_SERVER,64,32,100,12,ES_AUTOHSCROLL + RTEXT "Port:",IDC_STATIC,173,34,21,11 + EDITTEXT IDC_OPT_PORT,204,32,40,12,ES_AUTOHSCROLL + RTEXT "ICQ#:",IDC_STATIC,15,65,42,8 + EDITTEXT IDC_OPT_UIN,64,63,100,12,ES_AUTOHSCROLL | ES_NUMBER + RTEXT "Password:",IDC_STATIC,15,79,42,8 + EDITTEXT IDC_OPT_PASSWORD,64,78,100,12,ES_PASSWORD | + ES_AUTOHSCROLL + LTEXT "You will need to reconnect to the ICQ network for the changes you have made on this page to take effect.", + IDC_OPT_RECONNECT,14,119,237,16,NOT WS_VISIBLE +END + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#endif // Russian (Russia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/ICQCorp/res/version.rc b/protocols/ICQCorp/res/version.rc new file mode 100644 index 0000000000..5bfbab4754 --- /dev/null +++ b/protocols/ICQCorp/res/version.rc @@ -0,0 +1,38 @@ +// Microsoft Visual C++ generated resource script. +// +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + +#include "afxres.h" +#include "..\src\version.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "FileDescription", __DESCRIPTION + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + VALUE "ProductName", __PLUGIN_NAME + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/protocols/ICQCorp/src/corp.cpp b/protocols/ICQCorp/src/corp.cpp new file mode 100644 index 0000000000..ef8bff0dd8 --- /dev/null +++ b/protocols/ICQCorp/src/corp.cpp @@ -0,0 +1,118 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +/////////////////////////////////////////////////////////////////////////////// + +HINSTANCE hInstance; +char protoName[64]; +int hLangpack; + +PLUGININFOEX pluginInfo = +{ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE +}; + +/////////////////////////////////////////////////////////////////////////////// + +BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD reason, LPVOID lpReserved) +{ + hInstance = hModule; + if (reason == DLL_PROCESS_ATTACH) DisableThreadLibraryCalls(hModule); + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) int Unload() +{ + UnloadServices(); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) int Load() +{ + mir_getLP(&pluginInfo); + + PROTOCOLDESCRIPTOR pd = { PROTOCOLDESCRIPTOR_V3_SIZE }; + pd.szName = protoName; + pd.type = PROTOTYPE_PROTOCOL; + + char fileName[MAX_PATH]; + WIN32_FIND_DATA findData; + + GetModuleFileName(hInstance, fileName, MAX_PATH); + FindClose(FindFirstFile(fileName, &findData)); + findData.cFileName[strlen(findData.cFileName) - 4] = 0; + strcpy(protoName, findData.cFileName); + + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); + + LoadServices(); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD Version) +{ + return &pluginInfo; +} + +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _DEBUG +void T(char *format, ...) +{ + char buffer[8196], bufferTime[64]; + va_list list; + SYSTEMTIME t; + + va_start(list, format); + vsprintf(buffer, format, list); + va_end(list); + + GetLocalTime(&t); + sprintf(bufferTime, "%.2d:%.2d:%.2d.%.3d ", t.wHour, t.wMinute, t.wSecond, t.wMilliseconds); + + static HANDLE hFile = INVALID_HANDLE_VALUE; + DWORD result; + + if (hFile == INVALID_HANDLE_VALUE) + { + hFile = CreateFile("ICQ Corp.log", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL); + SetFilePointer(hFile, 0, 0, FILE_END); + } + WriteFile(hFile, bufferTime, (DWORD)strlen(bufferTime), &result, NULL); + WriteFile(hFile, buffer, (DWORD)strlen(buffer), &result, NULL); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/corp.h b/protocols/ICQCorp/src/corp.h new file mode 100644 index 0000000000..444f40382b --- /dev/null +++ b/protocols/ICQCorp/src/corp.h @@ -0,0 +1,71 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef corp_h +#define corp_h + +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "user.h" +#include "transfer.h" +#include "packet.h" +#include "socket.h" +#include "event.h" +#include "protocol.h" +#include "options.h" +#include "resource.h" +#include "version.h" + + +/////////////////////////////////////////////////////////////////////////////// + +extern HINSTANCE hInstance; +extern char protoName[64]; + +extern int LoadServices(); +extern int UnloadServices(); + +#ifdef _DEBUG +extern void T(char *format, ...); +#else +inline void T(char *format, ...) {}; +#endif + +/////////////////////////////////////////////////////////////////////////////// + +#endif \ No newline at end of file diff --git a/protocols/ICQCorp/src/event.cpp b/protocols/ICQCorp/src/event.cpp new file mode 100644 index 0000000000..69f2ac85db --- /dev/null +++ b/protocols/ICQCorp/src/event.cpp @@ -0,0 +1,111 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +std::vector icqEvents; + +/////////////////////////////////////////////////////////////////////////////// + +void WINAPI eventTimerProc(HWND hWnd, UINT Msg, UINT_PTR hTimer, DWORD Time) +{ + unsigned int i; + + KillTimer(NULL, hTimer); + for (i=0; ihTimer) icqEvents[i]->noAck(); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *getEvent(SOCKET hSocket, unsigned int sequence) +{ + unsigned int i; + + for (i=0; iisEvent(hSocket, sequence)) return icqEvents[i]; + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent::ICQEvent(unsigned short theCmd, unsigned short theSubCmd, unsigned int theSequence, + unsigned int theUin, Socket *theSocket, Packet *thePacket, int theReply) +{ + cmd = theCmd; + subCmd = theSubCmd; + sequence = theSequence; + uin = theUin; + socket = theSocket; + packet = new Packet(thePacket); + reply = theReply; + + hTimer = NULL; + retries = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent::~ICQEvent() +{ + stop(); + delete packet; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQEvent::start() +{ + // send the packet + if (!socket->sendPacket(*packet)) return false; + + if (cmd != ICQ_CMDxTCP_START) hTimer = SetTimer(NULL, 0, MAX_WAIT_ACK, (TIMERPROC)eventTimerProc); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQEvent::stop() +{ + if (hTimer) + { + KillTimer(NULL, hTimer); + hTimer = NULL; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQEvent::isEvent(SOCKET hSocket, unsigned long theSequence) +{ + return socket->handleVal == hSocket && sequence == theSequence; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQEvent::noAck() +{ + hTimer = NULL; + if (socket->connected() && retries < MAX_SERVER_RETRIES && cmd != ICQ_CMDxTCP_START) + { + retries++; + start(); + } + else icq.doneEvent(false, socket->handleVal, sequence); +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/event.h b/protocols/ICQCorp/src/event.h new file mode 100644 index 0000000000..ee204927e2 --- /dev/null +++ b/protocols/ICQCorp/src/event.h @@ -0,0 +1,52 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef event_h +#define event_h + +/////////////////////////////////////////////////////////////////////////////// + +class ICQEvent +{ +public: + ICQEvent(unsigned short theCmd, unsigned short theSubCmd, unsigned int theSequence, unsigned int theUin, Socket *theSocket, Packet *thePacket, int theReply); + ~ICQEvent(); + bool start(); + void stop(); + bool isEvent(SOCKET hSocket, unsigned long theSequence); + void noAck(); + unsigned short cmd, subCmd; + unsigned int uin, sequence; + int reply; + unsigned int hTimer; + Packet *packet; +protected: + unsigned short retries; + Socket *socket; +}; + +/////////////////////////////////////////////////////////////////////////////// + +extern std::vector icqEvents; + +extern ICQEvent *getEvent(SOCKET hSocket, unsigned int sequence); + +/////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/protocols/ICQCorp/src/options.cpp b/protocols/ICQCorp/src/options.cpp new file mode 100644 index 0000000000..aab67117c7 --- /dev/null +++ b/protocols/ICQCorp/src/options.cpp @@ -0,0 +1,90 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +/////////////////////////////////////////////////////////////////////////////// + +static BOOL CALLBACK icqOptionsDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + char str[128]; + + switch (msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hWnd); + SetDlgItemInt(hWnd, IDC_OPT_UIN, db_get_dw(NULL, protoName, "UIN", 0), FALSE); + if (!db_get(NULL, protoName, "Password", &dbv)) + { + SetDlgItemText(hWnd, IDC_OPT_PASSWORD, dbv.pszVal); + db_free(&dbv); + } + if(!db_get(NULL, protoName, "Server", &dbv)) + { + SetDlgItemText(hWnd, IDC_OPT_SERVER, dbv.pszVal); + db_free(&dbv); + } + SetDlgItemInt(hWnd, IDC_OPT_PORT, db_get_w(NULL, protoName, "Port", 4000), FALSE); + ShowWindow(GetDlgItem(hWnd, IDC_OPT_RECONNECT), SW_HIDE); + return TRUE; + + case WM_NOTIFY: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + db_set_dw(NULL, protoName, "UIN", (DWORD)GetDlgItemInt(hWnd, IDC_OPT_UIN, NULL, FALSE)); + GetDlgItemText(hWnd, IDC_OPT_PASSWORD, str, sizeof(str)); + db_set_s(NULL, protoName, "Password", str); + GetDlgItemText(hWnd, IDC_OPT_SERVER, str, sizeof(str)); + db_set_s(NULL, protoName, "Server", str); + db_set_w(NULL, protoName, "Port", (WORD)GetDlgItemInt(hWnd, IDC_OPT_PORT, NULL, FALSE)); + return TRUE; + } + break; + + case WM_COMMAND: + if ((LOWORD(wParam) == IDC_OPT_UIN || LOWORD(wParam) == IDC_OPT_PASSWORD || LOWORD(wParam) == IDC_OPT_SERVER || LOWORD(wParam) == IDC_OPT_PORT) && (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus())) return 0; + SendMessage(GetParent(hWnd), PSM_CHANGED, 0, 0); + break; + } + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////// + +int icqOptionsInitialise(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + + odp.cbSize = sizeof(odp); + odp.position = -800000000; + odp.pszTitle = Translate(protoName); + odp.pfnDlgProc = (DLGPROC)icqOptionsDlgProc; + odp.pszTemplate = MAKEINTRESOURCE(IDD_OPT_ICQCORP); + odp.hInstance = hInstance; + odp.pszGroup = Translate("Network"); + odp.flags = ODPF_BOLDGROUPS; +// odp.nIDBottomSimpleControl = IDC_STICQGROUP; + Options_AddPage(wParam, &odp); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/options.h b/protocols/ICQCorp/src/options.h new file mode 100644 index 0000000000..a0254cd3b9 --- /dev/null +++ b/protocols/ICQCorp/src/options.h @@ -0,0 +1,29 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef options_h +#define options_h + +/////////////////////////////////////////////////////////////////////////////// + +extern int icqOptionsInitialise(WPARAM wParam, LPARAM lParam); + +/////////////////////////////////////////////////////////////////////////////// + +#endif \ No newline at end of file diff --git a/protocols/ICQCorp/src/packet.cpp b/protocols/ICQCorp/src/packet.cpp new file mode 100644 index 0000000000..0baebee9a7 --- /dev/null +++ b/protocols/ICQCorp/src/packet.cpp @@ -0,0 +1,217 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +/////////////////////////////////////////////////////////////////////////////// + +Packet::Packet() +{ + maxSize = MAX_PACKET_SIZE; + buff = new char[maxSize]; + nextData = buff; + sizeVal = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet::Packet(Packet *packet) +{ + maxSize = packet->maxSize; + buff = new char[maxSize]; + nextData = buff + (packet->nextData - packet->buff); + sizeVal = packet->sizeVal; + memcpy(buff, packet->buff, sizeVal); +} + +/////////////////////////////////////////////////////////////////////////////// +/* +Packet::Packet(char *newBuff, unsigned long buffSize) +{ + maxSize = MAX_PACKET_SIZE; + if (buffSize > maxSize) buffSize = maxSize; + buff = new char[maxSize]; + memcpy(buff, newBuff, buffSize); + nextData = buff; + sizeVal = buffSize; +} + +/////////////////////////////////////////////////////////////////////////////// +*/ +Packet::~Packet() +{ + delete [] buff; +} + +/////////////////////////////////////////////////////////////////////////////// + +void Packet::clearPacket() +{ + nextData = buff; + sizeVal = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +void Packet::add(unsigned int s) +{ + nextData += s; + sizeVal += s; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator << (unsigned int data) +{ + *(unsigned int*)nextData = data; + sizeVal += sizeof(unsigned int); + nextData += sizeof(unsigned int); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator << (unsigned short data) +{ + *(unsigned short*)nextData = data; + sizeVal += sizeof(unsigned short); + nextData += sizeof(unsigned short); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator << (unsigned char data) +{ + *(unsigned char*)nextData = data; + sizeVal += sizeof(unsigned char); + nextData += sizeof(unsigned char); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator << (char *data) +{ + unsigned int s = (unsigned int)strlen(data) + 1; + operator << ((unsigned short)s); + memcpy(nextData, data, s); + sizeVal += s; + nextData += s; + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator << (Packet *packet) +{ + unsigned int s = packet->dataSize(); + memcpy(nextData, packet->nextData, s); + sizeVal += s; + nextData += s; + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator >> (unsigned int &in) +{ + if (nextData+sizeof(unsigned int) > buff+sizeVal) in = 0; + else + { + in = *(unsigned int*)nextData; + nextData += sizeof(unsigned int); + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator >> (unsigned short &in) +{ + if (nextData+sizeof(unsigned short) > buff+sizeVal) in = 0; + else + { + in = *(unsigned short*)nextData; + nextData += sizeof(unsigned short); + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator >> (unsigned char &in) +{ + if (nextData+sizeof(unsigned char) > buff+sizeVal) in = 0; + else + { + in = *(unsigned char*)nextData; + nextData += sizeof(unsigned char); + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +Packet &Packet::operator >> (char *&in) +{ + unsigned short s; + + operator >> (s); + if (nextData+s > buff+sizeVal) in = 0; + else + { + if (in == NULL) in = new char[s]; + memcpy(in, nextData, s); + nextData += s; + } + return *this; +} + +/////////////////////////////////////////////////////////////////////////////// + +char *Packet::print() +{ + unsigned int i; + static char p[8196]; + char *pPos = p; + + for (i=0; i ' ') pPos[48 - (i % 16)*2 + 1] = buff[i]; + + pPos += 3; + if ((i+1) % 16 == 0) + { + pPos[0] = ' '; + pPos += 18; + } + } + if (sizeVal % 16 != 0) pPos[0] = ' '; + return p; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/packet.h b/protocols/ICQCorp/src/packet.h new file mode 100644 index 0000000000..7ed15f24a5 --- /dev/null +++ b/protocols/ICQCorp/src/packet.h @@ -0,0 +1,62 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef packet_h +#define packet_h + +const int MAX_PACKET_SIZE = 8192; + +/////////////////////////////////////////////////////////////////////////////// + +class Packet +{ +public: + Packet(); + Packet(Packet *packet); +// Packet(char *newBuff, unsigned long buffSize); + ~Packet(); + void clearPacket(); + void reset() { nextData = buff; }; + void add(unsigned int s); + char *data() { return nextData; }; + unsigned int size() { return sizeVal; }; + unsigned int dataSize() { return buff + sizeVal - nextData; }; + Packet &operator << (unsigned int data); + Packet &operator << (unsigned short data); + Packet &operator << (unsigned char data); + Packet &operator << (char *data); + Packet &operator << (Packet *packet); + Packet &operator >> (unsigned int &in); + Packet &operator >> (unsigned short &in); + Packet &operator >> (unsigned char &in); + Packet &operator >> (char *&in); + char *print(); +protected: + char *buff; + char *nextData; + unsigned int maxSize; + unsigned int sizeVal; + + friend class UDPSocket; + friend class TCPSocket; +}; + +/////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/protocols/ICQCorp/src/protocol.cpp b/protocols/ICQCorp/src/protocol.cpp new file mode 100644 index 0000000000..25967327d5 --- /dev/null +++ b/protocols/ICQCorp/src/protocol.cpp @@ -0,0 +1,2339 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +ICQ icq; + +/////////////////////////////////////////////////////////////////////////////// + +unsigned short toIcqStatus(unsigned short status) +{ +/* + unsigned short icqStatus[] = { ICQ_STATUS_OFFLINE, ICQ_STATUS_ONLINE, ICQ_STATUS_AWAY, ICQ_STATUS_DND, + ICQ_STATUS_NA, ICQ_STATUS_OCCUPIED, ICQ_STATUS_FREEFORCHAT, ICQ_STATUS_PRIVATE }; + + return icqStatus[status - ID_STATUS_OFFLINE]; +*/ + switch (status) + { + case ID_STATUS_OFFLINE: return ICQ_STATUS_OFFLINE; + case ID_STATUS_ONLINE: return ICQ_STATUS_ONLINE; + case ID_STATUS_AWAY: return ICQ_STATUS_AWAY; + case ID_STATUS_DND: return ICQ_STATUS_DND; + case ID_STATUS_NA: return ICQ_STATUS_NA; + case ID_STATUS_OCCUPIED: return ICQ_STATUS_OCCUPIED; + case ID_STATUS_FREECHAT: return ICQ_STATUS_FREECHAT; + case ID_STATUS_INVISIBLE: return ICQ_STATUS_PRIVATE; + } + return ICQ_STATUS_ONLINE; +} + +/////////////////////////////////////////////////////////////////////////////// + +unsigned short toIdStatus(unsigned short status) +{ + switch (status) + { + case ICQ_STATUS_OFFLINE: return ID_STATUS_OFFLINE; + case ICQ_STATUS_ONLINE: return ID_STATUS_ONLINE; + case ICQ_STATUS_AWAY: return ID_STATUS_AWAY; + case ICQ_STATUS_DND: return ID_STATUS_DND; + case ICQ_STATUS_NA: return ID_STATUS_NA; + case ICQ_STATUS_OCCUPIED: return ID_STATUS_OCCUPIED; + case ICQ_STATUS_FREECHAT: return ID_STATUS_FREECHAT; + case ICQ_STATUS_PRIVATE: return ID_STATUS_INVISIBLE; + } + return ID_STATUS_ONLINE; +} + +/////////////////////////////////////////////////////////////////////////////// + +LRESULT WINAPI messageWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + SOCKET hSocket = (SOCKET)wParam; + unsigned short netEvents = LOWORD(lParam); + unsigned long result; + + switch (msg) + { + case WM_NETEVENT_SERVER: + if (hSocket == icq.udpSocket.handleVal) + { + if (netEvents & FD_READ) icq.recvUDP(0); + break; + } + break; + + case WM_NETEVENT_CONNECTION: + if (hSocket == icq.tcpSocket.handleVal) + { + if (netEvents & FD_ACCEPT) icq.recvNewTCP(0); + break; + } + break; + + case WM_NETEVENT_USER: + if (netEvents & FD_READ) + { + ioctlsocket(hSocket, FIONREAD, &result); + if (result > 0) icq.recvTCP(hSocket); + } + if (netEvents & FD_CLOSE) + { + unsigned int i; + for (i=0; isocket.handleVal) + { + T("[tcp] user %d is aborted connection\n", icqUsers[i]->uin); + icqUsers[i]->socket.closeConnection(); + break; + } + } + } + break; + + case WM_NETEVENT_TRANSFER: + if (netEvents & FD_READ) + { + ioctlsocket(hSocket, FIONREAD, &result); + if (result > 0) icq.recvTransferTCP(hSocket); + } + if (netEvents & FD_CLOSE) + { + unsigned int i; + for (i=0; isocket.handleVal) + { + T("[tcp] user %d is aborted file connection\n", icqTransfers[i]->uin); + ProtoBroadcastAck(protoName, icqTransfers[i]->hContact, ACKTYPE_FILE, ACKRESULT_FAILED, icqTransfers[i], 0); + delete icqTransfers[i]; + icqTransfers[i] = icqTransfers[icqTransfers.size() - 1]; + icqTransfers.pop_back(); + break; + } + } + } + break; + + default: + return DefWindowProc(hWnd, msg, wParam, lParam); + } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +void WINAPI pingTimerProc(HWND hWnd, UINT Msg, UINT_PTR hTimer, DWORD Time) +{ + icq.ping(); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// ICQ +// +/////////////////////////////////////////////////////////////////////////////// + +ICQ::ICQ() : + tcpSocket(WM_NETEVENT_CONNECTION), + udpSocket(WM_NETEVENT_SERVER) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQ::load() +{ + WSADATA data; + + if (WSAStartup(MAKEWORD(2,2), &data)) + { + MessageBox(NULL, Translate("ICQ Corporate plugin used only WinSock v2.2 or later."), protoName, MB_ICONWARNING|MB_OK); + return false; + } + + statusVal = ID_STATUS_OFFLINE; + searchSequenceVal = 0; + tcpSequenceVal = 0xFFFFFFFE; + + awayMessage = new char[1]; + awayMessage[0] = 0; + + WNDCLASS wc = { 0, messageWndProc, 0, 0, hInstance, NULL, NULL, NULL, NULL, protoName }; + if (!RegisterClass(&wc)) return false; + + hWnd = CreateWindowEx(0, protoName, NULL, 0, 0, 0, 0, 0, (unsigned short)GetVersion() >= 5 ? HWND_MESSAGE : 0, NULL, hInstance, NULL); + if (hWnd == NULL) return false; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::unload() +{ + if (statusVal != ID_STATUS_OFFLINE) logoff(false); + + KillTimer(NULL, pingTimer); + pingTimer = NULL; + + delete [] awayMessage; + + WSACleanup(); + + DestroyWindow(hWnd); + UnregisterClass(protoName, hInstance); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQ::logon(unsigned short logonStatus) +{ + DBVARIANT dbv; + char str[128]; + + if(!db_get(NULL, protoName, "Server", &dbv)) + { + lstrcpy(str, dbv.pszVal); + db_free(&dbv); + } + else + { + MessageBox(NULL, Translate("You need specify ICQ Corporate login server."), protoName, MB_ICONWARNING|MB_OK); + return false; + } + + if (!tcpSocket.connected() && !tcpSocket.startServer()) return false; + if (!udpSocket.connected()) + { + if (!udpSocket.setDestination(str, db_get_w(NULL, protoName, "Port", 4000))) return false; + udpSocket.openConnection(); + } + + if (pingTimer == NULL) pingTimer = SetTimer(NULL, 0, PING_FREQUENCY, (TIMERPROC)pingTimerProc); + + updateContactList(); + + uin = db_get_dw(NULL, protoName, "UIN", 0); + if (!db_get(NULL, protoName, "Password", &dbv)) + { + lstrcpy(str, dbv.pszVal); + db_free(&dbv); + } + + + timeStampLastMessage = 0; + sequenceVal = 1; + + Packet loginPacket; + loginPacket << ICQ_VERSION + << ICQ_CMDxSND_LOGON + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << tcpSocket.localPortVal + << str + << (unsigned short)0x7A + << (unsigned short)0x02 +// << LOCALHOST + << udpSocket.localIPVal + << (unsigned char)0x04 + << (unsigned int)toIcqStatus(logonStatus) + << (unsigned int)0x02 + << (unsigned int)0x00 + << (unsigned short)0x13 + << (unsigned short)0x7A; + + T("[udp] requesting logon (%d)...\n", sequenceVal); + sendICQ(udpSocket, loginPacket, ICQ_CMDxSND_LOGON, sequenceVal); + + desiredStatus = logonStatus; + statusVal = ID_STATUS_CONNECTING; + ProtoBroadcastAck(protoName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)ID_STATUS_OFFLINE, statusVal); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::logoff(bool reconnect) +{ + unsigned int i; + + // if not connected then don't both logging off + if (udpSocket.connected()) + { + Packet logoffPacket; + logoffPacket << ICQ_VERSION + << ICQ_CMDxSND_LOGOFF + << (unsigned int)0x00 + << uin + << (unsigned int)0x00 + << "B_USER_DISCONNECTED" + << (unsigned short)0x0005; + + T("[udp] logging off.\n"); + udpSocket.sendPacket(logoffPacket); +// udpSocket.closeConnection(); + + // close all open events + for (i=0; i ID_STATUS_OFFLINE) + { + Packet pingPacket; + pingPacket << ICQ_VERSION + << ICQ_CMDxSND_PING + << sequenceVal + << (unsigned short)0x00 + << uin + << (unsigned int)0x00; + + T("[udp] keep alive (%d)\n", sequenceVal); + sendICQ(udpSocket, pingPacket, ICQ_CMDxSND_PING, sequenceVal); + } + + if (statusVal == ID_STATUS_OFFLINE && desiredStatus != ID_STATUS_OFFLINE) logoff(true); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *ICQ::sendICQ(Socket &socket, Packet &packet, unsigned short cmd, unsigned long sequence, + unsigned long uin, unsigned short subCmd, int reply) +{ + ICQEvent *result; + + if (!socket.connected()) return NULL; + + if (cmd != ICQ_CMDxTCP_START) sequenceVal++; + + icqEvents.push_back(result = new ICQEvent(cmd, subCmd, sequence, uin, &socket, &packet, reply)); + if (!result->start()) + { + cancelEvent(result); + return NULL; + } + return result; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::doneEvent(bool gotAck, int hSocket, int sequence) +{ + unsigned int i; + ICQEvent *e; + + for (i=0; iisEvent(hSocket, sequence)) break; + } + if (i == icqEvents.size()) return; + + e->stop(); + if (!gotAck || e->reply == 0) + { + icqEvents[i] = icqEvents[icqEvents.size() - 1]; + icqEvents.pop_back(); + } + + if (!gotAck) T("[ ] sending failed (%d)\n", sequence); + + switch (e->cmd) + { + case ICQ_CMDxTCP_START: + doneUserFcn(gotAck, e); + break; + case ICQ_CMDxSND_THRUxSERVER: + doneUserFcn(gotAck, e); + break; + case ICQ_CMDxSND_USERxGETxINFO: + //emit doneUserInfo(true, e->uin); + break; + case ICQ_CMDxSND_SETxSTATUS: + if (gotAck) + { + int oldStatus = statusVal; + statusVal = desiredStatus; + ProtoBroadcastAck(protoName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, statusVal); + } + break; + case ICQ_CMDxSND_PING: + //if (!gotAck) emit doneOwnerFcn(false, cmd); + break; + case ICQ_CMDxSND_USERxADD: + //if (!gotAck) emit doneOwnerFcn(false, cmd); + break; + case ICQ_CMDxSND_AUTHORIZE: + //emit doneOwnerFcn(gotAck, cmd); + break; + case ICQ_CMDxSND_LOGON: + if (!gotAck) + { + logoff(false); + //emit doneOwnerFcn(false, cmd); + } + break; + case ICQ_CMDxSND_USERxLIST: + //if (!gotAck) emit doneOwnerFcn(false, cmd); + break; + case ICQ_CMDxSND_VISxLIST: + //if (!gotAck) emit doneOwnerFcn(false, cmd); + break; + case ICQ_CMDxSND_SYSxMSGxREQ: + //if (!gotAck) emit doneOwnerFcn(false, cmd); + break; + case ICQ_CMDxSND_SYSxMSGxDONExACK: + //if (!gotAck) emit doneOwnerFcn(false, cmd); + break; + } + + if (!gotAck && e->cmd != ICQ_CMDxTCP_START && e->cmd != ICQ_CMDxSND_LOGON) logoff(true); + + + if (!gotAck || e->reply == 0) delete e; + + else e->reply--; + +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::cancelEvent(ICQEvent *&e) +{ + unsigned int i; + + for (i=0; istop(); + + icqEvents[i] = icqEvents[icqEvents.size() - 1]; + icqEvents.pop_back(); + + delete e; + e = NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +unsigned short ICQ::processUdpPacket(Packet &packet) +{ + unsigned short version, command, newCommand, theSequence, theSequence1, searchSequence, junkShort; + unsigned int checkUin, userIP, realIP, junkl, newStatus, userPort, timedataStamp; + unsigned char junkChar; + char *message = NULL; + ICQUser *u; + ICQEvent *e; + + // read in the standard UDP header info + packet >> version + >> command + >> theSequence + >> theSequence1 + >> checkUin + >> junkl; + + if (version != ICQ_VERSION) + { + T("[udp] bad version number %d\n", version); + return 0xFFFF; + } +/* on offline multi packet field checkUin not equal uin :( + + if (checkUin != uin) + { + T("[udp] bad uin number %d\n", checkUin); + return 0xFFFF; + } +*/ + switch (command) + { + case ICQ_CMDxRCV_LOGIN_ERR: + T("[udp] error loging to server.\n"); + ackUDP(theSequence); + + packet >> message; + + T("%s\n", message); + MessageBox(NULL, message, protoName, MB_ICONERROR|MB_OK); + delete [] message; + break; + + case ICQ_CMDxRCV_USERxONLINE: // initial user status packet + packet >> checkUin; + + T("[udp] user %d is online\n", checkUin); + ackUDP(theSequence); + + if ((u = getUserByUIN(checkUin, false)) == NULL) break; + + packet >> userIP + >> userPort + >> realIP + >> junkChar + >> newStatus; + + u->socket.closeConnection(); + u->socket.setDestination(userIP, userPort); + u->setStatus(toIdStatus(newStatus)); + u->setInfo("IP", (unsigned int)ntohl(userIP)); + u->setInfo("Port", (unsigned short)userPort); + u->setInfo("RealIP", (unsigned int)ntohl(realIP)); + break; + + case ICQ_CMDxRCV_USERxOFFLINE: // user just went offline packet + packet >> checkUin; + + T("[udp] user %d is offline\n", checkUin); + ackUDP(theSequence); + + if ((u = getUserByUIN(checkUin, false)) == NULL) break; + + u->setStatus(ID_STATUS_OFFLINE); + u->socket.closeConnection(); + break; + + case ICQ_CMDxRCV_USERxBASICxINFO: + case ICQ_CMDxRCV_USERxINFO: + case ICQ_CMDxRCV_USERxWORKxINFO: + case ICQ_CMDxRCV_USERxWORKxPAGE: + case ICQ_CMDxRCV_USERxHOMExINFO: + case ICQ_CMDxRCV_USERxHOMExPAGE: + T("[udp] user information packet (%d)\n", theSequence); + ackUDP(theSequence); + + if ((e = getEvent(udpSocket.handleVal, theSequence1)) == NULL) break; + checkUin = e->uin; + if ((u = getUserByUIN(checkUin, false)) == NULL) break; + + char *buffer; + buffer = new char[1024]; + + switch (command) + { + case ICQ_CMDxRCV_USERxBASICxINFO: + case ICQ_CMDxRCV_USERxINFO: + packet >> buffer; + u->setInfo("Nick", buffer); + packet >> buffer; + u->setInfo("FirstName", buffer); + packet >> buffer; + u->setInfo("LastName", buffer); + packet >> buffer; + u->setInfo("e-mail", buffer); + break; + + case ICQ_CMDxRCV_USERxWORKxINFO: + packet >> buffer; + u->setInfo("CompanyStreet", buffer); + packet >> buffer; + u->setInfo("CompanyCity", buffer); + packet >> buffer; + u->setInfo("CompanyState", buffer); + packet >> junkShort; + u->setInfo("CompanyCountry", junkShort); + packet >> buffer; + u->setInfo("Company", buffer); + packet >> buffer; + u->setInfo("CompanyPosition", buffer); + packet >> junkl; + packet >> buffer; + u->setInfo("CompanyPhone", buffer); + packet >> buffer; + u->setInfo("CompanyFax", buffer); + packet >> buffer; + packet >> junkl; + if (junkl && junkl != 0xFFFFFFFF) _itoa(junkl, buffer, 10); + else buffer[0] = 0; + u->setInfo("CompanyZIP", buffer); + break; + + case ICQ_CMDxRCV_USERxWORKxPAGE: + packet >> buffer; + u->setInfo("CompanyHomepage", buffer); + break; + + case ICQ_CMDxRCV_USERxHOMExINFO: + packet >> buffer; + u->setInfo("Street", buffer); + packet >> buffer; + u->setInfo("City", buffer); + packet >> buffer; + u->setInfo("State", buffer); + packet >> junkShort; + u->setInfo("Country", junkShort); + packet >> buffer; + u->setInfo("Phone", buffer); + packet >> buffer; + u->setInfo("Fax", buffer); + packet >> buffer; + u->setInfo("Cellular", buffer); + packet >> junkl; + if (junkl && junkl != 0xFFFFFFFF) _itoa(junkl, buffer, 10); + else buffer[0] = 0; + u->setInfo("ZIP", buffer); + packet >> junkChar; + if (junkChar == 1) junkChar = 'F'; + if (junkChar == 2) junkChar = 'M'; + u->setInfo("Gender", junkChar); + packet >> junkShort; + u->setInfo("Age", (unsigned char)junkShort); + packet >> junkChar; + u->setInfo("BirthDay", junkChar); + packet >> junkChar; + u->setInfo("BirthMonth", junkChar); + packet >> junkShort; + u->setInfo("BirthYear", junkShort); + break; + + case ICQ_CMDxRCV_USERxHOMExPAGE: + packet >> buffer; + u->setInfo("Homepage", buffer); + break; + } + + if (e->reply == 0) ProtoBroadcastAck(protoName, u->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, 0, 0); + doneEvent(true, udpSocket.handleVal, theSequence1); + delete [] buffer; + break; + + case ICQ_CMDxRCV_USERxINVALIDxUIN: // not a good uin + T("[udp] invalid uin\n"); + ackUDP(theSequence); + + if ((e = getEvent(udpSocket.handleVal, theSequence1)) == NULL) break; + + checkUin = e->uin; + T("invalid uin: %d\n", checkUin); +/* + delete icqEvents[i2]; + icqEvents[i2] = icqEvents[icqEvents.size() - 1]; + icqEvents.pop_back(); +*/ + break; + + case ICQ_CMDxRCV_USERxSTATUS: // user changed status packet + packet >> checkUin; + + T("[udp] user %d changed status\n", checkUin); + ackUDP(theSequence); + + packet >> newStatus; + + if ((u = getUserByUIN(checkUin, false)) == NULL) break; + u->setStatus(toIdStatus(newStatus)); + break; + + case ICQ_CMDxRCV_USERxLISTxDONE: // end of user list + T("[udp] end of user list.\n"); + ackUDP(theSequence); + break; + + case ICQ_CMDxRCV_SEARCHxFOUND: // user found in search + T("[udp] search found user\n"); + ackUDP(theSequence); + + char *alias, *firstName, *lastName, *email; + unsigned char auth; + + alias = NULL; + firstName = NULL; + lastName = NULL; + email = NULL; + + packet >> checkUin + >> alias + >> firstName + >> lastName + >> email + >> auth; + + ICQSEARCHRESULT isr; + + isr.hdr.cbSize = sizeof(isr); + isr.hdr.nick = alias; + isr.hdr.firstName = firstName; + isr.hdr.lastName = lastName; + isr.hdr.email = email; + isr.uin = checkUin; + isr.auth = auth; + ProtoBroadcastAck(protoName, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)1, (LPARAM)&isr); + + delete [] alias; + delete [] firstName; + delete [] lastName; + delete [] email; + break; + + case ICQ_CMDxRCV_SEARCHxDONE: + T("[udp] search finished.\n"); + ackUDP(theSequence); + + packet >> searchSequence; + searchSequence = theSequence1; + + ProtoBroadcastAck(protoName, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)1, 0); + break; + + case ICQ_CMDxRCV_SYSxMSGxOFFLINE: // offline system message, now have to check the sub-command + T("[udp] offline system message\n"); + ackUDP(theSequence); + + packet >> checkUin + >> timedataStamp + >> newCommand; + + timeStampLastMessage = timedataStamp; + timedataStamp = CallService(MS_DB_TIME_TIMESTAMPTOLOCAL, timedataStamp, 0); + + processSystemMessage(packet, checkUin, newCommand, timedataStamp); + break; + + case ICQ_CMDxRCV_SYSxMSGxONLINE: // online system message, now have to check the sub-command + T("[udp] online system message\n"); + ackUDP(theSequence); + + packet >> checkUin + >> newCommand; + + processSystemMessage(packet, checkUin, newCommand, time(NULL)); + break; + + case ICQ_CMDxRCV_SYSxMSGxDONE: // end of system messages + T("[udp] end of system messages.\n"); + ackUDP(theSequence); + + if (timeStampLastMessage) + { + ackSYS(timeStampLastMessage); + timeStampLastMessage = 0; + } + break; + + case ICQ_CMDxRCV_BROADCASTxMULTI: + T("[udp] broadcast multi-packet (%d)\n", theSequence); + ackUDP(theSequence); + + unsigned int i; + unsigned char j, frameNo, frameSize; + bool found; + + packet >> frameNo + >> frameSize; + + icqEvents.push_back(new ICQEvent(ICQ_CMDxRCV_BROADCASTxMULTI, (unsigned short)frameNo, theSequence1, 0, &udpSocket, &packet, 0)); + + { + Packet multiPacket; + + for (j=0; jcmd == ICQ_CMDxRCV_BROADCASTxMULTI && e->subCmd == j && e->isEvent(udpSocket.handleVal, theSequence1)) + { + multiPacket << e->packet; + found = true; + break; + } + } + if (!found) break; + } + + if (j == frameSize) + { + for (i=0; icmd == ICQ_CMDxRCV_BROADCASTxMULTI && e->isEvent(udpSocket.handleVal, theSequence1)) + { + icqEvents[i] = icqEvents[icqEvents.size() - 1]; + icqEvents.pop_back(); + + delete e; + } + } + + multiPacket.reset(); + processUdpPacket(multiPacket); + } + } + break; + + case ICQ_CMDxRCV_BROADCASTxOFFLINE: + T("[udp] offline broadcast message (%d)\n", theSequence); + ackUDP(theSequence); + + packet >> checkUin + >> timedataStamp + >> newCommand; + + db_set_dw(NULL, protoName, "LastBroadcastTime", timedataStamp); + timedataStamp = CallService(MS_DB_TIME_TIMESTAMPTOLOCAL, timedataStamp, 0); + + processSystemMessage(packet, checkUin, newCommand, timedataStamp); + break; + + case ICQ_CMDxRCV_BROADCASTxONLINE: + T("[udp] online broadcast message (%d)\n", theSequence); + ackUDP(theSequence); + + packet >> checkUin + >> newCommand; + + processSystemMessage(packet, checkUin, newCommand, time(NULL)); + break; + + case ICQ_CMDxRCV_BROADCASTxDONE: + T("[udp] end of broadcast messages.\n"); + ackUDP(theSequence); + break; + + case ICQ_CMDxRCV_SETxOFFLINE: // we got put offline by mirabilis for some reason + T("[udp] kicked offline.\n"); + logoff(true); + break; + + case ICQ_CMDxRCV_ACK: // icq acknowledgement + T("[udp] received ack (%d)\n", theSequence); + doneEvent(true, udpSocket.handleVal, theSequence); + break; + + case ICQ_CMDxRCV_ERROR: // icq says go away + T("[udp] server says bugger off.\n"); + logoff(true); + break; + + case ICQ_CMDxRCV_HELLO: // hello packet from mirabilis received on logon + T("[udp] received hello.\n"); + ackUDP(theSequence); + + int oldStatus; + + requestSystemMsg(); + requestBroadcastMsg(); + +// pingTimer.start(PING_FREQUENCY * 1000); + oldStatus = statusVal; + statusVal = desiredStatus; + ProtoBroadcastAck(protoName, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)oldStatus, statusVal); + + updateContactList(); +// sendVisibleList(); +// sendInvisibleList(); + break; + + case ICQ_CMDxRCV_WRONGxPASSWD: // incorrect password sent in logon + T("[udp] incorrect password.\n"); + ProtoBroadcastAck(protoName, NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD); + MessageBox(NULL, Translate("Your ICQ Corp number and password combination was rejected by the ICQ Corporate server. Please go to M->Options->ICQCorp and try again."), protoName, MB_ICONERROR|MB_OK); + break; + + case ICQ_CMDxRCV_BUSY: // server too busy to respond + T("[udp] server busy, try again in a few minutes.\n"); + break; + + default: // what the heck is this packet? + T("[udp] unknown packet:\n%s", packet.print()); + ackUDP(theSequence); + break; + } + + return command; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::processSystemMessage(Packet &packet, unsigned long checkUin, unsigned short newCommand, time_t timeSent) +{ + char *message/*, *sysMsg*/; + ICQUser *u; + unsigned int i, /*j,*/ messageLen; + + u = getUserByUIN(checkUin); + + message = NULL; + packet >> message; + + switch (newCommand) + { + case ICQ_CMDxRCV_SYSxMSG: + T("message through server from %d\n", checkUin); + addMessage(u, message, ICQ_CMDxRCV_SYSxMSGxONLINE, ICQ_CMDxTCP_MSG, 0, timeSent); + break; + + case ICQ_CMDxRCV_SYSxURL: + T("url through server from %d\n", checkUin); + addUrl(u, message, ICQ_CMDxRCV_SYSxMSGxONLINE, ICQ_CMDxTCP_URL, 0, timeSent); + break; + + case ICQ_CMDxRCV_SYSxBROADCAST: + T("broadcast message from %d\n", checkUin); + + messageLen = (unsigned int)strlen(message); + for (i=0; i> messageLen; + message = new char[messageLen + 1]; + for (i=0; i<=messageLen; i++) + { + packet >> message[i]; + if (message[i] == (char)0xFE) message[i] = '\n'; + } + + sysMsg = new char[messageLen + 128]; + sprintf(sysMsg, "(%s) Authorization request from %ld:\n%s", sm.timeRec(), checkUin, message); + icqOwner.addMessage(sysMsg, ICQ_CMDxRCV_SYSxMSGxONLINE, ICQ_CMDxRCV_SMxREQxAUTH, 0, timeSent); + sprintf(sysMsg, "Authorization request from %ld:\n%s", checkUin, message); + addToSystemMessageHistory(sysMsg); + playSound(soundSysMsg); + delete sysMsg; + delete message; + break; + + case ICQ_CMDxRCV_SYSxAUTHxGRANTED: // system message: authorization granted + + outputWindow->wprintf(" (%s) Authorization granted from %ld.", sm.timeRec(), checkUin); + packet >> messageLen; + message = new char[messageLen + 1]; + for (i = 0; i <= messageLen; i++) + { + packet >> message[i]; + if (message[i] == (char)0xFE) message[i] = '\n'; + } + + sysMsg = new char[messageLen + 128]; + sprintf(sysMsg, "(%s) Authorization granted from %ld:\n%s", sm.timeRec(), checkUin, message); + icqOwner.addMessage(sysMsg, ICQ_CMDxRCV_SYSxMSGxONLINE, ICQ_CMDxRCV_SMxREQxAUTH, 0, timeSent); + sprintf(sysMsg, "Authorization granted from %ld:\n%s", checkUin, message); + addToSystemMessageHistory(sysMsg); + playSound(soundSysMsg); + + delete sysMsg; + delete message; + break; +*/ +/* + case ICQ_CMDxRCV_SYSxADDED: // system message: added to a contact list + outputWindow->wprintf(" %C(%s) user %C%ld%C added you to their contact list.", COLOR_RECEIVE, sm.timeRec(), COLOR_DATA, checkUin, COLOR_RECEIVE); + sysMsg = new char[128]; + sprintf(sysMsg, "(%s) User %ld added you to their contact list.", sm.timeRec(), checkUin); + icqOwner.addMessage(sysMsg, ICQ_CMDxRCV_SYSxMSGxONLINE, ICQ_CMDxRCV_SMxADDED, 0, timeSent); + sprintf(sysMsg, "User %ld added you to their contact list.", checkUin); + addToSystemMessageHistory(sysMsg); + delete sysMsg; + playSound(soundSysMsg); +*/ + /* there is a bunch of info about the given user in the packet but the read routine to get + at it is totally broken right now + int infoLen, j; + packet >> infoLen; + + // declare all the strings we will need for reading in the user data + char *userInfo, *aliasField, *firstNameField, *lastNameField, *emailField; + userInfo = new char[infoLen]; + aliasField = new char[infoLen]; + firstNameField = new char[infoLen]; + lastNameField = new char[infoLen]; + emailField = new char[infoLen]; + + // read in the user data from the packet + for (i = 0; i < infoLen; i++) packet >> userInfo[i]; + + // parse the user info string for the four fields + i = j = 0; + do { aliasField[j] = userInfo[i]; i++; j++;} while (userInfo[i] != (char)0xFE); + aliasField[j] = '\0'; j = 0; + do { firstNameField[j] = userInfo[i]; i++; j++;} while (userInfo[i] != (char)0xFE); + firstNameField[j] = '\0'; j = 0; + do { lastNameField[j] = userInfo[i]; i++; j++;} while (userInfo[i] != (char)0xFE); + lastNameField[j] = '\0'; j = 0; + do { emailField[j] = userInfo[i]; i++; j++;} while (i < infoLen); + emailField[j] = '\0'; + + *outputWindow << " " << aliasField << " (" << firstNameField << " " << lastNameField << "), " << emailField << "."; + + delete userInfo; delete aliasField; delete firstNameField; delete lastNameField; delete emailField; + break; + */ + + default: + T("[udp] unknown system packet:\n%s", packet.print()); + break; + } + + delete [] message; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::ackUDP(unsigned short theSequence) +{ + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_ACK + << theSequence + << (unsigned short)0x00 + << uin + << (unsigned int)0x00; + + T("[udp] sending ack (%d)\n", theSequence); + udpSocket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::ackSYS(unsigned int timeStamp) +{ + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_SYSxMSGxDONExACK + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << timeStamp; + + T("[udp] sending system message ack (%d)\n", sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_SYSxMSGxDONExACK, sequenceVal); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQUser *ICQ::getUserByUIN(unsigned long uin, bool allowAdd) +{ + unsigned long i; + ICQUser *u; + + for (i=0; iuin == uin) return u; + } + + if (allowAdd) + { + T("unknown user %d, adding them to your list\n", uin); + return addUser(uin, false); + } + + T("ICQ sent unknown user %d\n", uin); + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQUser *ICQ::getUserByContact(MCONTACT hContact) +{ + unsigned long i; + ICQUser *u; + +// uin = db_get_dw(ccs->hContact, protoName, "UIN", 0); + + for (i=0; ihContact == hContact) return u; + } + return NULL; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::requestSystemMsg() +{ + // request offline system messages + // 02 00 4C 04 02 00 50 A5 82 00 + + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_SYSxMSGxREQ + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00; + + T("[udp] sending offline system messages request (%d)...\n", sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_SYSxMSGxREQ, sequenceVal); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::requestBroadcastMsg() +{ + unsigned int timeStamp = db_get_dw(NULL, protoName, "LastBroadcastTime", 0); + + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_BROADCASTxREQ + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << timeStamp + << (unsigned int)0x00; + + T("[udp] sending offline broadcast messages request (%d)...\n", sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_SYSxMSGxREQ, sequenceVal); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQ::setStatus(unsigned short newStatus) +{ + if (!udpSocket.connected()) return false; + + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_SETxSTATUS + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << toIcqStatus(newStatus); + + T("[udp] sending set status packet (%d)\n", sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_SETxSTATUS, sequenceVal); + + desiredStatus = newStatus; + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::updateContactList() +{ + char *proto; + unsigned int i; + int userCount; + //HANDLE hContact; + ICQUser *u; + + for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { + proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if (proto && !strcmp(proto, protoName)) + { + if ((u = getUserByContact(hContact)) == NULL) + { + u = new ICQUser(); + u->hContact = hContact; + u->uin = db_get_dw(hContact, protoName, "UIN", 0); + icqUsers.push_back(u); + } + if (statusVal <= ID_STATUS_OFFLINE) u->setStatus(ID_STATUS_OFFLINE); + else u->statusVal = db_get_w(hContact, protoName, "Status", ID_STATUS_OFFLINE); + } + } + + if (statusVal <= ID_STATUS_OFFLINE) return; + + + // create user info packet + Packet userPacket; + for (i=0; i 100) userCount = 100; + + userPacket.clearPacket(); + userPacket << ICQ_VERSION + << ICQ_CMDxSND_USERxLIST + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << (unsigned char)userCount; + + for (; userCount>0; userCount--) userPacket << icqUsers[i++]->uin; + + // send user info packet + T("[udp] sending contact list (%d)...\n", sequenceVal); + sendICQ(udpSocket, userPacket, ICQ_CMDxSND_USERxLIST, sequenceVal); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::sendVisibleList() +{ +/* + unsigned int i, numUsers = 0; + ICQUser *u; + + if (statusVal != ID_STATUS_INVISIBLE) return; + + Packet userPacket; + userPacket << ICQ_VERSION + << ICQ_CMDxSND_VISxLIST + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00; + + for (i=0; istatusVal != ID_STATUS_OFFLINE && db_get_w(u->hContact, protoName, "ApparentMode", 0) == ID_STATUS_ONLINE) + numUsers++; + } + + if (numUsers == 0) return; + userPacket << (char)numUsers; + + for (i=0; istatusVal != ID_STATUS_OFFLINE && db_get_w(u->hContact, protoName, "ApparentMode", 0) == ID_STATUS_ONLINE) + userPacket << icqUsers[i]->uin; + } + + T("[udp] sending visible list (%d)\n", sequenceVal); + sendICQ(udpSocket, userPacket, ICQ_CMDxSND_VISxLIST, sequenceVal); +*/ +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::sendInvisibleList() +{ +/* + unsigned int i, numUsers = 0; + + Packet userPacket; + userPacket << ICQ_VERSION + << ICQ_CMDxSND_INVISxLIST + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00; + + for (i=0; ihContact, protoName, "ApparentMode", 0) == ID_STATUS_OFFLINE) + numUsers++; + } + + if (numUsers == 0) return; + userPacket << (char)numUsers; + + for (i=0; ihContact, protoName, "ApparentMode", 0) == ID_STATUS_OFFLINE) + userPacket << icqUsers[i]->uin; + } + + T("[udp] sending invisible list (%d)\n", sequenceVal); + sendICQ(udpSocket, userPacket, ICQ_CMDxSND_INVISxLIST, sequenceVal); +*/ +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::updateUserList(ICQUser *u, char list, char add) +{ +/* + Packet userPacket; + userPacket << ICQ_VERSION + << ICQ_CMDxSND_UPDATExLIST + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << u->uin + << list + << add; + + T("[udp] update user list (%d)\n", sequenceVal); + sendICQ(udpSocket, userPacket, ICQ_CMDxSND_UPDATExLIST, sequenceVal); +*/ +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQUser *ICQ::addUser(unsigned int uin, bool persistent) +{ + unsigned int i; + ICQUser *u; + + for (i=0; iuin == uin) + { + if (persistent) + { + db_unset(u->hContact, "CList", "NotOnList"); + db_unset(u->hContact, "CList", "Hidden"); + } + return u; + } + } + + u = new ICQUser(); + u->uin = uin; + u->hContact = (MCONTACT)CallService(MS_DB_CONTACT_ADD, 0, 0); + icqUsers.push_back(u); + + CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)u->hContact, (LPARAM)protoName); + u->setInfo("UIN", uin); + + if (persistent) getUserInfo(u, true); + else + { + db_set_b(u->hContact, "CList", "NotOnList", 1); + db_set_b(u->hContact, "CList", "Hidden", 1); + } + + updateContactList(); + return u; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::addNewUser(ICQUser *u) +{ +/* + // update the users info from the server + if (statusVal != ICQ_STATUS_OFFLINE) + { + Packet packet; // alert server to new user + + packet << ICQ_VERSION + << ICQ_CMDxSND_USERxADD + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << u->uin; + + T("[udp] alerting server to new user (%d)...\n", sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_USERxADD, sequenceVal); + +// getUserInfo(u); + } +*/ + updateContactList(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::removeUser(ICQUser *u) +{ + unsigned int i; + + for (i=0; istatusVal > ID_STATUS_OFFLINE && (result = sendTCP(u, cmd, cmdStr, m)) != NULL) return result; + else return sendUDP(u, cmd, cmdStr, m); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQ::openConnection(TCPSocket &socket) +{ + T("[tcp] connecting to %s on port %d...\n", inet_ntoa(*(in_addr*)&socket.remoteIPVal), socket.remotePortVal); + socket.openConnection(); + + if (!socket.connected()) + { + T("[tcp] connect failed\n"); + return false; + } + + T("[tcp] connection successful\n"); + + Packet packet; +// packet << ICQ_CMDxTCP_HANDSHAKE3 + packet << (unsigned char)0xFF + << (unsigned int)0x02 + << (unsigned int)0x00 +// << (unsigned long)tcpSocket.localPortVal + << uin + << socket.localIPVal + << socket.localIPVal + << (unsigned char)0x04 + << (unsigned int)0x00; +// << (unsigned long)tcpSocket.localPortVal; + + T("[tcp] sending handshake\n"); + if (!socket.sendPacket(packet)) + { + T("[tcp] send failed\n"); + return false; + } + + T("[tcp] setup completed\n"); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *ICQ::sendTCP(ICQUser *u, unsigned short cmd, char *cmdStr, char *m) +{ + if (!u->socket.connected() && !openConnection(u->socket)) return NULL; + + unsigned int status; + if (accept) + { + switch (statusVal) + { + case ID_STATUS_ONLINE: status = 0x00100000; break; + case ID_STATUS_FREECHAT: status = 0x00000000; break; // ?? + case ID_STATUS_AWAY: status = 0x01100000; break; + case ID_STATUS_NA: status = 0x00100000; break; + case ID_STATUS_DND: status = 0x00100000; break; + case ID_STATUS_OCCUPIED: status = 0x02100000; break; + case ID_STATUS_INVISIBLE: status = 0x00900000; break; // ?? + default: status = 0x00100000; break; + } + } + else status = 0x00000001; + + Packet packet; + packet << uin + << (unsigned short)0x02 // ICQ_VERSION + << ICQ_CMDxTCP_START // ICQ_CMDxTCP_ACK, ICQ_CMDxTCP_START, ICQ_CMDxTCP_CANCEL + << (unsigned short)0x00 + << uin + << cmd + << m + << udpSocket.localIPVal + << udpSocket.localIPVal + << tcpSocket.localPortVal + << (unsigned char)0x04 + << status + << tcpSequenceVal--; + + T("[tcp] sending %s (%d)\n", cmdStr, tcpSequenceVal + 1); + return sendICQ(u->socket, packet, ICQ_CMDxTCP_START, tcpSequenceVal + 1, u->uin, cmd); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *ICQ::sendUDP(ICQUser *u, unsigned short cmd, char *cmdStr, char *m) +{ + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_THRUxSERVER + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << u->uin + << cmd + << m; + +/* write for offline multi packet, but not work - little architecturial trouble: + one big packet must divided on several little packets and Miranda use returned ONE event for control process sending, + but not several events + + if (packet.size() > 450) + { + unsigned int i, j = 0; + unsigned char c, frameNo, frameSize; + + packet.reset(); + + frameSize = (packet.size()+449) / 450; + for (frameNo=0; frameNo> c; + frame << c; + } + + T("[udp] sending %s through server, part %d of %d (%d)\n", cmdStr, frameNo, frameSize, sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_THRUxSERVER, sequenceVal, u->uin, cmd); + } + } + else +*/ + { + T("[udp] sending %s through server (%d)\n", cmdStr, sequenceVal); + return sendICQ(udpSocket, packet, ICQ_CMDxSND_THRUxSERVER, sequenceVal, u->uin, cmd); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *ICQ::sendMessage(ICQUser *u, char *m) +{ + return send(u, ICQ_CMDxTCP_MSG, "message", m); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *ICQ::sendUrl(ICQUser *u, char *url) +{ + unsigned int nameLen, descriptionLen; + char *m, *description; + ICQEvent *result; + + nameLen = (unsigned int)strlen(url); + description = (char*)url + nameLen + 1; + descriptionLen = (unsigned int)strlen(description); + + m = new char[nameLen + descriptionLen + 2]; + strcpy(m, description); + strcpy(m + descriptionLen + 1, url); + m[descriptionLen] = (char)0xFE; + + result = send(u, ICQ_CMDxTCP_URL, "url", m); + delete [] m; + + return result; +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQEvent *ICQ::sendReadAwayMsg(ICQUser *u) +{ + unsigned short cmd; + + switch (u->statusVal) + { + case ID_STATUS_AWAY: cmd = ICQ_CMDxTCP_READxAWAYxMSG; break; + case ID_STATUS_DND: cmd = ICQ_CMDxTCP_READxDNDxMSG; break; + case ID_STATUS_NA: cmd = ICQ_CMDxTCP_READxNAxMSG; break; + case ID_STATUS_OCCUPIED: cmd = ICQ_CMDxTCP_READxOCCUPIEDxMSG; break; + case ID_STATUS_FREECHAT: cmd = ICQ_CMDxTCP_READxFREECHATxMSG; break; + default: return NULL; + } + + return sendTCP(u, cmd, "away message request", ""); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQTransfer *ICQ::sendFile(ICQUser *u, char *description, char *filename, unsigned int size, char **files) +{ + if (!u->socket.connected() && !openConnection(u->socket)) return NULL; + + unsigned int i; + + ICQTransfer *transfer = new ICQTransfer(u, tcpSequenceVal); + + for (i=0; files[i]; i++); + transfer->files = new char*[i + 1]; + for (i=0; files[i]; i++) transfer->files[i] = _strdup(files[i]); + transfer->files[i] = 0; + + transfer->description = _strdup(description); + transfer->count = i; + transfer->totalSize = size; + + transfer->path = _strdup(files[0]); + *strrchr(transfer->path, '\\') = 0; + + icqTransfers.push_back(transfer); + transfer->ack(ACKRESULT_SENTREQUEST); + + + unsigned short cmd = ICQ_CMDxTCP_FILE; + char *m = description; + + unsigned int status; + if (accept) + { + switch (statusVal) + { + case ID_STATUS_ONLINE: status = 0x00100000; break; + case ID_STATUS_FREECHAT: status = 0x00000000; break; // ?? + case ID_STATUS_AWAY: status = 0x01100000; break; + case ID_STATUS_NA: status = 0x00100000; break; + case ID_STATUS_DND: status = 0x00100000; break; + case ID_STATUS_OCCUPIED: status = 0x02100000; break; + case ID_STATUS_INVISIBLE: status = 0x00900000; break; // ?? + default: status = 0x00100000; break; + } + } + else status = 0x00000001; + + Packet packet; + packet << uin + << (unsigned short)0x02 // ICQ_VERSION + << ICQ_CMDxTCP_START // ICQ_CMDxTCP_ACK, ICQ_CMDxTCP_START, ICQ_CMDxTCP_CANCEL + << (unsigned short)0x00 + << uin + << cmd + << m + << udpSocket.localIPVal + << udpSocket.localIPVal + << tcpSocket.localPortVal + << (unsigned char)0x04 + << status; + + + packet << (unsigned int)0x00 + << filename + << size + << (unsigned int)0x00; + + packet << tcpSequenceVal--; + + T("[tcp] sending file request (%d)\n", tcpSequenceVal + 1); + sendICQ(u->socket, packet, ICQ_CMDxTCP_START, tcpSequenceVal + 1, u->uin, cmd); + return transfer; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::acceptFile(ICQUser *u, unsigned long hTransfer, char *path) +{ + unsigned int theSequence = hTransfer; + unsigned short cmd = ICQ_CMDxTCP_FILE; + char m[1] = { 0 }; + + unsigned long status; + if (accept) + { + switch (statusVal) + { + case ID_STATUS_ONLINE: status = 0x00100000; break; + case ID_STATUS_FREECHAT: status = 0x00000000; break; // ?? + case ID_STATUS_AWAY: status = 0x01100000; break; + case ID_STATUS_NA: status = 0x00100000; break; + case ID_STATUS_DND: status = 0x00100000; break; + case ID_STATUS_OCCUPIED: status = 0x02100000; break; + case ID_STATUS_INVISIBLE: status = 0x00900000; break; // ?? + default: status = 0x00100000; break; + } + } + else status = 0x00000001; + + Packet packet; + packet << uin + << (unsigned short)0x02 // ICQ_VERSION + << ICQ_CMDxTCP_ACK // ICQ_CMDxTCP_ACK, ICQ_CMDxTCP_START, ICQ_CMDxTCP_CANCEL + << (unsigned short)0x00 + << uin + << cmd + << m + << udpSocket.localIPVal + << udpSocket.localIPVal + << tcpSocket.localPortVal + << (unsigned char)0x04 +// << status; + << (unsigned int)0x00; + + packet << (unsigned int)htons(tcpSocket.localPortVal) + << m + << (unsigned int)0x00 + << tcpSocket.localPortVal; + + packet << theSequence; + + T("[tcp] sending accept file ack (%d)\n", theSequence); + u->socket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::refuseFile(ICQUser *u, unsigned long hTransfer, char *reason) +{ + unsigned int theSequence = hTransfer; + unsigned short cmd = ICQ_CMDxTCP_FILE; + char m[1] = { 0 }; + + unsigned int status; + if (accept) + { + switch (statusVal) + { + case ID_STATUS_ONLINE: status = 0x00100000; break; + case ID_STATUS_FREECHAT: status = 0x00000000; break; // ?? + case ID_STATUS_AWAY: status = 0x01100000; break; + case ID_STATUS_NA: status = 0x00100000; break; + case ID_STATUS_DND: status = 0x00100000; break; + case ID_STATUS_OCCUPIED: status = 0x02100000; break; + case ID_STATUS_INVISIBLE: status = 0x00900000; break; // ?? + default: status = 0x00100000; break; + } + } + else status = 0x00000001; + + Packet packet; + packet << uin + << (unsigned short)0x02 // ICQ_VERSION + << ICQ_CMDxTCP_ACK // ICQ_CMDxTCP_ACK, ICQ_CMDxTCP_START, ICQ_CMDxTCP_CANCEL + << (unsigned short)0x00 + << uin + << cmd + << reason + << udpSocket.localIPVal + << udpSocket.localIPVal + << tcpSocket.localPortVal + << (unsigned char)0x04 +// << status; + << (unsigned int)0x00000001; + + packet << (unsigned int)0x00 + << m + << (unsigned int)0x00 + << (unsigned int)0x00; + + packet << theSequence; + + T("[tcp] sending refuse file ack (%d)\n", theSequence); + u->socket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool ICQ::getUserInfo(ICQUser *u, bool basicInfo) +{ + unsigned short cmd = basicInfo ? ICQ_CMDxSND_USERxGETxBASICxINFO : ICQ_CMDxSND_USERxGETxINFO; + + Packet request; + request << ICQ_VERSION + << cmd + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << u->uin; + + T("[udp] sending user %s info request (%d)...\n", basicInfo ? "basic" : "details", sequenceVal); + sendICQ(udpSocket, request, cmd, sequenceVal, u->uin, 0, basicInfo ? 1 : 5); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::authorize(unsigned int uinToAuthorize) +{ + Packet packet; + packet << ICQ_VERSION + << ICQ_CMDxSND_AUTHORIZE + << sequenceVal + << sequenceVal + << uin + << (unsigned int)0x00 + << uinToAuthorize + << (unsigned int)0x00010008 // who knows, seems to be constant + << (unsigned char)0x00; + + T("[udp] sending authorization (%d)\n", sequenceVal); + sendICQ(udpSocket, packet, ICQ_CMDxSND_AUTHORIZE, sequenceVal); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::processTcpPacket(Packet &packet, unsigned int hSocket) +{ + unsigned int i, checkUin, senderIp, localIp, userStatus, senderPort, junkLong, thePort, theTCPSequence; + unsigned short version, command, junkShort, newCommand, /*messageLen,*/ cicqVersion; + unsigned char cicqChar, junkChar; + char *message = NULL; + ICQUser *u; + static unsigned int chatUin, chatSequence; + + packet >> checkUin + >> version + >> command // so far either message stuff or message ack + >> junkShort // 00 00 to fill in the MSB of the command long int which is read in as a short + >> checkUin + >> newCommand // if a message then what type, message/chat/read away message/... + >> message + >> senderIp + >> localIp + >> senderPort + >> junkChar + >> userStatus; + + u = getUserByUIN(checkUin); + switch(command) + { + case ICQ_CMDxTCP_START: // incoming tcp packet containing one of many possible things + switch(newCommand) // do a switch on what it could be + { + case ICQ_CMDxTCP_MSG: // straight message from a user + T("[tcp] message from %d.\n", checkUin); + + packet >> theTCPSequence; + + ackTCP(packet, u, newCommand, theTCPSequence); + addMessage(u, message, ICQ_CMDxTCP_START, ICQ_CMDxTCP_MSG, theTCPSequence, time(NULL)); + break; + + case ICQ_CMDxTCP_CHAT: + T("[tcp] chat request from %d.\n", checkUin); + + packet >> junkLong + >> junkLong + >> junkShort + >> junkChar + >> theTCPSequence + >> cicqChar + >> cicqVersion; +/* + char *chatReq; + chatReq = new char[messageLen + 32]; + sprintf(chatReq, "Chat request:\n %s", message); +// u->addMessage(chatReq, ICQ_CMDxTCP_START, ICQ_CMDxTCP_CHAT, theTCPSequence, 0, (cicqChar == 'C'), cicqVersion); + delete chatReq; +*/ + break; + + case ICQ_CMDxTCP_URL: // url sent + T("[tcp] url from %d.\n", checkUin); + + packet >> theTCPSequence; + + ackTCP(packet, u, newCommand, theTCPSequence); + addUrl(u, message, ICQ_CMDxTCP_START, ICQ_CMDxTCP_URL, theTCPSequence, time(NULL)); + break; + + case ICQ_CMDxTCP_FILE: + unsigned int size; + char *fileName; + + fileName = NULL; + packet >> junkLong + >> fileName + >> size + >> junkLong + >> theTCPSequence; + + T("[tcp] file transfer request from %d (%d)\n", checkUin, theTCPSequence); + + addFileReq(u, message, fileName, size, ICQ_CMDxTCP_START, ICQ_CMDxTCP_FILE, theTCPSequence, time(NULL)); + delete [] fileName; + break; + + case ICQ_CMDxTCP_READxAWAYxMSG: // read away message + case ICQ_CMDxTCP_READxOCCUPIEDxMSG: + case ICQ_CMDxTCP_READxNAxMSG: + case ICQ_CMDxTCP_READxDNDxMSG: + case ICQ_CMDxTCP_READxFREECHATxMSG: + T("[tcp] %d requested read of away message.\n", checkUin); + + packet >> theTCPSequence; + ackTCP(packet, u, newCommand, theTCPSequence); + break; + } + break; + + case ICQ_CMDxTCP_ACK: // message received packet + switch (newCommand) + { + case ICQ_CMDxTCP_MSG: + packet >> theTCPSequence; + break; + + case ICQ_CMDxTCP_CHAT: + packet >> junkShort + >> junkChar + >> junkLong // port backwards + >> thePort // port to connect to for chat + >> theTCPSequence; + + if (chatSequence != theTCPSequence || chatUin != checkUin) // only if this is the first chat ack packet + { // do we do anything + chatSequence = theTCPSequence; + chatUin = checkUin; +// emit eventResult(u, ICQ_CMDxTCP_CHAT, userStatus == 0x0000 ? true : false, thePort); + } + break; + + case ICQ_CMDxTCP_URL: + packet >> theTCPSequence; + break; + + case ICQ_CMDxTCP_FILE: + packet >> junkLong + >> junkShort + >> junkChar + >> junkLong + >> thePort + >> theTCPSequence; + + T("[tcp] file transfer ack from %d (%d)\n", u->uin, theTCPSequence); + + ICQTransfer *t; + for (i=0; iuin == checkUin && !t->socket.connected()) + { + if (userStatus != 0) + { + T("[tcp] file transfer denied by %d\n", checkUin); + ProtoBroadcastAck(protoName, t->hContact, ACKTYPE_FILE, ACKRESULT_DENIED, t, 0); + delete t; + icqTransfers[i] = icqTransfers[icqTransfers.size() - 1]; + icqTransfers.pop_back(); + break; + } + + if (!t->socket.setDestination(u->socket.remoteIPVal, thePort)) + { + T("[tcp] can't set destination\n"); + break; + } + t->ack(ACKRESULT_CONNECTING); + if (openConnection(t->socket)) + { + t->ack(ACKRESULT_CONNECTED); + t->sendPacket0x00(); + } + break; + } + } + break; + + case ICQ_CMDxTCP_READxAWAYxMSG: + case ICQ_CMDxTCP_READxOCCUPIEDxMSG: + case ICQ_CMDxTCP_READxNAxMSG: + case ICQ_CMDxTCP_READxDNDxMSG: + case ICQ_CMDxTCP_READxFREECHATxMSG: + packet >> theTCPSequence; + addAwayMsg(u, message, ICQ_CMDxTCP_START, ICQ_CMDxTCP_READxAWAYxMSG, theTCPSequence, time(NULL)); + break; + } + + // output the away message if there is one (ie if user status is not online) + if (userStatus == 0x0000) T("[tcp] ack from %d (%d).\n", u->uin, theTCPSequence); + else if (userStatus == 0x0001) + { + T("[tcp] refusal from %d (%d): %s\n", u->uin, theTCPSequence, message); + } + else + { +// u->setAwayMessage(message); + T("[tcp] ack from %d (%d).\n", u->uin, theTCPSequence); +// T("[tcp] ack from %d (%ld): %s\n", u->uin, theTCPSequence, message); + } + + doneEvent(true, hSocket, theTCPSequence); + break; + + case ICQ_CMDxTCP_CANCEL: + switch (newCommand) + { + case ICQ_CMDxTCP_CHAT: + T("[tcp] chat request from %d (%d) cancelled.\n", checkUin, theTCPSequence); +// u->addMessage(chatReq, ICQ_CMDxTCP_CANCEL, ICQ_CMDxTCP_CHAT, 0); + break; + + case ICQ_CMDxTCP_FILE: + T("[tcp] file transfer request from %d (%d) cancelled.\n", u->uin, theTCPSequence); +// u->addMessage(fileReq, ICQ_CMDxTCP_CANCEL, ICQ_CMDxTCP_FILE, 0); + break; + } + break; + + default: + T("[tcp] unknown packet:\n%s", packet.print()); + packet.reset(); + } + delete [] message; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::ackTCP(Packet &packet, ICQUser *u, unsigned short newCommand, unsigned int theSequence) +{ + unsigned int status; + + switch (statusVal) + { + case ID_STATUS_ONLINE: status = 0x00100000; break; + case ID_STATUS_FREECHAT: status = 0x00000000; break; // ?? + case ID_STATUS_AWAY: status = 0x01100000; break; + case ID_STATUS_NA: status = 0x00100000; break; + case ID_STATUS_DND: status = 0x00100000; break; + case ID_STATUS_OCCUPIED: status = 0x02100000; break; + case ID_STATUS_INVISIBLE: status = 0x00900000; break; // ?? + default: status = 0x00100000; break; + } + + packet.clearPacket(); + packet << uin + << (unsigned short)0x02 + << (unsigned short)ICQ_CMDxTCP_ACK // ICQ_CMDxTCP_ACK, ICQ_CMDxTCP_START, ICQ_CMDxTCP_CANCEL + << (unsigned short)0x00 + << uin + << newCommand + << awayMessage + << u->socket.localIPVal + << u->socket.localIPVal + << u->socket.localPortVal + << (unsigned char)0x04 + << status + << theSequence; + + T("[tcp] sending ack (%d)\n", theSequence); + u->socket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::recvUDP(int) +{ + Packet packet; + + // mirabilis contacts us using udp on this server + if (udpSocket.receivePacket(packet)) processUdpPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::recvNewTCP(int) +{ + ICQUser *u; + Packet handshake; + + // our tcp incoming server + TCPSocket newSocket(0); + tcpSocket.receiveConnection(newSocket); + newSocket.receivePacket(handshake); + + unsigned int ulJunk, newUin, localHost; + unsigned short command, usJunk; + unsigned char ucJunk; + + handshake >> command; + + if (command != ICQ_CMDxTCP_HANDSHAKE && command != ICQ_CMDxTCP_HANDSHAKE2 && command != ICQ_CMDxTCP_HANDSHAKE3) + { + T("[tcp] garbage packet:\n%s", handshake.print()); + handshake.reset(); + } + else + { + handshake >> ulJunk + >> usJunk + >> ucJunk + >> newUin + >> localHost + >> localHost + >> ulJunk + >> ucJunk; + + u = getUserByUIN(newUin); + if (!u->socket.connected()) + { + T("[tcp] connection from uin %d.\n", newUin); + u->socket.transferConnectionFrom(newSocket); + } + else + { + unsigned int i; + ICQTransfer *t; + + T("[tcp] file direct connection from uin %d.\n", newUin); + for (i=0; iuin == newUin && !t->socket.connected()) t->socket.transferConnectionFrom(newSocket); + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::recvTCP(SOCKET hSocket) +{ + unsigned int i; + Packet packet; + ICQUser *u; + + for(i=0; isocket.handleVal == hSocket) + { + if (!u->socket.receivePacket(packet)) + { + T("[tcp] connection to %d lost.\n", u->uin); + return; + } + processTcpPacket(packet, hSocket); + return; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::recvTransferTCP(SOCKET hSocket) +{ + unsigned int i; + Packet packet; + ICQTransfer *transfer; + + for(i=0; isocket.handleVal == hSocket) + { + if (!transfer->socket.receivePacket(packet)) + { +// T("[tcp] connection to %d lost.\n", s->uin); + return; + } + transfer->processTcpPacket(packet); + return; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::addMessage(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t) +{ + CCSDATA ccs; + PROTORECVEVENT pre; + + T("message: %s\n", m); + + ccs.hContact = u->hContact; + ccs.szProtoService = PSR_MESSAGE; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.flags = 0; + pre.timestamp = t; + pre.szMessage = (char*)m; + pre.lParam = 0; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::addUrl(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t) +{ + unsigned int i, messageLen; + char *url; + CCSDATA ccs; + PROTORECVEVENT pre; + + messageLen = lstrlen(m); + for (i=0; ihContact; + ccs.szProtoService = PSR_URL; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.flags = 0; + pre.timestamp = t; + pre.szMessage = url; + pre.lParam = 0; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + + delete [] url; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::addAwayMsg(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t) +{ + CCSDATA ccs; + PROTORECVEVENT pre; + + T("away msg: %s\n", m); + + ccs.hContact = u->hContact; + ccs.szProtoService = PSR_AWAYMSG; + ccs.wParam = u->statusVal; + ccs.lParam = (LPARAM)⪯ + pre.flags = 0; + pre.timestamp = t; + pre.szMessage = (char*)m; + pre.lParam = theSequence; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); +} + +/////////////////////////////////////////////////////////////////////////////// +/* +void ICQ::addAdded(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t) +{ + DBEVENTINFO dbei; + PBYTE pCurBlob; + + //blob is: uin(DWORD), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize=sizeof(dbei); + dbei.szModule="ICQ"; + dbei.timestamp=TimestampLocalToGMT(YMDHMSToTime(year,month,day,hour,minute,0)); + dbei.flags=0; + dbei.eventType=EVENTTYPE_ADDED; + dbei.cbBlob=sizeof(DWORD)+strlen(nick)+strlen(first)+strlen(last)+strlen(email)+4; + pCurBlob=dbei.pBlob=(PBYTE)malloc(dbei.cbBlob); + CopyMemory(pCurBlob,&uin,sizeof(DWORD)); pCurBlob+=sizeof(DWORD); + CopyMemory(pCurBlob,nick,strlen(nick)+1); pCurBlob+=strlen(nick)+1; + CopyMemory(pCurBlob,first,strlen(first)+1); pCurBlob+=strlen(first)+1; + CopyMemory(pCurBlob,last,strlen(last)+1); pCurBlob+=strlen(last)+1; + CopyMemory(pCurBlob,email,strlen(email)+1); pCurBlob+=strlen(email)+1; + CallService(MS_DB_EVENT_ADD,(WPARAM)(HANDLE)NULL,(LPARAM)&dbei); +} +*/ +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::addFileReq(ICQUser *u, char *m, char *filename, unsigned long size, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t) +{ + CCSDATA ccs; + PROTORECVEVENT pre; + char *szBlob; +/* + filetransfer *ft; + + // Initialize a filetransfer struct + ft = new filetransfer; + memset(ft, 0, sizeof(filetransfer)); + ft->status = 0; + ft->wCookie = wCookie; + ft->szFilename = _strdup(fileName); + ft->szDescription = _strdup(m); + ft->dwUin = u->uin; + ft->fileId = -1; + ft->dwTotalSize = size; + ft->nVersion = nVersion; + ft->TS1 = dwID1; + ft->TS2 = dwID2; +*/ + ICQTransfer *transfer = new ICQTransfer(u, theSequence); + transfer->description = _strdup(m); + transfer->totalSize = size; + + icqTransfers.push_back(transfer); + + + + // Send chain event + szBlob = new char[sizeof(DWORD) + strlen(filename) + strlen(m) + 2]; + + *(PDWORD)szBlob = (DWORD)transfer; + strcpy(szBlob + sizeof(DWORD), filename); + strcpy(szBlob + sizeof(DWORD) + strlen(filename) + 1, m); + + ccs.hContact = u->hContact; + ccs.szProtoService = PSR_FILE; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + pre.flags = 0; + pre.timestamp = t; + pre.szMessage = szBlob; + pre.lParam = theSequence; + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)&ccs); + + delete [] szBlob; + +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQ::doneUserFcn(bool ack, ICQEvent *icqEvent) +{ + unsigned int type = 0; + + if (icqEvent->subCmd == ICQ_CMDxTCP_MSG) type = ACKTYPE_MESSAGE; + if (icqEvent->subCmd == ICQ_CMDxTCP_URL) type = ACKTYPE_URL; + + ProtoBroadcastAck(protoName, getUserByUIN(icqEvent->uin)->hContact, type, ack ? ACKRESULT_SUCCESS : ACKRESULT_FAILED, (HANDLE)icqEvent->sequence, 0); +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/protocol.h b/protocols/ICQCorp/src/protocol.h new file mode 100644 index 0000000000..60294d834c --- /dev/null +++ b/protocols/ICQCorp/src/protocol.h @@ -0,0 +1,223 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef protocol_h +#define protocol_h + +/////////////////////////////////////////////////////////////////////////////// + + +#define ICQ_TCP_VER 0x0002 +#define ICQ_UDP_VER 0x0003 + +// UDP commands +const unsigned short ICQ_CMDxRCV_SETxOFFLINE = 0x0028; +const unsigned short ICQ_CMDxRCV_LOGIN_ERR = 0x0370; +const unsigned short ICQ_CMDxRCV_ACK = 0x000A; +const unsigned short ICQ_CMDxRCV_HELLO = 0x005A; +const unsigned short ICQ_CMDxRCV_WRONGxPASSWD = 0x0064; +const unsigned short ICQ_CMDxRCV_USERxONLINE = 0x006E; +const unsigned short ICQ_CMDxRCV_USERxOFFLINE = 0x0078; +const unsigned short ICQ_CMDxRCV_SEARCHxFOUND = 0x008C; +const unsigned short ICQ_CMDxRCV_SEARCHxDONE = 0x00A0; +const unsigned short ICQ_CMDxRCV_SYSxMSGxOFFLINE = 0x00DC; +const unsigned short ICQ_CMDxRCV_SYSxMSGxONLINE = 0x0104; +const unsigned short ICQ_CMDxRCV_SYSxMSGxDONE = 0x00E6; +const unsigned short ICQ_CMDxRCV_BROADCASTxMULTI = 0x0366; +const unsigned short ICQ_CMDxRCV_BROADCASTxOFFLINE = 0x038E; +const unsigned short ICQ_CMDxRCV_BROADCASTxONLINE = 0x03A2; +const unsigned short ICQ_CMDxRCV_BROADCASTxDONE = 0x0398; +const unsigned short ICQ_CMDxRCV_ERROR = 0x00F0; +const unsigned short ICQ_CMDxRCV_BUSY = 0x00FA; +const unsigned short ICQ_CMDxRCV_USERxBASICxINFO = 0x0118; +const unsigned short ICQ_CMDxRCV_USERxINFO = 0x02e4; +const unsigned short ICQ_CMDxRCV_USERxWORKxINFO = 0x02F8; +const unsigned short ICQ_CMDxRCV_USERxWORKxPAGE = 0x030C; +const unsigned short ICQ_CMDxRCV_USERxHOMExINFO = 0x0320; +const unsigned short ICQ_CMDxRCV_USERxHOMExPAGE = 0x0334; + +const unsigned short ICQ_CMDxRCV_USERxSTATUS = 0x01A4; +const unsigned short ICQ_CMDxRCV_USERxINVALIDxUIN = 0x02EE; +const unsigned short ICQ_CMDxRCV_USERxLISTxDONE = 0x021C; + +const unsigned short ICQ_CMDxRCV_SYSxMSG = 0x0001; +const unsigned short ICQ_CMDxRCV_SYSxURL = 0x0004; +const unsigned short ICQ_CMDxRCV_SYSxAUTHxREQ = 0x0006; +const unsigned short ICQ_CMDxRCV_SYSxAUTHxGRANTED = 0x0008; +const unsigned short ICQ_CMDxRCV_SYSxADDED = 0x000C; +const unsigned short ICQ_CMDxRCV_SYSxBROADCAST = 0x0014; + +const unsigned short ICQ_CMDxSND_ACK = 0x000A; +const unsigned short ICQ_CMDxSND_SEARCHxSTART = 0x05c8; +const unsigned short ICQ_CMDxSND_THRUxSERVER = 0x010E; +const unsigned short ICQ_CMDxSND_PING = 0x042E; +const unsigned short ICQ_CMDxSND_LOGON = 0x03E8; +const unsigned short ICQ_CMDxSND_LOGOFF = 0x0438; +const unsigned short ICQ_CMDxSND_SYSxMSGxDONExACK = 0x0442; +const unsigned short ICQ_CMDxSND_SYSxMSGxREQ = 0x044C; +const unsigned short ICQ_CMDxSND_BROADCASTxREQ = 0x0604; +const unsigned short ICQ_CMDxSND_MULTI = 0x05D2; +const unsigned short ICQ_CMDxSND_USERxGETxINFO = 0x05FA; +const unsigned short ICQ_CMDxSND_USERxGETxBASICxINFO = 0x0460; +const unsigned short ICQ_CMDxSND_USERxADD = 0x053C; +const unsigned short ICQ_CMDxSND_SETxSTATUS = 0x04D8; +const unsigned short ICQ_CMDxSND_USERxLIST = 0x0406; +const unsigned short ICQ_CMDxSND_INVISxLIST = 0x06A4; +const unsigned short ICQ_CMDxSND_VISxLIST = 0x06AE; +const unsigned short ICQ_CMDxSND_UPDATExLIST = 0x06B8; +const unsigned short ICQ_CMDxSND_AUTHORIZE = 0x0456; + +const unsigned short int ICQ_CMDxSND_PING2 = 0x051E; + +// TCP commands +const unsigned short ICQ_CMDxTCP_START = 0x07EE; +const unsigned short ICQ_CMDxTCP_CANCEL = 0x07D0; +const unsigned short ICQ_CMDxTCP_ACK = 0x07DA; + +const unsigned short ICQ_CMDxTCP_MSG = 0x0001; +const unsigned short ICQ_CMDxTCP_CHAT = 0x0002; +const unsigned short ICQ_CMDxTCP_FILE = 0x0003; +const unsigned short ICQ_CMDxTCP_URL = 0x0004; +const unsigned short ICQ_CMDxTCP_READxAWAYxMSG = 0x03E8; +const unsigned short ICQ_CMDxTCP_READxOCCUPIEDxMSG = 0x03E9; +const unsigned short ICQ_CMDxTCP_READxNAxMSG = 0x03EA; +const unsigned short ICQ_CMDxTCP_READxDNDxMSG = 0x03EB; +const unsigned short ICQ_CMDxTCP_READxFREECHATxMSG = 0x03EC; +const unsigned short ICQ_CMDxTCP_HANDSHAKE = 0x03FF; +const unsigned short ICQ_CMDxTCP_HANDSHAKE2 = 0x04FF; +const unsigned short ICQ_CMDxTCP_HANDSHAKE3 = 0x02FF; + +// status constants +const unsigned short int ICQ_STATUS_OFFLINE = 0xFFFF; +const unsigned short int ICQ_STATUS_ONLINE = 0x0000; +const unsigned short int ICQ_STATUS_AWAY = 0x0001; +const unsigned short int ICQ_STATUS_NA = 0x0005; +const unsigned short int ICQ_STATUS_OCCUPIED = 0x0011; +const unsigned short int ICQ_STATUS_DND = 0x0013; +const unsigned short int ICQ_STATUS_FREECHAT = 0x0020; +const unsigned short int ICQ_STATUS_PRIVATE = 0x0100; + +// miscellaneous constants +const unsigned short int ICQ_VERSION = 0x0003; +const unsigned short MAX_MESSAGE_SIZE = 450; +const unsigned short INT_VERSION = 40; +const unsigned short PING_FREQUENCY = 45000; +const unsigned short DEFAULT_SERVER_PORT = 4000; +const unsigned short MAX_SERVER_RETRIES = 3; +const unsigned short MAX_WAIT_ACK = 10000; +const unsigned long LOCALHOST = 0x0100007F; + + +const unsigned int WM_NETEVENT_SERVER = WM_USER + 1; +const unsigned int WM_NETEVENT_CONNECTION = WM_USER + 2; +const unsigned int WM_NETEVENT_USER = WM_USER + 3; +const unsigned int WM_NETEVENT_TRANSFER = WM_USER + 4; + +/////////////////////////////////////////////////////////////////////////////// + +typedef struct { //extended search result structure, used for all searches + PROTOSEARCHRESULT hdr; + DWORD uin; + BYTE auth; +} ICQSEARCHRESULT; + +/////////////////////////////////////////////////////////////////////////////// + +class ICQ +{ +public: + ICQ(); + bool load(); + void unload(); + + bool setStatus(unsigned short newStatus); + ICQEvent *sendMessage(ICQUser *u, char *m); + ICQEvent *sendUrl(ICQUser *u, char *url); + ICQEvent *sendReadAwayMsg(ICQUser *u); + ICQTransfer *sendFile(ICQUser *u, char *description, char *filename, unsigned int size, char **files); + + bool logon(unsigned short logonStatus); + void logoff(bool reconnect); + void ping(); + unsigned short processUdpPacket(Packet &packet); + void doneEvent(bool gotAck, int hSocket, int sequence); + void cancelEvent(ICQEvent *&); + void ackUDP(unsigned short theSequence); + ICQEvent *sendICQ(Socket &socket, Packet &packet, unsigned short cmd, unsigned long sequence, unsigned long uin = 0, unsigned short subCmd = 0, int reply = 0); + ICQUser *getUserByUIN(unsigned long uin, bool allowAdd = true); + ICQUser *getUserByContact(MCONTACT hContact); + void requestSystemMsg(); + void requestBroadcastMsg(); + void updateContactList(); + void sendVisibleList(); + void sendInvisibleList(); + void updateUserList(ICQUser *u, char list, char add); + void processSystemMessage(Packet &packet, unsigned long checkUin, unsigned short newCommand, time_t timeSent); + void ackSYS(unsigned int timeStamp); + ICQUser *addUser(unsigned int uin, bool peristent = true); + void addNewUser(ICQUser *u); + void removeUser(ICQUser *u); + void startSearch(unsigned char skrit, unsigned char smode, char *sstring, unsigned int s); + + + bool getUserInfo(ICQUser *u, bool basicInfo); + void authorize(unsigned int uinToAuthorize); + void processTcpPacket(Packet &packet, unsigned int hSocket); + void ackTCP(Packet &packet, ICQUser *u, unsigned short newCommand, unsigned int theSequence); + void recvUDP(int); + void recvNewTCP(int); + void recvTCP(SOCKET hSocket); + void recvTransferTCP(SOCKET hSocket); + + void addMessage(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t = 0); + void addUrl(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t = 0); + void addAwayMsg(ICQUser *u, char *m, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t = 0); + void addFileReq(ICQUser *u, char *m, char *filename, unsigned long size, unsigned short theCmd, unsigned short theSubCmd, unsigned long theSequence, time_t t = 0); + void doneUserFcn(bool ack, ICQEvent *icqEvent); + + void acceptFile(ICQUser *u, unsigned long hTransfer, char *path); + void refuseFile(ICQUser *u, unsigned long hTransfer, char *reason); + + TCPSocket tcpSocket; + UDPSocket udpSocket; + unsigned short sequenceVal, searchSequenceVal; + unsigned int uin, tcpSequenceVal; + unsigned short desiredStatus; + unsigned short statusVal; + unsigned int pingTimer; +// int eventThread; + HWND hWnd; + char *awayMessage; + unsigned int timeStampLastMessage; +private: + ICQEvent *send(ICQUser *u, unsigned short cmd, char *cmdStr, char *m); + + bool openConnection(TCPSocket &socket); + + ICQEvent *sendTCP(ICQUser *u, unsigned short cmd, char *cmdStr, char *m); + + ICQEvent *sendUDP(ICQUser *u, unsigned short cmd, char *cmdStr, char *m); + +}; + +/////////////////////////////////////////////////////////////////////////////// + +extern ICQ icq; + +#endif diff --git a/protocols/ICQCorp/src/resource.h b/protocols/ICQCorp/src/resource.h new file mode 100644 index 0000000000..7d590bb97b --- /dev/null +++ b/protocols/ICQCorp/src/resource.h @@ -0,0 +1,46 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#define IDI_ICQCORP 1 + +/////////////////////////////////////////////////////////////////////////////// + +#define IDD_INFO_ICQCORP 101 + +#define IDC_INFO_UIN 1001 +#define IDC_INFO_IP 1002 +#define IDC_INFO_REALIP 1003 +#define IDC_INFO_PORT 1004 +#define IDC_INFO_VERSION 1005 +#define IDC_INFO_MIRVER 1006 +#define IDC_INFO_PING 1007 + +/////////////////////////////////////////////////////////////////////////////// + +#define IDD_OPT_ICQCORP 102 + +#define IDC_OPT_UIN 1001 +#define IDC_OPT_PASSWORD 1002 +#define IDC_OPT_SERVER 1003 +#define IDC_OPT_PORT 1004 +#define IDC_OPT_RECONNECT 1005 + +/////////////////////////////////////////////////////////////////////////////// + +#define IDC_STATIC -1 diff --git a/protocols/ICQCorp/src/services.cpp b/protocols/ICQCorp/src/services.cpp new file mode 100644 index 0000000000..a94fa5450c --- /dev/null +++ b/protocols/ICQCorp/src/services.cpp @@ -0,0 +1,589 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqGetCaps(WPARAM wParam, LPARAM lParam) +{ + switch (wParam) + { + case PFLAGNUM_1: + return PF1_IM|PF1_URL|PF1_FILE|PF1_MODEMSG|PF1_AUTHREQ|PF1_ADDED|PF1_PEER2PEER|PF1_BASICSEARCH|PF1_EXTSEARCH|PF1_CANRENAMEFILE|PF1_FILERESUME|PF1_ADDSEARCHRES|PF1_SEARCHBYEMAIL|PF1_SEARCHBYNAME|PF1_NUMERICUSERID; + + case PFLAGNUM_2: + return PF2_ONLINE|PF2_INVISIBLE|PF2_SHORTAWAY|PF2_LONGAWAY|PF2_LIGHTDND|PF2_HEAVYDND|PF2_FREECHAT; + + case PFLAGNUM_3: + return PF2_SHORTAWAY|PF2_LONGAWAY|PF2_LIGHTDND|PF2_HEAVYDND|PF2_FREECHAT; + + case PFLAG_UNIQUEIDTEXT: + return (int)Translate("ICQ number:"); + + case PFLAG_UNIQUEIDSETTING: + return (int)"UIN"; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqGetName(WPARAM wParam, LPARAM lParam) +{ + strncpy((char*)lParam, Translate(protoName), wParam); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqLoadIcon(WPARAM wParam, LPARAM lParam) +{ + unsigned int id; + + switch (wParam & 0xFFFF) + { + case PLI_PROTOCOL: id = IDI_ICQCORP; break; + default: return (int)(HICON)NULL; + } + return (int)LoadImage(hInstance, MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSetStatus(WPARAM wParam, LPARAM lParam) +{ + unsigned short desiredStatus = (unsigned short)wParam; + + T("[ ] set status\n"); + + // on change status to online set away msg not calling + if (desiredStatus == ID_STATUS_ONLINE) icq.awayMessage[0] = 0; + + if (icq.desiredStatus == desiredStatus) return 0; + if (desiredStatus == ID_STATUS_OFFLINE) + { + icq.desiredStatus = desiredStatus; + icq.logoff(false); + } + else + { + if (icq.statusVal == ID_STATUS_OFFLINE) icq.logon(desiredStatus); + else icq.setStatus(desiredStatus); + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqGetStatus(WPARAM wParam, LPARAM lParam) +{ + return icq.statusVal; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqAuthAllow(WPARAM wParam, LPARAM lParam) +{ +// DBEVENTINFO dbei; + //DWORD uin; +/* + if (!icqOnline) return 1; + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = sizeof(DWORD); + dbei.pBlob = (PBYTE)&uin; + if (CallService(MS_DB_EVENT_GET, wParam, (LPARAM)&dbei)) return 1; + if (dbei.eventType != EVENTTYPE_AUTHREQUEST) return 1; + if (strcmp(dbei.szModule, ICQOSCPROTONAME)) return 1; + if (uin <= 1) return 1; + icq_sendAuthGrantedServ(uin); +*/ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqAuthDeny(WPARAM wParam, LPARAM lParam) +{ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqBasicSearch(WPARAM wParam, LPARAM lParam) +{ + T("[ ] basic search\n"); + icq.startSearch(0, 0, (char*)lParam, 0); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSearchByEmail(WPARAM wParam, LPARAM lParam) +{ + T("[ ] search by e-mail\n"); + icq.startSearch(4, 0, (char*)lParam, 0); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSearchByName(WPARAM wParam, LPARAM lParam) +{ + PROTOSEARCHBYNAME *psbn = (PROTOSEARCHBYNAME*)lParam; + + T("[ ] search by name\n"); + icq.startSearch(1, 0, psbn->pszNick, 0); + return 1; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqAddToList(WPARAM wParam, LPARAM lParam) +{ + ICQSEARCHRESULT *isr = (ICQSEARCHRESULT *)lParam; + bool persistent = (wParam & PALF_TEMPORARY) == 0; + + T("[ ] add user to list\n"); + if (isr->hdr.cbSize != sizeof(ICQSEARCHRESULT) || isr->uin == icq.uin) return NULL; + return (int)icq.addUser(isr->uin, persistent)->hContact; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqGetInfo(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + ICQUser *u; + + T("[ ] get user info\n"); + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL || icq.statusVal <= ID_STATUS_OFFLINE) return 1; + + icq.getUserInfo(u, ccs->wParam & SGIF_MINIMAL); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSendMessage(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + ICQUser *u; + ICQEvent *icqEvent; + + T("[ ] send message\n"); + + u = icq.getUserByContact(ccs->hContact); +// uin = db_get_dw(ccs->hContact, ICQCORP_PROTONAME, "UIN", 0); + if (u == NULL || icq.statusVal <= ID_STATUS_OFFLINE) return 0; + + icqEvent = icq.sendMessage(u, (char*)ccs->lParam); + return icqEvent ? icqEvent->sequence : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqRecvMessage(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA *ccs = (CCSDATA*)lParam; + PROTORECVEVENT *pre = (PROTORECVEVENT*)ccs->lParam; + + T("[ ] recieve message\n"); + + db_unset(ccs->hContact, "CList", "Hidden"); + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = protoName; + dbei.timestamp = pre->timestamp; + dbei.flags = pre->flags & (PREF_CREATEREAD ? DBEF_READ : 0); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = lstrlen(pre->szMessage) + 1; + dbei.pBlob = (PBYTE)pre->szMessage; + db_event_add(ccs->hContact, &dbei); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSendUrl(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + ICQUser *u; + ICQEvent *icqEvent; + + T("[ ] send url\n"); + + u = icq.getUserByContact(ccs->hContact); +// uin = db_get_dw(ccs->hContact, ICQCORP_PROTONAME, "UIN", 0); + if (u == NULL || icq.statusVal <= ID_STATUS_OFFLINE) return 0; + + icqEvent = icq.sendUrl(u, (char*)ccs->lParam); + return icqEvent ? icqEvent->sequence : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqRecvUrl(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA *ccs = (CCSDATA*)lParam; + PROTORECVEVENT *pre = (PROTORECVEVENT*)ccs->lParam; + char *pszDescr; + + T("[ ] recieve url\n"); + + db_unset(ccs->hContact, "CList", "Hidden"); + pszDescr = pre->szMessage + lstrlen(pre->szMessage) + 1; + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = protoName; + dbei.timestamp = pre->timestamp; + dbei.flags = pre->flags & (PREF_CREATEREAD ? DBEF_READ : 0); + dbei.eventType = EVENTTYPE_URL; + dbei.cbBlob = lstrlen(pre->szMessage) + lstrlen(pszDescr) + 2; + dbei.pBlob = (PBYTE)pre->szMessage; + db_event_add(ccs->hContact, &dbei); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSetAwayMsg(WPARAM wParam, LPARAM lParam) +{ + T("[ ] set away msg\n"); + + if (lParam == NULL) return 0; + + if (icq.awayMessage) delete [] icq.awayMessage; + icq.awayMessage = new char[strlen((char*)lParam) + 1]; + strcpy(icq.awayMessage, (char*)lParam); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqGetAwayMsg(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + ICQUser *u; + ICQEvent *icqEvent; + + T("[ ] send get away msg\n"); + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL || u->statusVal <= ID_STATUS_ONLINE) return 0; + + icqEvent = icq.sendReadAwayMsg(u); + return icqEvent ? icqEvent->sequence : 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqRecvAwayMsg(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + PROTORECVEVENT *pre = (PROTORECVEVENT *)ccs->lParam; + + T("[ ] recieve away message\n"); + + ProtoBroadcastAck(protoName, ccs->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)pre->lParam, (LPARAM)pre->szMessage); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSendFile(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + char **files = (char **)ccs->lParam; + //HANDLE hFile; + ICQUser *u; + + T("[ ] send file\n"); + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL || u->statusVal == ID_STATUS_OFFLINE || icq.statusVal <= ID_STATUS_OFFLINE) return 0; + + unsigned long filesCount, directoriesCount, filesSize = 0; + char filename[MAX_PATH], format[32]; + WIN32_FIND_DATA findData; + + for (filesCount=0,directoriesCount=0; files[filesCount]; filesCount++) + { + FindClose(FindFirstFile(files[filesCount], &findData)); + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) directoriesCount++; + else filesSize += findData.nFileSizeLow; + } + filesCount -= directoriesCount; + + if (directoriesCount) + { + sprintf(format, "%s, %s", filesCount == 1 ? Translate("%d file") : Translate("%d files"), directoriesCount == 1 ? Translate("%d directory") : Translate("%d directories")); + sprintf(filename, format, filesCount, directoriesCount); + } + else + { + if (filesCount == 1) + { + char *p = strrchr(files[0], '\\'); + strcpy(filename, p ? p+1 : files[0]); + } + else sprintf(filename, filesCount == 1 ? Translate("%d file") : Translate("%d files"), filesCount); + } + + return (int)icq.sendFile(u, (char*)ccs->wParam, filename, filesSize, files); +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqFileAllow(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + ICQTransfer *t = (ICQTransfer *)ccs->wParam; + ICQUser *u; + + T("[ ] send accept file request\n"); + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL || u->statusVal == ID_STATUS_OFFLINE) return 0; + + t->path = _strdup((char*)ccs->lParam); + + icq.acceptFile(u, t->sequence, (char*)ccs->lParam); + return (int)t; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqFileDeny(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *)lParam; + ICQTransfer *t = (ICQTransfer *)ccs->wParam; + ICQUser *u; + + T("[ ] send refuse file request\n"); + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL || u->statusVal == ID_STATUS_OFFLINE) return 0; + + icq.refuseFile(u, t->sequence, (char*)ccs->lParam); + + unsigned int i; + for (i=0; iwParam; + ICQUser *u; + + T("[ ] file cancel\n"); + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL || u->statusVal == ID_STATUS_OFFLINE) return 0; + +// icq.refuseFile(u, t->sequence, (char*)ccs->lParam); + + unsigned int i; + for (i=0; ilParam; + char *szDesc, *szFile; + + T("[ ] recieve file\n"); + + db_unset(ccs->hContact, "CList", "Hidden"); + + szFile = pre->szMessage + sizeof(DWORD); + szDesc = szFile + strlen(szFile) + 1; + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = protoName; + dbei.timestamp = pre->timestamp; + dbei.flags = pre->flags & (PREF_CREATEREAD ? DBEF_READ : 0); + dbei.eventType = EVENTTYPE_FILE; + dbei.cbBlob = sizeof(DWORD)+(DWORD)strlen(szFile) + (DWORD)strlen(szDesc) + 2; + dbei.pBlob = (PBYTE)pre->szMessage; + db_event_add(ccs->hContact, &dbei); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqFileResume(WPARAM wParam, LPARAM lParam) +{ + PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam; + ICQTransfer *t = (ICQTransfer *)wParam; + + T("[ ] send file resume\n"); + t->resume(pfr->action, pfr->szFilename); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static INT_PTR icqSetApparentMode(WPARAM wParam, LPARAM lParam) +{ +/* + CCSDATA *ccs = (CCSDATA *)lParam; + int oldMode, newMode = ccs->wParam; + ICQUser *u; + + u = icq.getUserByContact(ccs->hContact); + if (u == NULL) return 1; + + oldMode = db_get_w(u->hContact, ICQCORP_PROTONAME, "ApparentMode", 0); + if (newMode == oldMode) return 1; + + T("[ ] set apparent mode\n"); + + if (newMode == ID_STATUS_ONLINE || newMode == ID_STATUS_OFFLINE) db_set_w(u->hContact, ICQCORP_PROTONAME, "ApparentMode", (WORD)newMode); + else db_unset(u->hContact, ICQCORP_PROTONAME, "ApparentMode"); + + if (icq.statusVal <= ID_STATUS_OFFLINE) return 0; + + if (oldMode != 0) icq.updateUserList(u, oldMode == ID_STATUS_OFFLINE ? 1 : 2, 0); + if (newMode != 0) icq.updateUserList(u, newMode == ID_STATUS_OFFLINE ? 1 : 2, 1); +*/ + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int icqContactDeleted(WPARAM wParam, LPARAM lParam) +{ + ICQUser *u; + + T("[ ] contact deleted\n"); + + if ((u = icq.getUserByContact((MCONTACT)wParam)) != NULL) icq.removeUser(u); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +static int icqModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + HookEvent(ME_USERINFO_INITIALISE, icqUserInfoInitialise); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +char *CreateServiceName(char *serviceName, char *functionName) +{ + strcpy(serviceName, protoName); + strcat(serviceName, functionName); + + return serviceName; +} + +/////////////////////////////////////////////////////////////////////////////// + +int LoadServices() +{ + char serviceName[MAX_PATH + 30]; + + if (!icq.load()) return 1; + + HookEvent(ME_DB_CONTACT_DELETED, icqContactDeleted); + HookEvent(ME_OPT_INITIALISE, icqOptionsInitialise); + HookEvent(ME_SYSTEM_MODULESLOADED, icqModulesLoaded); + + CreateServiceFunction(CreateServiceName(serviceName, PS_GETCAPS), icqGetCaps); + CreateServiceFunction(CreateServiceName(serviceName, PS_GETNAME), icqGetName); + CreateServiceFunction(CreateServiceName(serviceName, PS_LOADICON), icqLoadIcon); + CreateServiceFunction(CreateServiceName(serviceName, PS_SETSTATUS), icqSetStatus); + CreateServiceFunction(CreateServiceName(serviceName, PS_GETSTATUS), icqGetStatus); + CreateServiceFunction(CreateServiceName(serviceName, PS_SETAWAYMSG), icqSetAwayMsg); + CreateServiceFunction(CreateServiceName(serviceName, PS_AUTHALLOW), icqAuthAllow); + CreateServiceFunction(CreateServiceName(serviceName, PS_AUTHDENY), icqAuthDeny); + CreateServiceFunction(CreateServiceName(serviceName, PS_BASICSEARCH), icqBasicSearch); + CreateServiceFunction(CreateServiceName(serviceName, PS_SEARCHBYEMAIL), icqSearchByEmail); + CreateServiceFunction(CreateServiceName(serviceName, PS_SEARCHBYNAME), icqSearchByName); +// CreateServiceFunction(MS_ICQ_SEARCHBYDETAILS, icqSearchByDetails); + CreateServiceFunction(CreateServiceName(serviceName, PS_ADDTOLIST), icqAddToList); +// CreateServiceFunction(CreateServiceName(serviceName, PS_ADDTOLISTBYEVENT), icqAddToListByEvent); + CreateServiceFunction(CreateServiceName(serviceName, PS_FILERESUME), icqFileResume); + + CreateServiceFunction(CreateServiceName(serviceName, PSS_GETINFO), icqGetInfo); + CreateServiceFunction(CreateServiceName(serviceName, PSS_MESSAGE), icqSendMessage); + CreateServiceFunction(CreateServiceName(serviceName, PSS_URL), icqSendUrl); + CreateServiceFunction(CreateServiceName(serviceName, PSS_GETAWAYMSG), icqGetAwayMsg); + CreateServiceFunction(CreateServiceName(serviceName, PSS_FILE), icqSendFile); + CreateServiceFunction(CreateServiceName(serviceName, PSS_FILEALLOW), icqFileAllow); + CreateServiceFunction(CreateServiceName(serviceName, PSS_FILEDENY), icqFileDeny); + CreateServiceFunction(CreateServiceName(serviceName, PSS_FILECANCEL), icqFileCancel); + CreateServiceFunction(CreateServiceName(serviceName, PSS_SETAPPARENTMODE), icqSetApparentMode); + + CreateServiceFunction(CreateServiceName(serviceName, PSR_MESSAGE), icqRecvMessage); + CreateServiceFunction(CreateServiceName(serviceName, PSR_URL), icqRecvUrl); + CreateServiceFunction(CreateServiceName(serviceName, PSR_AWAYMSG), icqRecvAwayMsg); + CreateServiceFunction(CreateServiceName(serviceName, PSR_FILE), icqRecvFile); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +int UnloadServices() +{ + icq.unload(); + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/socket.cpp b/protocols/ICQCorp/src/socket.cpp new file mode 100644 index 0000000000..b3516f2069 --- /dev/null +++ b/protocols/ICQCorp/src/socket.cpp @@ -0,0 +1,399 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +/////////////////////////////////////////////////////////////////////////////// +// +// Socket +// +/////////////////////////////////////////////////////////////////////////////// + +Socket::Socket() +{ + handleVal = INVALID_SOCKET; + remoteIPVal = 0; + remotePortVal = 0; + localIPVal = 0; + localPortVal = 0; + messageVal = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +Socket::~Socket() +{ + if (connected()) closeConnection(); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::connected() +{ + return handleVal != INVALID_SOCKET; +}; + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::completed(int result) +{ + if (result != SOCKET_ERROR || WSAGetLastError() != WSAEWOULDBLOCK) return true; + + Sleep(1); + return false; +}; + +/////////////////////////////////////////////////////////////////////////////// + +void Socket::openSocket() +{ + if (connected()) WSAAsyncSelect(handleVal, icq.hWnd, messageVal, FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE); +} + +/////////////////////////////////////////////////////////////////////////////// + +void Socket::closeSocket() +{ + if (connected()) WSAAsyncSelect(handleVal, icq.hWnd, 0, 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::setDestination(unsigned long rIp, unsigned short rPort) +{ + char localName[128]; + + if (rIp == 0) return false; + gethostname(localName, 128); + localIPVal = lookup(localName); + + // set up remote connection + remoteIPVal = rIp; + remotePortVal = rPort; + remote.sin_port = htons(rPort); + remote.sin_addr.s_addr = rIp; + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::setDestination(char *rHost, unsigned short rPort) +{ + return setDestination(lookup(rHost), rPort); +}; + +/////////////////////////////////////////////////////////////////////////////// + +unsigned long Socket::lookup(char *h) +{ + unsigned long ina; + struct hostent *host; + + // check if the hostname is in dot and number notation + ina = inet_addr(h); + if (ina != INADDR_NONE) return ina; + + // try and resolve hostname + if ((host = gethostbyname(h)) == NULL) return 0; // Couldn't resolve hostname/ip + + // return the ip + return *((unsigned long *)host->h_addr); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::openConnection(int Type) +{ + struct sockaddr_in local; + + handleVal = socket(AF_INET, Type, 0); + if (handleVal == INVALID_SOCKET) return false; + + memset(&local.sin_zero, 0, 8); + local.sin_family = AF_INET; + local.sin_port = htons(localPortVal); + local.sin_addr.s_addr = htonl(INADDR_ANY); +// local.sin_addr.s_addr = htonl(localIPVal); + + memset(&remote.sin_zero, 0, 8); + remote.sin_family = AF_INET; + + bind(handleVal, (sockaddr*)&local, sizeof(sockaddr)); + + int sizeofSockaddr = sizeof(sockaddr); + getsockname(handleVal, (sockaddr*)&local, &sizeofSockaddr); + localPortVal = ntohs(local.sin_port); + if (local.sin_addr.s_addr) localIPVal = ntohl(local.sin_addr.s_addr); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void Socket::closeConnection() +{ + if (connected()) + { + closeSocket(); + shutdown(handleVal, SD_BOTH); + closesocket(handleVal); + handleVal = INVALID_SOCKET; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::sendBuffer(char *buffer, unsigned int bufferSize) +{ + int result; + + while (bufferSize > 0) + { + while (! completed(result = send(handleVal, buffer, bufferSize, 0))); + if (result <= 0) + { + closeConnection(); + return false; + } + buffer += result; + bufferSize -= result; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool Socket::receiveBuffer(char *buffer, unsigned int bufferSize) +{ + int result; + + while (bufferSize > 0) + { + while (! completed(result = recv(handleVal, buffer, bufferSize, 0))); + if (result <= 0) + { + closeConnection(); + return false; + } + buffer += result; + bufferSize -= result; + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// TCPSocket +// +/////////////////////////////////////////////////////////////////////////////// + +TCPSocket::TCPSocket(unsigned int msg) +{ + messageVal = msg; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool TCPSocket::openConnection() +{ + int result; + + if (remoteIPVal == 0) return false; + if (! Socket::openConnection(SOCK_STREAM)) return false; + + result = connect(handleVal, (sockaddr*)&remote, sizeof(sockaddr)); + if (result == SOCKET_ERROR) + { + closeConnection(); + return false; + } + openSocket(); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void TCPSocket::receiveConnection(TCPSocket &newSocket) +{ + int sizeofSockaddr = sizeof(sockaddr); + newSocket.handleVal = accept(handleVal, (sockaddr*)&remote, &sizeofSockaddr); + newSocket.openSocket(); + + sizeofSockaddr = sizeof(sockaddr); + getpeername(newSocket.handleVal, (sockaddr*)&newSocket.remote, &sizeofSockaddr); + + newSocket.remoteIPVal = newSocket.remote.sin_addr.s_addr; + newSocket.remotePortVal = ntohs(newSocket.remote.sin_port); + + newSocket.localIPVal = localIPVal; + newSocket.localPortVal = localPortVal; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool TCPSocket::startServer() +{ + if (! Socket::openConnection(SOCK_STREAM)) return false; + listen(handleVal, 10); + openSocket(); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +void TCPSocket::transferConnectionFrom(TCPSocket &from) +{ + handleVal = from.handleVal; + remoteIPVal = from.remoteIPVal; + remotePortVal = from.remotePortVal; + localIPVal = from.localIPVal; + localPortVal = from.localPortVal; + + from.closeSocket(); + from.handleVal = INVALID_SOCKET; + openSocket(); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool TCPSocket::sendPacket(Packet &p) +{ + return sendPacket(p, true); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool TCPSocket::receivePacket(Packet &p) +{ + return receivePacket(p, true); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool TCPSocket::sendPacket(Packet &p, bool sendSize) +{ + if (! connected()) return false; + if (sendSize) + { + char pSize[2]; + + pSize[0] = (p.sizeVal) & 0xFF; + pSize[1] = (p.sizeVal >> 8) & 0xFF; + + if (! sendBuffer(pSize, 2)) return false; + } + return sendBuffer(p.buff, p.sizeVal); +} + +/////////////////////////////////////////////////////////////////////////////// + +bool TCPSocket::receivePacket(Packet &p, bool recvSize) +{ + unsigned short sizeVal; + + if (! connected()) return false; + WSAAsyncSelect(handleVal, icq.hWnd, messageVal, FD_ACCEPT|FD_CONNECT|FD_CLOSE); + + p.clearPacket(); + if (recvSize) + { + if (!receiveBuffer((char*)&sizeVal, 2) || sizeVal > p.maxSize) return false; + } + else sizeVal = 1; + + if (! receiveBuffer(p.buff, sizeVal)) return false; + p.sizeVal = sizeVal; + + WSAAsyncSelect(handleVal, icq.hWnd, messageVal, FD_READ|FD_ACCEPT|FD_CONNECT|FD_CLOSE); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// UDPSocket +// +/////////////////////////////////////////////////////////////////////////////// + +UDPSocket::UDPSocket(unsigned int msg) +{ + messageVal = msg; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool UDPSocket::openConnection() +{ + if (remoteIPVal == 0) return false; + if (! Socket::openConnection(SOCK_DGRAM)) return false; + openSocket(); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool UDPSocket::startServer() +{ + if (! Socket::openConnection(SOCK_DGRAM)) return false; + openSocket(); + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool UDPSocket::sendPacket(Packet &p) +{ + if (! connected()) return false; + + unsigned int bytesSent = 0; + bytesSent = sendto(handleVal, p.buff, p.sizeVal, 0, (sockaddr*)&remote, sizeof(sockaddr)); + + // if unable to send anything + if (bytesSent != p.sizeVal) + { + closeConnection(); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +bool UDPSocket::receivePacket(Packet &p) +{ + if (! connected()) return false; + + int sizeofSockaddr = sizeof(sockaddr); + p.clearPacket(); + p.sizeVal = recvfrom(handleVal, p.buff, p.maxSize, 0, (sockaddr*)&remote, &sizeofSockaddr); + + // it didn't manage to receive anything, there was an error, close the socket and return false + if (int(p.sizeVal) <= 0) + { + closeConnection(); + return false; + } + + // make sure the size won't overflow the buffer + if (p.sizeVal > p.maxSize) p.sizeVal = p.maxSize - sizeof(unsigned long); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/socket.h b/protocols/ICQCorp/src/socket.h new file mode 100644 index 0000000000..5efd6e5df1 --- /dev/null +++ b/protocols/ICQCorp/src/socket.h @@ -0,0 +1,85 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef socket_h +#define socket_h + +#include "packet.h" + +/////////////////////////////////////////////////////////////////////////////// + +class Socket +{ +public: + SOCKET handleVal; + unsigned int remoteIPVal, remotePortVal; + unsigned int localIPVal, localPortVal; + unsigned int messageVal; + Socket(); + ~Socket(); + bool connected(); + bool completed(int result); + bool setDestination(unsigned long rIp, unsigned short rPort); + bool setDestination(char *rHost, unsigned short rPort); + void resetSocket(); + unsigned long lookup(char *h); + bool openConnection(int Type); + void closeConnection(); + virtual bool startServer() = 0; + virtual bool sendPacket(Packet &p) = 0; + virtual bool receivePacket(Packet &p) = 0; +protected: + struct sockaddr_in remote; + void openSocket(); + void closeSocket(); + bool sendBuffer(char *buffer, unsigned int bufferSize); + bool receiveBuffer(char *buffer, unsigned int bufferSize); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class TCPSocket : public Socket +{ +public: + TCPSocket(unsigned int msg); + bool openConnection(); + virtual bool startServer(); + virtual bool sendPacket(Packet &p); + virtual bool receivePacket(Packet &p); + bool sendPacket(Packet &p, bool sendSize); + bool receivePacket(Packet &p, bool recvSize); + void receiveConnection(TCPSocket &newSocket); + void transferConnectionFrom(TCPSocket &from); +}; + +/////////////////////////////////////////////////////////////////////////////// + +class UDPSocket : public Socket +{ +public: + UDPSocket(unsigned int msg); + bool openConnection(); + virtual bool startServer(); + virtual bool sendPacket(Packet &p); + virtual bool receivePacket(Packet &p); +}; + +/////////////////////////////////////////////////////////////////////////////// + +#endif diff --git a/protocols/ICQCorp/src/stdafx.cpp b/protocols/ICQCorp/src/stdafx.cpp new file mode 100644 index 0000000000..36e7f91d0c --- /dev/null +++ b/protocols/ICQCorp/src/stdafx.cpp @@ -0,0 +1,18 @@ +/* +Copyright (c) 2013-14 Miranda NG project (http://miranda-ng.org) + +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 version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "corp.h" diff --git a/protocols/ICQCorp/src/transfer.cpp b/protocols/ICQCorp/src/transfer.cpp new file mode 100644 index 0000000000..eb1a8dbf7b --- /dev/null +++ b/protocols/ICQCorp/src/transfer.cpp @@ -0,0 +1,505 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +std::vector icqTransfers; + +/////////////////////////////////////////////////////////////////////////////// + +void WINAPI transferTimerProc(HWND hWnd, UINT Msg, UINT_PTR hTimer, DWORD Time) +{ + unsigned int i; + + KillTimer(NULL, hTimer); + for (i=0; ihTimer) icqTransfers[i]->process(); +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQTransfer::ICQTransfer(ICQUser *u, unsigned int theSequence) : + socket(WM_NETEVENT_TRANSFER) +{ + uin = u->uin; + hContact = u->hContact; + sequence = theSequence; + files = NULL; + description = NULL; + path = NULL; + sending = 0; + speed = 100; + count = 0; + current = -1; + fileName = NULL; + fileSize = 0; + fileProgress = 0; + totalSize = 0; + totalProgress = 0; + lastNotify = 0; + hTimer = NULL; + hFile = INVALID_HANDLE_VALUE; +} + +/////////////////////////////////////////////////////////////////////////////// + +ICQTransfer::~ICQTransfer() +{ + closeFile(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::processTcpPacket(Packet &packet) +{ + unsigned int /*i,*/ status, junkLong; + //unsigned short junkShort; + unsigned char cmd/*, junkChar*/; + char *name = NULL, *directoryName = NULL; + + packet >> cmd; + switch (cmd) + { + case 0x00: + T("[tcp] recieve initialising file transfer\n"); + packet >> junkLong + >> count + >> totalSize + >> speed + >> name; + + files = new char*[count + 1]; + ZeroMemory(files, (count+1)*sizeof(char*)); + + ack(ACKRESULT_INITIALISING); + sendPacket0x01(); + break; + + case 0x01: + T("[tcp] ack initialising\n"); + packet >> speed + >> name; + + ack(ACKRESULT_INITIALISING); + sendPacket0x02(); + break; + + case 0x02: + T("[tcp] recieve next file\n"); + packet >> directory + >> files[++current] + >> directoryName + >> fileSize + >> fileDate + >> speed; + + if (directoryName[0]) + { + char *fullName = new char[strlen(directoryName) + strlen(files[current]) + 2]; + sprintf(fullName, "%s\\%s", directoryName, files[current]); + delete [] files[current]; + files[current] = fullName; + } + + if (directory) createDirectory(); + else openFile(); + ack(ACKRESULT_NEXTFILE); + + if (fileProgress) ack(ACKRESULT_FILERESUME); + else sendPacket0x03(); + break; + + case 0x03: + T("[tcp] ack next file\n"); + packet >> fileProgress + >> status + >> speed; + + totalProgress += fileProgress; + setFilePosition(); + ack(ACKRESULT_NEXTFILE); + + if (status != 0) + { + totalProgress += fileSize - fileProgress; + fileProgress = fileSize; + closeFile(); + ack(ACKRESULT_DATA); + } + + process(); + break; + + case 0x04: + T("[tcp] recieve stop file\n"); + packet >> junkLong; + + totalProgress += fileSize - fileProgress; + fileProgress = fileSize; + closeFile(); + ack(ACKRESULT_DATA); + break; + + case 0x05: + T("[tcp] recieve new speed\n"); + packet >> speed; + break; + + case 0x06: + unsigned long result; + + WriteFile(hFile, packet.data(), packet.dataSize(), &result, NULL); + + fileProgress += result; + totalProgress += result; + + if (fileProgress >= fileSize) closeFile(); + ack(ACKRESULT_DATA); + break; + + default: + T("[tcp] unknown packet:\n%s", packet.print()); + packet.reset(); + } + + delete [] directoryName; + delete [] name; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x00() +{ + char nick[1] = { 0 }; + + sending = true; + + Packet packet; + packet << (unsigned char)0x00 + << (unsigned int)0x00 + << count + << totalSize + << speed + << nick; + + T("[tcp] send packet 0x00\n"); + socket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x01() +{ + char nick[1] = { 0 }; + + Packet packet; + packet << (unsigned char)0x01 + << speed + << nick; + + T("[tcp] send packet 0x01\n"); + socket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x02() +{ + char *directoryName, *p; + + current++; + openFile(); + + directoryName = _strdup(fileName); + p = strrchr(directoryName, '\\'); + p[0] = 0; + p[1] = 0; + + Packet packet; + packet << (unsigned char)0x02 + << directory + << (strrchr(fileName, '\\') + 1) + << (directoryName + strlen(path) + 1) + << fileSize + << fileDate + << speed; + + T("[tcp] send packet 0x02\n"); + socket.sendPacket(packet); + ack(ACKRESULT_NEXTFILE); + + free(directoryName); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x03() +{ + Packet packet; + packet << (unsigned char)0x03 + << fileProgress + << (unsigned int)0x00 + << speed; + + setFilePosition(); + + T("[tcp] send packet 0x03\n"); + socket.sendPacket(packet); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x04() +{ + T("[tcp] send packet 0x04\n"); +/* + icq_PacketAppend8(p, 0x04); + icq_PacketAppend32(p, filenum); +*/ +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x05() +{ + T("[tcp] send packet 0x05\n"); +/* + icq_PacketAppend8(p, 0x05); + icq_PacketAppend32(p, speed); +*/ +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::sendPacket0x06() +{ + unsigned long result; + + Packet packet; + packet << (unsigned char)0x06; + + ReadFile(hFile, packet.data(), 2048, &result, NULL); + if (result == 0) return; + packet.add(result); + +// T("[tcp] send packet 0x06\n"); + socket.sendPacket(packet); + + fileProgress += result; + totalProgress += result; + + if (fileProgress >= fileSize) closeFile(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::ack(unsigned int result) +{ + PROTOFILETRANSFERSTATUS fts; + + if (result == ACKRESULT_DATA && GetTickCount() < lastNotify+250 && fileProgress < fileSize) return; + + fts.cbSize = sizeof(fts); + fts.hContact = hContact; + //fts.sending = sending; + fts.pszFiles = files; + fts.totalFiles = count; + fts.currentFileNumber = current; + fts.totalBytes = totalSize; + fts.totalProgress = totalProgress; + fts.szWorkingDir = path; + fts.szCurrentFile = fileName; + fts.currentFileSize = fileSize; + fts.currentFileProgress = fileProgress; + fts.currentFileTime = CallService(MS_DB_TIME_TIMESTAMPTOLOCAL, fileDate, 0); +/* + switch (session->status) + { + case FILE_STATUS_LISTENING: result = ACKRESULT_SENTREQUEST; break; + case FILE_STATUS_CONNECTED: result = ACKRESULT_CONNECTED; break; + case FILE_STATUS_CONNECTING: result = ACKRESULT_CONNECTING; break; + case FILE_STATUS_INITIALIZING: result = ACKRESULT_INITIALISING; break; + case FILE_STATUS_NEXT_FILE: result = ACKRESULT_NEXTFILE; break; + case FILE_STATUS_SENDING: + case FILE_STATUS_RECEIVING: result=ACKRESULT_DATA; break; + } +*/ + ProtoBroadcastAck(protoName, hContact, ACKTYPE_FILE, result, this, (LPARAM)&fts); + lastNotify = GetTickCount(); + + if (result == ACKRESULT_DATA && current >= count-1 && fileProgress >= fileSize) + { + ProtoBroadcastAck(protoName, hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0); + socket.closeConnection(); + + unsigned int i; + for (i=0; i= count) return; + + startTime = GetTickCount(); + while (fileProgress < fileSize && GetTickCount() < startTime+100) sendPacket0x06(); + ack(ACKRESULT_DATA); + + if (fileProgress < fileSize) hTimer = SetTimer(NULL, 0, 1, (TIMERPROC)transferTimerProc); + else if (current < count-1) sendPacket0x02(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::resume(int action, const char *newName) +{ + switch (action) + { + case FILERESUME_OVERWRITE: + T("[ ] overwrite existing file\n"); + fileProgress = 0; + break; + + case FILERESUME_RESUME: + T("[ ] file resume\n"); + break; + + case FILERESUME_RENAME: + T("[ ] rename file\n"); + delete [] fileName; + fileName = new char[strlen(newName) + 1]; + strcpy(fileName, newName); + files[current] = fileName; + + openFile(); + fileProgress = 0; + break; + + case FILERESUME_SKIP: + T("[ ] skip file\n"); + fileProgress = fileSize; + break; + } + + totalProgress += fileProgress; + + sendPacket0x03(); + ack(ACKRESULT_NEXTFILE); + + if (fileProgress) ack(ACKRESULT_DATA); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::openFile() +{ + HANDLE hFind; + WIN32_FIND_DATA findData; + __int64 fileTime; + + if (hFile != INVALID_HANDLE_VALUE) closeFile(); + if (path) SetCurrentDirectory(path); + + fileName = files[current]; + + hFind = FindFirstFile(fileName, &findData); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + T("open directory %s\n", fileName); + directory = 1; + fileProgress = 0; + fileSize = 0; + fileDate = *(__int64*)(&findData.ftLastWriteTime) / 10000000 - 11644473600i64; + return; + } + } + directory = 0; + + hFile = CreateFile(fileName, sending ? GENERIC_READ : GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) + { + char msg[2048]; + + T("can't open file %s\n", fileName); + sprintf(msg, "%s\n%s", sending ? Translate("Your file transfer has been aborted because one of the files that you selected to send is no longer readable from the disk. You may have deleted or moved it.") : Translate("Your file receive has been aborted because Miranda could not open the destination file in order to write to it. You may be trying to save to a read-only folder."), fileName); + MessageBox(NULL, msg, Translate(protoName), MB_ICONWARNING|MB_OK); + return; + } + + if (sending) + { + fileProgress = 0; + fileSize = GetFileSize(hFile, NULL); + + GetFileTime(hFile, NULL, NULL, (LPFILETIME)&fileTime); + fileDate = fileTime / 10000000 - 11644473600i64; + } + else + { + fileProgress = GetFileSize(hFile, NULL); + + fileTime = (11644473600i64 + (__int64)fileDate) * 10000000; + SetFileTime(hFile, NULL, NULL, (LPFILETIME)&fileTime); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::closeFile() +{ + CloseHandle(hFile); + hFile = INVALID_HANDLE_VALUE; +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::setFilePosition() +{ + if (hFile != INVALID_HANDLE_VALUE) SetFilePointer(hFile, fileProgress, NULL, FILE_BEGIN); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQTransfer::createDirectory() +{ + if (path) SetCurrentDirectory(path); + + fileName = files[current]; + CreateDirectory(fileName, NULL); + + fileProgress = 0; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/transfer.h b/protocols/ICQCorp/src/transfer.h new file mode 100644 index 0000000000..8bfed7fe4a --- /dev/null +++ b/protocols/ICQCorp/src/transfer.h @@ -0,0 +1,75 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef transfer_h +#define transfer_h + +/////////////////////////////////////////////////////////////////////////////// + +class ICQTransfer +{ +public: + unsigned int uin; + MCONTACT hContact; + unsigned int sequence; + TCPSocket socket; + char **files; + char *description; + char *path; + unsigned char directory; + unsigned int sending; + unsigned int speed; + unsigned int count; + unsigned int current; + char *fileName; + unsigned int fileDate; + unsigned int fileSize; + unsigned int fileProgress; + unsigned int totalSize; + unsigned int totalProgress; + unsigned int lastNotify; + unsigned int hTimer; + HANDLE hFile; + + ICQTransfer(ICQUser *u, unsigned int theSequence); + ~ICQTransfer(); + void processTcpPacket(Packet &packet); + void sendPacket0x00(); + void sendPacket0x01(); + void sendPacket0x02(); + void sendPacket0x03(); + void sendPacket0x04(); + void sendPacket0x05(); + void sendPacket0x06(); + void ack(unsigned int result); + void process(); + void resume(int action, const char *newName); + void openFile(); + void closeFile(); + void setFilePosition(); + void createDirectory(); +}; + +/////////////////////////////////////////////////////////////////////////////// + +extern std::vector icqTransfers; + +/////////////////////////////////////////////////////////////////////////////// + +#endif \ No newline at end of file diff --git a/protocols/ICQCorp/src/user.cpp b/protocols/ICQCorp/src/user.cpp new file mode 100644 index 0000000000..c2274c7d26 --- /dev/null +++ b/protocols/ICQCorp/src/user.cpp @@ -0,0 +1,160 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#include "corp.h" + +std::vector icqUsers; + +/////////////////////////////////////////////////////////////////////////////// + +ICQUser::ICQUser() : + socket(WM_NETEVENT_USER) +{ +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQUser::setStatus(unsigned short newStatus) +{ + if (statusVal == newStatus) return; + + statusVal = newStatus; + db_set_w(hContact, protoName, "Status", newStatus); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQUser::setInfo(char *name, unsigned int data) +{ + if (data && data != 0xFFFFFFFF) db_set_dw(hContact, protoName, name, data); + else db_unset(hContact, protoName, name); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQUser::setInfo(char *name, unsigned short data) +{ + if (data && data != 0xFFFF) db_set_w(hContact, protoName, name, data); + else db_unset(hContact, protoName, name); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQUser::setInfo(char *name, unsigned char data) +{ + if (data && data != 0xFF) db_set_b(hContact, protoName, name, data); + else db_unset(hContact, protoName, name); +} + +/////////////////////////////////////////////////////////////////////////////// + +void ICQUser::setInfo(char *name, char *data) +{ + if (data[0]) db_set_s(hContact, protoName, name, data); + else db_unset(hContact, protoName, name); +} + +/////////////////////////////////////////////////////////////////////////////// + +static char *iptoa(unsigned int ip) +{ + struct in_addr addr; + + addr.S_un.S_addr = htonl(ip); + return inet_ntoa(addr); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void setTextValue(HWND hWnd, int id, char *value) +{ + bool unspecified = value == NULL; + + EnableWindow(GetDlgItem(hWnd, id), !unspecified); + SetDlgItemText(hWnd, id, unspecified ? Translate("") : value); +} + +/////////////////////////////////////////////////////////////////////////////// + +static BOOL CALLBACK icqUserInfoDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + LPNMHDR hdr; + + switch (msg) + { + case WM_INITDIALOG: + TranslateDialogDefault(hWnd); + return TRUE; + + case WM_NOTIFY: + hdr = (LPNMHDR)lParam; + if (hdr->idFrom == 0 && hdr->code == PSN_INFOCHANGED) + { + char buffer[64]; + unsigned long ip, port; + MCONTACT hContact = (MCONTACT)((LPPSHNOTIFY)lParam)->lParam; + + _itoa(db_get_dw(hContact, protoName, "UIN", 0), buffer, 10); + setTextValue(hWnd, IDC_INFO_UIN, buffer); + + ip = db_get_dw(hContact, protoName, "IP", 0); + setTextValue(hWnd, IDC_INFO_IP, ip ? iptoa(ip) : NULL); + + ip = db_get_dw(hContact, protoName, "RealIP", 0); + setTextValue(hWnd, IDC_INFO_REALIP, ip ? iptoa(ip) : NULL); + + port = db_get_w(hContact, protoName, "Port", 0); + _itoa(port, buffer, 10); + setTextValue(hWnd, IDC_INFO_PORT, port ? buffer : NULL); + + setTextValue(hWnd, IDC_INFO_VERSION, NULL); + setTextValue(hWnd, IDC_INFO_MIRVER, NULL); + setTextValue(hWnd, IDC_INFO_PING, NULL); + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDCANCEL) SendMessage(GetParent(hWnd), msg, wParam, lParam); + break; + } + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////// + +int icqUserInfoInitialise(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + char *proto; + + proto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, lParam, 0); + if ((proto == NULL || strcmp(proto, protoName)) && lParam) return 0; + + odp.cbSize = sizeof(odp); + odp.position = -1900000000; + odp.pszTitle = Translate(protoName); + odp.pfnDlgProc = (DLGPROC)icqUserInfoDlgProc; + odp.pszTemplate = MAKEINTRESOURCE(IDD_INFO_ICQCORP); + odp.hInstance = hInstance; + Options_AddPage(wParam, &odp); + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/ICQCorp/src/user.h b/protocols/ICQCorp/src/user.h new file mode 100644 index 0000000000..9c13867237 --- /dev/null +++ b/protocols/ICQCorp/src/user.h @@ -0,0 +1,52 @@ +/* + ICQ Corporate protocol plugin for Miranda IM. + Copyright (C) 2003-2005 Eugene Tarasenko + + 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. +*/ + +#ifndef user_h +#define user_h + +#include "socket.h" + + +/////////////////////////////////////////////////////////////////////////////// + +class ICQUser +{ +public: + unsigned int uin; + MCONTACT hContact; + TCPSocket socket; + unsigned short statusVal; + + ICQUser(); + void setStatus(unsigned short newStatus); + void setInfo(char *name, unsigned int data); + void setInfo(char *name, unsigned short data); + void setInfo(char *name, unsigned char data); + void setInfo(char *name, char *data); +}; + +/////////////////////////////////////////////////////////////////////////////// + +extern std::vector icqUsers; + +extern int icqUserInfoInitialise(WPARAM wParam, LPARAM lParam); + +/////////////////////////////////////////////////////////////////////////////// + +#endif \ No newline at end of file diff --git a/protocols/ICQCorp/src/version.h b/protocols/ICQCorp/src/version.h new file mode 100644 index 0000000000..78cd36b9cc --- /dev/null +++ b/protocols/ICQCorp/src/version.h @@ -0,0 +1,14 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 0 +#define __RELEASE_NUM 1 +#define __BUILD_NUM 0 + +#include + +#define __PLUGIN_NAME "ICQ corporate protocol" +#define __FILENAME "ICQCorp.dll" +#define __DESCRIPTION "ICQ corporate protocol support for Miranda NG." +#define __AUTHOR "Miranda NG Team, Eugene Tarasenko" +#define __AUTHOREMAIL "" +#define __AUTHORWEB "http://miranda-ng.org/p/ICQCorp/" +#define __COPYRIGHT "© 2014 Miranda NG Team, 2003-2005 Eugene Tarasenko" -- cgit v1.2.3