From 9070dd01ae46fa9187684b66405a751fb4822702 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 27 Nov 2012 18:41:03 +0000 Subject: adaptation of old good E-mage LAN proto git-svn-id: http://svn.miranda-ng.org/main/trunk@2523 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/EmLanProto/amdproto.vcxproj | 201 +++ protocols/EmLanProto/amdproto.vcxproj.filters | 70 + protocols/EmLanProto/res/amdproto.rc | 143 ++ protocols/EmLanProto/res/icon_off.ico | Bin 0 -> 766 bytes protocols/EmLanProto/res/icon_onl.ico | Bin 0 -> 766 bytes protocols/EmLanProto/src/amdproto.cpp | 394 ++++++ protocols/EmLanProto/src/get_time.cpp | 70 + protocols/EmLanProto/src/get_time.h | 25 + protocols/EmLanProto/src/lan.cpp | 301 ++++ protocols/EmLanProto/src/lan.h | 128 ++ protocols/EmLanProto/src/mlan.cpp | 1807 +++++++++++++++++++++++++ protocols/EmLanProto/src/mlan.h | 200 +++ protocols/EmLanProto/src/packet.cpp | 2 + protocols/EmLanProto/src/packet.h | 14 + protocols/EmLanProto/src/resource.h | 25 + protocols/EmLanProto/src/stdafx.cpp | 8 + protocols/EmLanProto/src/stdafx.h | 80 ++ 17 files changed, 3468 insertions(+) create mode 100644 protocols/EmLanProto/amdproto.vcxproj create mode 100644 protocols/EmLanProto/amdproto.vcxproj.filters create mode 100644 protocols/EmLanProto/res/amdproto.rc create mode 100644 protocols/EmLanProto/res/icon_off.ico create mode 100644 protocols/EmLanProto/res/icon_onl.ico create mode 100644 protocols/EmLanProto/src/amdproto.cpp create mode 100644 protocols/EmLanProto/src/get_time.cpp create mode 100644 protocols/EmLanProto/src/get_time.h create mode 100644 protocols/EmLanProto/src/lan.cpp create mode 100644 protocols/EmLanProto/src/lan.h create mode 100644 protocols/EmLanProto/src/mlan.cpp create mode 100644 protocols/EmLanProto/src/mlan.h create mode 100644 protocols/EmLanProto/src/packet.cpp create mode 100644 protocols/EmLanProto/src/packet.h create mode 100644 protocols/EmLanProto/src/resource.h create mode 100644 protocols/EmLanProto/src/stdafx.cpp create mode 100644 protocols/EmLanProto/src/stdafx.h (limited to 'protocols') diff --git a/protocols/EmLanProto/amdproto.vcxproj b/protocols/EmLanProto/amdproto.vcxproj new file mode 100644 index 0000000000..331d399c02 --- /dev/null +++ b/protocols/EmLanProto/amdproto.vcxproj @@ -0,0 +1,201 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + EmLanProto + {2115FEBC-1EC4-4F95-A058-A523ED5295A4} + Win32Proj + + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + true + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)\$(Configuration)\Plugins\ + $(SolutionDir)\$(Configuration)64\Plugins\ + $(SolutionDir)\$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)\$(Configuration)64\Obj\$(ProjectName)\ + true + true + $(SolutionDir)\$(Configuration)\Plugins\ + $(SolutionDir)\$(Configuration)64\Plugins\ + $(SolutionDir)\$(Configuration)\Obj\$(ProjectName)\ + $(SolutionDir)\$(Configuration)64\Obj\$(ProjectName)\ + false + false + + + + Disabled + ..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;AMDPROTO_EXPORTS;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + EditAndContinue + + + Ws2_32.lib;%(AdditionalDependencies) + NotSet + true + $(OutDir)amdproto.pdb + Windows + 0x22000000 + $(OutDir)amdproto.lib + MachineX86 + $(ProfileDir)..\..\bin10\lib + + + + + Disabled + ..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories) + WIN64;_DEBUG;_WINDOWS;_USRDLL;AMDPROTO_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Use + Level3 + ProgramDatabase + + + Ws2_32.lib;%(AdditionalDependencies) + NotSet + true + $(OutDir)amdproto.pdb + Windows + 0x22000000 + $(OutDir)amdproto.lib + $(ProfileDir)..\..\bin10\lib + + + + + Full + OnlyExplicitInline + ..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;AMDPROTO_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Use + Level3 + Size + + + Ws2_32.lib;%(AdditionalDependencies) + false + Windows + true + true + 0x22000000 + $(OutDir)amdproto.lib + MachineX86 + $(ProfileDir)..\..\bin10\lib + true + + + + + Full + OnlyExplicitInline + ..\..\include;..\..\plugins\ExternalAPI;%(AdditionalIncludeDirectories) + WIN64;NDEBUG;_WINDOWS;_USRDLL;AMDPROTO_EXPORTS;%(PreprocessorDefinitions) + true + MultiThreadedDLL + true + Use + Level3 + Size + + + Ws2_32.lib;%(AdditionalDependencies) + false + true + Windows + true + true + 0x22000000 + $(OutDir)amdproto.lib + $(ProfileDir)..\..\bin10\lib + + + + + + + + + Create + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/protocols/EmLanProto/amdproto.vcxproj.filters b/protocols/EmLanProto/amdproto.vcxproj.filters new file mode 100644 index 0000000000..92fdc52433 --- /dev/null +++ b/protocols/EmLanProto/amdproto.vcxproj.filters @@ -0,0 +1,70 @@ + + + + + {aa1fb7ce-7e83-46e8-b50b-cc87043ddfe8} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c7da55a0-28ce-4c6f-acbe-8e2cba06f96d} + h;hpp;hxx;hm;inl;inc + + + {ee329731-83da-4e3e-abb0-188efa6b23b2} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Resource Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/protocols/EmLanProto/res/amdproto.rc b/protocols/EmLanProto/res/amdproto.rc new file mode 100644 index 0000000000..4795110dd0 --- /dev/null +++ b/protocols/EmLanProto/res/amdproto.rc @@ -0,0 +1,143 @@ +// 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 resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON_ONLINE ICON "icon_onl.ico" +IDI_ICON_OFFLINE ICON "icon_off.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_DIALOG1 DIALOGEX 0, 0, 327, 191 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "EmLan protocol - donate author please" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,277,177,50,14 + EDITTEXT IDC_EDIT1,0,0,327,176,ES_MULTILINE | ES_READONLY | + WS_VSCROLL + LTEXT "This window is shown only once",IDC_STATIC,2,179,274,11 +END + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#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 + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_EMP_FORM_OPT DIALOGEX 0, 0, 200, 63 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LISTBOX IDC_LIST_IP,5,23,94,34,LBS_USETABSTOPS | + LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP + CTEXT "Select your IP address",IDC_STATIC,7,12,92,8 + GROUPBOX "LAN Settings",IDC_STATIC,2,2,196,58 + CONTROL "Use computer name",IDC_RADIO_USECOMPNAME,"Button", + BS_AUTORADIOBUTTON,101,24,79,10 + CONTROL "Your name",IDC_RADIO_USEOWN,"Button",BS_AUTORADIOBUTTON, + 101,34,50,10 + EDITTEXT IDC_EDIT_NAME,101,44,93,12,ES_AUTOHSCROLL + CTEXT "Select your name",IDC_STATIC,99,13,92,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_EMP_FORM_OPT, DIALOG + BEGIN + LEFTMARGIN, 2 + RIGHTMARGIN, 198 + TOPMARGIN, 2 + BOTTOMMARGIN, 61 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/protocols/EmLanProto/res/icon_off.ico b/protocols/EmLanProto/res/icon_off.ico new file mode 100644 index 0000000000..ead47f556f Binary files /dev/null and b/protocols/EmLanProto/res/icon_off.ico differ diff --git a/protocols/EmLanProto/res/icon_onl.ico b/protocols/EmLanProto/res/icon_onl.ico new file mode 100644 index 0000000000..f35ab26753 Binary files /dev/null and b/protocols/EmLanProto/res/icon_onl.ico differ diff --git a/protocols/EmLanProto/src/amdproto.cpp b/protocols/EmLanProto/src/amdproto.cpp new file mode 100644 index 0000000000..20f20a954e --- /dev/null +++ b/protocols/EmLanProto/src/amdproto.cpp @@ -0,0 +1,394 @@ +////////////////////////////////////////////////////////////////////////// +// AMD local protocol main file + +#include "stdafx.h" +#include "mlan.h" +#include "resource.h" + +////////////////////////////////////////////////////////////////////////// + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "E-mage LAN Protocol", + VER, + "Communicating over LAN using UDP protocol", + "kva", + "kva@fromru.com", + "Viktor Kuzmin of e-mage", + "", + 0 +}; + +HINSTANCE g_hInstance = NULL; +CMLan* g_lan = NULL; +HANDLE g_heOptions = NULL; + +int hLangpack; +bool g_InitOptions = false; + +#ifdef VERBOSE +std::fstream emlanLog("EmLanLog.txt", std::ios::out|std::ios::app); +#endif + +extern "C" __declspec(dllexport) PLUGININFOEX* __cdecl MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +////////////////////////////////////////////////////////////////////////// +// Interface information + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +////////////////////////////////////////////////////////////////////////// + +BOOL APIENTRY DllMain( HINSTANCE hInstDLL,DWORD reason,LPVOID ) +{ + g_hInstance = hInstDLL; + if (reason == DLL_PROCESS_ATTACH) { + EMLOG("EmLan Started"); + DisableThreadLibraryCalls( hInstDLL); + } + else if (reason == DLL_PROCESS_DETACH) { + EMLOG("EmLan Stopped"); + } + + return TRUE; +} + +////////////////////////////////////////////////////////////////////////// + +static INT_PTR __cdecl EMPGetCaps(WPARAM wParam,LPARAM ) +{ + int res = 0; + switch(wParam) { + case PFLAGNUM_1: + res = PF1_IM|PF1_BASICSEARCH|PF1_ADDSEARCHRES|PF1_PEER2PEER|PF1_INDIVSTATUS| + PF1_URL|PF1_MODEMSG|PF1_FILE|PF1_CANRENAMEFILE|PF1_FILERESUME; + break; + case PFLAGNUM_2: + res = PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT; + break; + case PFLAGNUM_3: + res = PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND | PF2_FREECHAT; + break; + case PFLAG_UNIQUEIDTEXT: + res = (INT_PTR)Translate("User name or '*'"); + break; + } + return res; +} + +static INT_PTR __cdecl EMPGetName(WPARAM wParam,LPARAM lParam) +{ + lstrcpyn((char*)lParam, "EmLan", wParam); + return 0; +} + +static INT_PTR __cdecl EMPLoadIcon(WPARAM wParam, LPARAM) +{ + UINT id = IDI_ICON_ONLINE; + if ((wParam & 0xFFFF) == PLI_OFFLINE) + id = IDI_ICON_OFFLINE; + HICON res = LoadIcon(g_hInstance, MAKEINTRESOURCE(id)); + return (INT_PTR)res; +} + +static INT_PTR __cdecl EMPGetStatus(WPARAM ,LPARAM ) +{ + return g_lan->GetMirandaStatus(); +} + +INT_PTR __cdecl EMPSetStatus(WPARAM new_status, LPARAM lParam) +{ + g_lan->SetMirandaStatus(new_status); + return 0; +} + +static INT_PTR __cdecl EMPSendMessage(WPARAM ,LPARAM lParam) +{ + return g_lan->SendMessageUrl((CCSDATA*)lParam, false); +} + +static INT_PTR __cdecl EMPSendUrl(WPARAM ,LPARAM lParam) +{ + return g_lan->SendMessageUrl((CCSDATA*)lParam, true); +} + +static INT_PTR __cdecl EMPRecvMessageUrl(WPARAM ,LPARAM lParam) +{ + g_lan->RecvMessageUrl((CCSDATA*)lParam); + return 0; +} + +static INT_PTR __cdecl EMPAddToList(WPARAM flags,LPARAM lParam) +{ + return g_lan->AddToContactList((u_int)flags, (EMPSEARCHRESULT*)lParam); +} + +static INT_PTR __cdecl EMPBasicSearch(WPARAM, LPARAM lParam) +{ + return g_lan->Search((const char*)lParam); +} + +static INT_PTR __cdecl EMPGetAwayMsg(WPARAM, LPARAM lParam) +{ + return g_lan->GetAwayMsg((CCSDATA*)lParam); +} + +static INT_PTR __cdecl EMPRecvAwayMessage(WPARAM, LPARAM lParam) +{ + return g_lan->RecvAwayMsg((CCSDATA*)lParam); +} + +static INT_PTR __cdecl EMPSetAwayMsg(WPARAM wParam, LPARAM lParam) +{ + return g_lan->SetAwayMsg((u_int)wParam, (char*)lParam); +} + +static INT_PTR __cdecl EMPFileResume(WPARAM wParam, LPARAM lParam) +{ + return g_lan->FileResume((int)wParam, (PROTOFILERESUME*)lParam); +} + +static INT_PTR __cdecl EMPSendFileAllow(WPARAM wParam, LPARAM lParam) +{ + return g_lan->FileAllow((CCSDATA*)lParam); +} + +static INT_PTR __cdecl EMPSendFileDeny(WPARAM wParam, LPARAM lParam) +{ + return g_lan->FileDeny((CCSDATA*)lParam); +} + +static INT_PTR __cdecl EMPSendFileCancel(WPARAM wParam, LPARAM lParam) +{ + return g_lan->FileCancel((CCSDATA*)lParam); +} + +static INT_PTR __cdecl EMPSendFile(WPARAM wParam, LPARAM lParam) +{ + return g_lan->SendFile((CCSDATA*)lParam); +} + +static INT_PTR __cdecl EMPRecvFile(WPARAM wParam, LPARAM lParam) +{ + g_lan->RecvFile((CCSDATA*)lParam); + return 0; +} + +////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK EMPDlgProcMainOpts(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { + case WM_INITDIALOG: + g_InitOptions = true; + TranslateDialogDefault(hwndDlg); + { + int count = g_lan->GetHostAddrCount(); + in_addr caddr = g_lan->GetCurHostAddress(); + int cind = 0; + for (int i=0; iGetHostAddress(i); + char* ipStr = inet_ntoa(addr); + if (addr.S_un.S_addr == caddr.S_un.S_addr) + cind = i; + SendDlgItemMessage(hwndDlg, IDC_LIST_IP, LB_ADDSTRING, 0, (LPARAM)ipStr); + } + SendDlgItemMessage(hwndDlg, IDC_LIST_IP, LB_SETCURSEL, cind, 0); + SetDlgItemText(hwndDlg, IDC_EDIT_NAME, g_lan->GetName()); + if (g_lan->GetUseHostName()) + { + SendDlgItemMessage(hwndDlg, IDC_RADIO_USECOMPNAME, BM_SETCHECK, BST_CHECKED, 0); + SendDlgItemMessage(hwndDlg, IDC_RADIO_USEOWN, BM_SETCHECK, BST_UNCHECKED, 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_NAME), FALSE); + } + else + { + SendDlgItemMessage(hwndDlg, IDC_RADIO_USECOMPNAME, BM_SETCHECK, BST_UNCHECKED, 0); + SendDlgItemMessage(hwndDlg, IDC_RADIO_USEOWN, BM_SETCHECK, BST_CHECKED, 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_NAME), TRUE); + } + } + g_InitOptions = false; + return TRUE; + + case WM_COMMAND: + { + if (g_InitOptions) + break; + + bool changed = false; + switch(LOWORD(wParam)) { + case IDC_RADIO_USECOMPNAME: + g_lan->SetUseHostName(true); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_NAME), FALSE); + changed = true; + break; + case IDC_RADIO_USEOWN: + g_lan->SetUseHostName(false); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_NAME), TRUE); + changed = true; + break; + case IDC_LIST_IP: + { + u_long addr = g_lan->GetHostAddress(SendDlgItemMessage(hwndDlg, IDC_LIST_IP, LB_GETCURSEL, 0, 0)).S_un.S_addr; + if (addr != g_lan->GetCurHostAddress().S_un.S_addr) + { + g_lan->SetRequiredIp(addr); + changed = true; + } + } + break; + case IDC_EDIT_NAME: + if (HIWORD(wParam)==EN_CHANGE) + changed = true; + break; + } + if (changed) + SendMessage(GetParent(hwndDlg), PSM_CHANGED,0,0); + } + break; + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) + { + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_RESET: + g_lan->LoadSettings(); + return TRUE; + case PSN_APPLY: + { + int status = g_lan->GetMirandaStatus(); + g_lan->SetMirandaStatus(ID_STATUS_OFFLINE); + + GetDlgItemText(hwndDlg, IDC_EDIT_NAME, g_lan->GetName(), MAX_HOSTNAME_LEN); + + g_lan->SaveSettings(); + g_lan->LoadSettings(); + + g_lan->SetMirandaStatus(status); + } + return TRUE; + } + } + break; + } + return FALSE; +} + +int __cdecl EMPCreateOptionsDlg(WPARAM wParam,LPARAM) +{ + OPTIONSDIALOGPAGE odp = { sizeof(odp) }; + odp.position = 100000000; + odp.hInstance = g_hInstance; + odp.pszTemplate = MAKEINTRESOURCE(IDD_EMP_FORM_OPT); + odp.pszTitle = LPGEN("E-mage LAN protocol"); + odp.pszGroup = LPGEN("Network"); + odp.groupPosition = 910000000; + odp.flags = ODPF_BOLDGROUPS; + odp.pfnDlgProc = EMPDlgProcMainOpts; + Options_AddPage(wParam, &odp); + + return 0; +} + +////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK EMPDlgProcMessage(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) { + case WM_INITDIALOG: + { + HWND hwndOwner; + RECT rc, rcDlg, rcOwner; + if ((hwndOwner = GetParent(hwndDlg)) == NULL) + { + hwndOwner = GetDesktopWindow(); + } + + GetWindowRect(hwndOwner, &rcOwner); + GetWindowRect(hwndDlg, &rcDlg); + CopyRect(&rc, &rcOwner); + + OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top); + OffsetRect(&rc, -rc.left, -rc.top); + OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom); + + SetWindowPos(hwndDlg, + HWND_TOP, + rcOwner.left + (rc.right / 2), + rcOwner.top + (rc.bottom / 2), + 0, 0, // ignores size arguments + SWP_NOSIZE); + + if (GetDlgCtrlID((HWND) wParam) != IDOK) { + SetFocus(GetDlgItem(hwndDlg, IDOK)); + return FALSE; + } + return TRUE; + } + break; + + case WM_CLOSE: + EndDialog(hwndDlg, 0); + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDOK: + EndDialog(hwndDlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +extern "C" int __declspec(dllexport) __cdecl Load() +{ + mir_getLP(&pluginInfo); + + PROTOCOLDESCRIPTOR pd = { PROTOCOLDESCRIPTOR_V3_SIZE }; + pd.szName = PROTONAME; + pd.type = PROTOTYPE_PROTOCOL; + CallService(MS_PROTO_REGISTERMODULE, 0, (LPARAM)&pd); + + CreateServiceFunction(PROTONAME PS_GETCAPS, EMPGetCaps); + CreateServiceFunction(PROTONAME PS_GETNAME, EMPGetName); + CreateServiceFunction(PROTONAME PS_LOADICON, EMPLoadIcon); + CreateServiceFunction(PROTONAME PS_SETSTATUS, EMPSetStatus); + CreateServiceFunction(PROTONAME PS_GETSTATUS, EMPGetStatus); + CreateServiceFunction(PROTONAME PS_BASICSEARCH, EMPBasicSearch); + CreateServiceFunction(PROTONAME PS_ADDTOLIST, EMPAddToList); + CreateServiceFunction(PROTONAME PSS_MESSAGE, EMPSendMessage); + CreateServiceFunction(PROTONAME PSS_URL, EMPSendUrl); + CreateServiceFunction(PROTONAME PSR_MESSAGE, EMPRecvMessageUrl); + CreateServiceFunction(PROTONAME PSR_URL, EMPRecvMessageUrl); + CreateServiceFunction(PROTONAME PSS_GETAWAYMSG, EMPGetAwayMsg); + CreateServiceFunction(PROTONAME PS_SETAWAYMSG, EMPSetAwayMsg); + CreateServiceFunction(PROTONAME PSR_AWAYMSG, EMPRecvAwayMessage); + + CreateServiceFunction(PROTONAME PS_FILERESUME, EMPFileResume); + CreateServiceFunction(PROTONAME PSS_FILEALLOW, EMPSendFileAllow); + CreateServiceFunction(PROTONAME PSS_FILEDENY, EMPSendFileDeny); + CreateServiceFunction(PROTONAME PSS_FILECANCEL, EMPSendFileCancel); + CreateServiceFunction(PROTONAME PSS_FILE, EMPSendFile); + CreateServiceFunction(PROTONAME PSR_FILE, EMPRecvFile); + + g_heOptions = HookEvent(ME_OPT_INITIALISE,EMPCreateOptionsDlg); + + g_lan = new CMLan(); + return 0; +} + +extern "C" int __declspec(dllexport) __cdecl Unload() +{ + UnhookEvent(g_heOptions); + + delete g_lan; + return 0; +} diff --git a/protocols/EmLanProto/src/get_time.cpp b/protocols/EmLanProto/src/get_time.cpp new file mode 100644 index 0000000000..5f918a8037 --- /dev/null +++ b/protocols/EmLanProto/src/get_time.cpp @@ -0,0 +1,70 @@ +/* +Miranda ICQ: the free icq client for MS Windows +Copyright (C) 2000-2 Richard Hughes, Roland Rabien & Tristan Van de Vreede + +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 "stdafx.h" +#include +#include "get_time.h" + + +static int daysInMonth[]={31,28,31,30,31,30,31,31,30,31,30,31}; +static int IsLeapYear(int year) +{ + if (year&3) return 0; + if (year%100) return 1; + if (year%400) return 0; + return 1; +} + +static DWORD YMDHMSToTime(int year,int month,int day,int hour,int minute,int second) +{ + DWORD ret=0; + int i; + + for(i=1970;i2 && IsLeapYear(year)) ret++; + ret+=day-1; + ret*=24*3600; + return ret+3600*hour+60*minute+second; +} + + +static DWORD TimestampLocalToGMT(DWORD from) +{ + FILETIME ft1,ft2; + LARGE_INTEGER liFiletime; + + //this huge number is the difference between 1970 and 1601 in seconds + //liFiletime.QuadPart=(11644473600i64+(__int64)from)*10000000; + __int64 t = 11644473600; + liFiletime.QuadPart=(t+(__int64)from)*10000000; + ft1.dwHighDateTime=liFiletime.HighPart; + ft1.dwLowDateTime=liFiletime.LowPart; + LocalFileTimeToFileTime(&ft1,&ft2); + liFiletime.HighPart=ft2.dwHighDateTime; + liFiletime.LowPart=ft2.dwLowDateTime; + return (DWORD)(liFiletime.QuadPart/10000000-t); +} + +DWORD get_time() +{ + SYSTEMTIME stime; + GetSystemTime(&stime); + return YMDHMSToTime(stime.wYear,stime.wMonth,stime.wDay,stime.wHour,stime.wMinute,stime.wSecond); +} \ No newline at end of file diff --git a/protocols/EmLanProto/src/get_time.h b/protocols/EmLanProto/src/get_time.h new file mode 100644 index 0000000000..9f5676c5d3 --- /dev/null +++ b/protocols/EmLanProto/src/get_time.h @@ -0,0 +1,25 @@ +/* +Miranda ICQ: the free icq client for MS Windows +Copyright (C) 2000-2 Richard Hughes, Roland Rabien & Tristan Van de Vreede + +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 __GET_TIME_H__ +#define __GET_TIME_H__ + +DWORD get_time(); + +#endif //__GET_TIME_H__ diff --git a/protocols/EmLanProto/src/lan.cpp b/protocols/EmLanProto/src/lan.cpp new file mode 100644 index 0000000000..f1b27d3a99 --- /dev/null +++ b/protocols/EmLanProto/src/lan.cpp @@ -0,0 +1,301 @@ +////////////////////////////////////////////////////////////////////////// +// Lan protocol + +#include "stdafx.h" + +#include "lan.h" + +CLan::CLan() +{ + m_income = INVALID_SOCKET; + m_filesoc = INVALID_SOCKET; + m_status = LS_OK; + m_mode = LM_OFF; + m_hListenThread = NULL; + m_hAcceptTCPThread = NULL; + InitializeCriticalSection(&m_csAcceptTCPThread); + Startup(); +} + +CLan::~CLan() +{ + Shutdown(); + DeleteCriticalSection(&m_csAcceptTCPThread); +} + +void CLan::Startup() +{ + WSADATA wsa; + if (WSAStartup(MAKEWORD(2,2), &wsa)==0) + { + m_status = LS_OK; + m_mode = LM_ON; + + char hostname[256]; + if (gethostname(hostname, 256)==0) + { + hostent* host = gethostbyname(hostname); + char** pAddr = host->h_addr_list; + m_hostAddrCount = 0; + while (*pAddr && m_hostAddrCountListen(); + return 0; +} + +void CLan::Listen() +{ + if (m_mode==LM_LISTEN) + { + char buf[65536]; + while(1) + { + sockaddr_in addr; + int addrLen = sizeof(addr); + Sleep(20); + int recLen = recvfrom(m_income, buf, 65536, 0, (sockaddr*)&addr, &addrLen); + if (recLen!=SOCKET_ERROR) + OnRecvPacket((u_char*)buf, recLen, addr.sin_addr); + } + } +} + +void CLan::SendPacketBroadcast(const u_char* mes, int len) +{ + in_addr addr; + addr.S_un.S_addr = INADDR_BROADCAST; + SendPacket(addr, mes, len); +} + +void CLan::SendPacket(in_addr addr, const u_char* mes, int len) +{ + if (m_mode==LM_LISTEN) + { + sockaddr_in addrTo; + addrTo.sin_addr = addr; + addrTo.sin_family = AF_INET; + addrTo.sin_port = PORT_NUMBER; + int res = sendto(m_income, (const char*)mes, len, 0, (sockaddr*)&addrTo, sizeof(addrTo)); + } +} + +////////////////////////////////////////////////////////////////////////// + +DWORD WINAPI CLan::AcceptTCPProc(LPVOID lpParameter) +{ + CLan* lan = (CLan*)lpParameter; + lan->AcceptTCP(); + return 0; +} + +void CLan::AcceptTCP() +{ + while (1) + { + SOCKET in_socket; + sockaddr_in addrFrom; + int addrLen = sizeof(addrFrom); + in_socket = accept(m_filesoc, (sockaddr*)&addrFrom, &addrLen); + EnterCriticalSection(&m_csAcceptTCPThread); + if (in_socket != INVALID_SOCKET) + { + TTCPConnect* tcp_conn = new TTCPConnect; + tcp_conn->m_addr = addrFrom.sin_addr.S_un.S_addr; + tcp_conn->m_lan = this; + tcp_conn->m_socket = in_socket; + DWORD threadId; + CreateThread(NULL, 0, OnInTCPConnectionProc, (LPVOID)tcp_conn, 0, &threadId); + } + LeaveCriticalSection(&m_csAcceptTCPThread); + Sleep(100); + } +} + +DWORD WINAPI CLan::OnInTCPConnectionProc(LPVOID lpParameter) +{ + TTCPConnect* tcp_conn = (TTCPConnect*)lpParameter; + tcp_conn->m_lan->OnInTCPConnection(tcp_conn->m_addr, tcp_conn->m_socket); + shutdown(tcp_conn->m_socket, SD_BOTH); + closesocket(tcp_conn->m_socket); + delete tcp_conn; + return 0; +} + +SOCKET CLan::CreateTCPConnection(u_long addr, LPVOID lpParameter) +{ + SOCKET out_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (out_socket==INVALID_SOCKET) + return INVALID_SOCKET; + + sockaddr_in addrTo; + addrTo.sin_addr.S_un.S_addr = addr; + addrTo.sin_family = AF_INET; + addrTo.sin_port = PORT_NUMBER; + if (connect(out_socket, (sockaddr*)&addrTo, sizeof(addrTo))!=0) + { + closesocket(out_socket); + out_socket = INVALID_SOCKET; + } + + //OnOutTCPConnectionProc is called anyway + TTCPConnect* tcp_conn = new TTCPConnect; + tcp_conn->m_socket = out_socket; + tcp_conn->m_lan = this; + tcp_conn->m_addr = addr; + tcp_conn->m_lpParameter = lpParameter; + + DWORD threadId; + CreateThread(NULL, 0, OnOutTCPConnectionProc, (LPVOID)tcp_conn, 0, &threadId); + + return out_socket; +} + +DWORD WINAPI CLan::OnOutTCPConnectionProc(LPVOID lpParameter) +{ + TTCPConnect* tcp_conn = (TTCPConnect*)lpParameter; + tcp_conn->m_lan->OnOutTCPConnection(tcp_conn->m_addr, tcp_conn->m_socket, tcp_conn->m_lpParameter); + shutdown(tcp_conn->m_socket, SD_BOTH); + closesocket(tcp_conn->m_socket); + delete tcp_conn; + return 0; +} diff --git a/protocols/EmLanProto/src/lan.h b/protocols/EmLanProto/src/lan.h new file mode 100644 index 0000000000..e1a897cc20 --- /dev/null +++ b/protocols/EmLanProto/src/lan.h @@ -0,0 +1,128 @@ +////////////////////////////////////////////////////////////////////////// +// Lan functions + +#ifndef __lan_h__ +#define __lan_h__ + +#define MAKE_PORT(x) (HIBYTE(x)|(LOBYTE(x)<<8)) + +#define MAX_INTERNAL_IP 32 +#define PORT_NUMBER MAKE_PORT(34074) + +#include "winsock2.h" + +//! Class for operating with LAN +class CLan +{ +public: + //! constructor + CLan(); + //! destructor + ~CLan(); + + //! Helper function - returns status + int GetStatus() { return m_status; } + //! Helper function - returns mode + int GetMode() { return m_mode; } + //! Getting host addresses count + int GetHostAddrCount() { return m_hostAddrCount; } + //! Getting host addresses + in_addr GetHostAddress(int ind) { return m_hostAddr[ind]; } + //! Get current host address + in_addr GetCurHostAddress() { return m_curAddr; } + +protected: + //! Lan status + enum enumStatus + { + LS_OK, //!< no problems + LS_WRONG_WINSOCK, //!< not found winsock of propper version + LS_CANT_CREATE_SOCKET, //!< can not create income socket + LS_CANT_GET_HOSTADDR, //!< can not find host address + LS_CANT_TURN_ON_BROADCAST, //!< can not allow broadcast messages for socket + LS_CANT_BIND_SOCKET, //!< can not bind socket to the address + LS_CANT_START_LISTEN, //!< can not start listen on TCP socket + LS_CANT_CREATE_THREADS, //!< can not create threads for listen and accept + }; + + //! Lan mode + enum enumMode + { + LM_OFF, //!< Winsock is turned off + LM_ON, //!< Winsock is on + LM_LISTEN, //!< Listening for incoming messages + }; + + //! Starts winsock + void Startup(); + //! Stops winsock + void Shutdown(); + //! Listen + void StartListen(); + //! Stop Listen + void StopListen(); + + //! Set current host address + void SetCurHostAddress(in_addr addr); + + //! Send packet + void SendPacket(in_addr addr, const u_char* mes, int len); + //! Send broadcast packet + void SendPacketBroadcast(const u_char* mes, int len); + + //! Event - called when packet is received + virtual void OnRecvPacket(u_char* mes, int len, in_addr from) { }; + //! Event - called when new incoming tcp connection is created (new thread is created) + virtual void OnInTCPConnection(u_long addr, SOCKET m_socket) { }; + //! Event - called when new outgoing tcp connection is created )new thread is created) + virtual void OnOutTCPConnection(u_long addr, SOCKET m_socket, LPVOID lpParameter) {}; + //! Creates new outgoing TCP connection + SOCKET CreateTCPConnection(u_long addr, LPVOID lpParameter); + +private: + //! Launches Listen procedure when in new thread + static DWORD WINAPI ListenProc(LPVOID lpParameter); + //! Listnes for incoming messages + void Listen(); + //! Listen thread handle + HANDLE m_hListenThread; + //! Structure passed to new TCP connection thread + struct TTCPConnect + { + CLan* m_lan; + u_long m_addr; + SOCKET m_socket; + LPVOID m_lpParameter; + }; + //! Launches accept procedure for TCP connections in new thread + static DWORD WINAPI AcceptTCPProc(LPVOID lpParameter); + //! Accepts TCP connections + void AcceptTCP(); + //! Accept TCP thread handle + HANDLE m_hAcceptTCPThread; + //! Semaphore for killing accept thread + CRITICAL_SECTION m_csAcceptTCPThread; + + //! Called when new income TCP connection is created + static DWORD WINAPI OnInTCPConnectionProc(LPVOID lpParameter); + //! Called when new ougoing TCP connectio is created + static DWORD WINAPI OnOutTCPConnectionProc(LPVOID lpParameter); + + //! Stores retreived host addresses + in_addr m_hostAddr[MAX_INTERNAL_IP]; + //! Current address count + int m_hostAddrCount; + + //! Stores current host address + in_addr m_curAddr; + //! Socket for income messages + SOCKET m_income; + //! Socket for income files + SOCKET m_filesoc; + //! Current status + int m_status; + //! Current mode + int m_mode; +}; + +#endif //__lan_h__ diff --git a/protocols/EmLanProto/src/mlan.cpp b/protocols/EmLanProto/src/mlan.cpp new file mode 100644 index 0000000000..53370e2526 --- /dev/null +++ b/protocols/EmLanProto/src/mlan.cpp @@ -0,0 +1,1807 @@ +////////////////////////////////////////////////////////////////////////// +// Miranda lan functions + +#include "stdafx.h" +#include "mlan.h" +#include "get_time.h" + +#define MCODE_SND_STATUS 1 +#define MCODE_SND_NAME 2 +#define MCODE_REQ_STATUS 3 +#define MCODE_SND_MESSAGE 4 +#define MCODE_ACK_MESSAGE 5 +#define MCODE_SND_VERSION 6 +#define MCODE_REQ_AWAYMSG 7 +#define MCODE_SND_AWAYMSG 8 +#define MCODE_SND_URL 9 +#define MCODE_ACK_URL 10 + +#define FCODE_SND_ACCEPT 1 +#define FCODE_SND_FILEREQ 2 +#define FCODE_SND_FILESKIP 3 +#define FCODE_SND_NEXTFILE 4 +#define FCODE_SND_FILEDATA 5 + +enum enuLEXT +{ + LEXT_SENDMESSAGE, + LEXT_SEARCH, + LEXT_GETAWAYMSG, + LEXT_SENDURL, +}; + +CMLan::CMLan() +{ + m_RequiredIp = 0; + m_UseHostName = true; + + m_mirStatus = ID_STATUS_OFFLINE; + m_pRootContact = 0; + + m_pRootContact = NULL; + m_hCheckThread = NULL; + + m_handleId = 1; + + m_amesAway = NULL; + m_amesNa = NULL; + m_amesOccupied = NULL; + m_amesDnd = NULL; + m_amesFfc = NULL; + + m_pFileConnectionList = NULL; + + LoadSettings(); + + InitializeCriticalSection(&m_csAccessClass); + InitializeCriticalSection(&m_csReceiveThreadLock); + InitializeCriticalSection(&m_csAccessAwayMes); + InitializeCriticalSection(&m_csFileConnectionList); + + SetAllOffline(); + + //m_hookIcqMsgReq = CreateHookableEvent(ME_ICQ_STATUSMSGREQ); +} + +CMLan::~CMLan() +{ + m_mirStatus = ID_STATUS_OFFLINE; + StopChecking(); + DeleteCache(); + StopListen(); + Shutdown(); + DeleteCriticalSection(&m_csFileConnectionList); + DeleteCriticalSection(&m_csAccessAwayMes); + DeleteCriticalSection(&m_csReceiveThreadLock); + DeleteCriticalSection(&m_csAccessClass); + + delete[] m_amesAway; + delete[] m_amesNa; + delete[] m_amesOccupied; + delete[] m_amesDnd; + delete[] m_amesFfc; +} + +void CMLan::DeleteCache() +{ + TContact* pCont = m_pRootContact; + m_pRootContact = NULL; + while (pCont) + { + delete[] pCont->m_nick; + TContact* pPrev = pCont->m_prev; + delete pCont; + pCont = pPrev; + } +} + +int CMLan::GetMirandaStatus() +{ + if (GetMode()!=LM_LISTEN) + return ID_STATUS_OFFLINE; + return m_mirStatus; +} + +void CMLan::SetMirandaStatus(u_int status) +{ + if (status==ID_STATUS_INVISIBLE) + { + ProtoBroadcastAck(PROTONAME,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS, (HANDLE)m_mirStatus, m_mirStatus); + return; + } + u_int old_status = m_mirStatus; + m_mirStatus = status; + if (old_status==ID_STATUS_OFFLINE && m_mirStatus!=ID_STATUS_OFFLINE) + { + StartChecking(); + } + else if (old_status!=ID_STATUS_OFFLINE && m_mirStatus==ID_STATUS_OFFLINE) + { + StopChecking(); + } + else if (m_mirStatus!=ID_STATUS_OFFLINE && m_mirStatus!=old_status) + { + RequestStatus(false); + } + + ProtoBroadcastAck(PROTONAME,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS,(HANDLE)old_status,m_mirStatus); +} + +void CMLan::SetAllOffline() +{ + HANDLE hContact =(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + while(hContact!=NULL) + { + char* svc = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0); + if (svc!=NULL && lstrcmp(PROTONAME,svc)==0) + { + DBWriteContactSettingWord(hContact,PROTONAME,"Status",ID_STATUS_OFFLINE); + //Delet all temp contact settings + DBDeleteContactSetting(hContact, PROTONAME, "IP"); + //DBDeleteContactSetting(hContact, PROTONAME, "UID"); + } + hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0); + } + DeleteCache(); +} + +void CMLan::StartChecking() +{ + if (m_hCheckThread) + return; + + TContact* cont = m_pRootContact; + while (cont) + { + cont->m_time = MLAN_CHECK + MLAN_TIMEOUT; + cont = cont->m_prev; + } + + DWORD threadId; + m_hCheckThread = CreateThread(NULL, 0, CheckProc, (LPVOID)this, 0, &threadId); + StartListen(); + RequestStatus(true); +} + +void CMLan::StopChecking() +{ + EnterCriticalSection(&m_csAccessClass); + if (m_hCheckThread) + { + TerminateThread(m_hCheckThread, 0); + m_hCheckThread = NULL; + } + LeaveCriticalSection(&m_csAccessClass); + EnterCriticalSection(&m_csReceiveThreadLock); + m_mirStatus = ID_STATUS_OFFLINE; + RequestStatus(false); + StopListen(); + LeaveCriticalSection(&m_csReceiveThreadLock); + + TFileConnection* fc = m_pFileConnectionList; + while (fc) + { + fc->Terminate(); + fc = fc->m_pNext; + } + while (m_pFileConnectionList) + Sleep(10); + + SetAllOffline(); +} + +DWORD WINAPI CMLan::CheckProc(LPVOID lpParameter) +{ + CMLan* lan = (CMLan*)lpParameter; + lan->Check(); + return 0; +} + +void CMLan::Check() +{ + while(1) + { + Sleep(MLAN_SLEEP); + EnterCriticalSection(&m_csAccessClass); + TContact* cont = m_pRootContact; + while (cont) + { + if (cont->m_status != ID_STATUS_OFFLINE) + { + if (cont->m_time) + cont->m_time--; + if (cont->m_time==MLAN_TIMEOUT) + RequestStatus(true, cont->m_addr.S_un.S_addr); + if (!cont->m_time) + { + cont->m_status = ID_STATUS_OFFLINE; + HANDLE hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false); + if (hContact) + { + DBWriteContactSettingWord(hContact,PROTONAME,"Status",ID_STATUS_OFFLINE); + } + } + } + cont = cont->m_prev; + } + LeaveCriticalSection(&m_csAccessClass); + } +} + +void CMLan::RequestStatus(bool answer, u_long addr) +{ + TPacket pak; + ZeroMemory(&pak, sizeof(pak)); + pak.flReqStatus = answer; + pak.strName = m_name; + SendPacketExt(pak, addr); +} + +void CMLan::SendPacketExt(TPacket& pak, u_long addr) +{ + int pakLen; + u_char* buf = CreatePacket(pak, &pakLen); + in_addr _addr; + _addr.S_un.S_addr = addr; + SendPacket(_addr, (u_char*)buf, pakLen); + delete[] buf; +} + +HANDLE CMLan::FindContact(in_addr addr, const char* nick, bool add_to_list, bool make_permanent, bool make_visible, u_int status) +{ + HANDLE res=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + while(res!=NULL) + { + char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)res,0); + if (szProto!=NULL && !lstrcmp(PROTONAME,szProto)) + { + u_long caddr = db_get_dw(res, PROTONAME, "ipaddr", -1); + if (caddr==addr.S_un.S_addr) + { + if (make_permanent) + DBDeleteContactSetting(res,"CList","NotOnList"); + if (make_visible) + DBDeleteContactSetting(res,"CList","Hidden"); + return res; + } + } + res=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)res,0); + } + + if (add_to_list) + { + res=(HANDLE)CallService(MS_DB_CONTACT_ADD,0,0); + CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)res,(LPARAM)PROTONAME); + DBWriteContactSettingDword(res,PROTONAME, "ipaddr", addr.S_un.S_addr); + DBWriteContactSettingString(res,PROTONAME, "Nick", nick); + + if (!make_permanent) + DBWriteContactSettingByte(res,"CList","NotOnList",1); + if (!make_visible) + DBWriteContactSettingByte(res,"CList","Hidden",1); + + DBWriteContactSettingWord(res,PROTONAME, "Status", status); + } + else res = NULL; + + return res; +} + +void CMLan::OnRecvPacket(u_char* mes, int len, in_addr from) +{ + EnterCriticalSection(&m_csReceiveThreadLock); + + if (len) + { + TPacket pak; + ParsePacket(pak, mes, len); + + if (pak.idVersion!=0) + { + TContact* cont = m_pRootContact; + while (cont) + { + if (cont->m_addr.S_un.S_addr == from.S_un.S_addr) + break; + cont = cont->m_prev; + } + if (pak.idStatus) + { + EnterCriticalSection(&m_csAccessClass); + if (!cont) + { + if (!pak.strName) + pak.strName = "Unknown"; + cont = new TContact; + cont->m_addr = from; + cont->m_prev = m_pRootContact; + cont->m_status = ID_STATUS_OFFLINE; + int nlen = (int)strlen(pak.strName); + cont->m_nick = new char[nlen+1]; + CopyMemory(cont->m_nick, pak.strName, nlen+1); + m_pRootContact = cont; + } + else + { + if (pak.strName && strcmp(pak.strName, cont->m_nick)!=0) + { + delete[] cont->m_nick; + int nlen = (int)strlen(pak.strName); + cont->m_nick = new char[nlen+1]; + CopyMemory(cont->m_nick, pak.strName, nlen+1); + } + } + cont->m_time = MLAN_CHECK + MLAN_TIMEOUT; + cont->m_ver = pak.idVersion; + u_int old_status = cont->m_status; + cont->m_status = pak.idStatus; + HANDLE hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false); + if (hContact) + { + DBWriteContactSettingWord(hContact,PROTONAME, "Status", cont->m_status); + if (db_get_dw(hContact,PROTONAME, "RemoteVersion", 0)!=cont->m_ver) + DBWriteContactSettingDword(hContact,PROTONAME, "RemoteVersion", cont->m_ver); + if (old_status = ID_STATUS_OFFLINE) + { + u_int rip = cont->m_addr.S_un.S_addr; + int tip = (rip<<24)|((rip&0xff00)<<8)|((rip&0xff0000)>>8)|(rip>>24); + DBWriteContactSettingDword(hContact, PROTONAME, "IP", tip); +// HOSTENT* host = gethostbyaddr((const char*)&rip, sizeof(rip), AF_INET); +// if (host) +// DBWriteContactSettingString(hContact, PROTONAME, "UID", host->h_name); + } + } + LeaveCriticalSection(&m_csAccessClass); + } + if (pak.flReqStatus) + RequestStatus(false, cont->m_addr.S_un.S_addr); + + if (pak.strMessage) + { + if (!cont) + RequestStatus(true, cont->m_addr.S_un.S_addr); + else + { + CCSDATA ccs; + PROTORECVEVENT pre; + + ccs.hContact = FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status); + ccs.szProtoService = pak.flIsUrl?PSR_URL:PSR_MESSAGE; + ccs.wParam = 0; + ccs.lParam =(LPARAM)⪯ + + pre.flags = 0; + pre.timestamp = get_time(); + pre.szMessage = pak.strMessage; + pre.lParam = 0; + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + + TPacket npak; + ZeroMemory(&npak, sizeof(npak)); + npak.idAckMessage = pak.idMessage; + npak.flIsUrl = pak.flIsUrl; + SendPacketExt(npak, from.S_un.S_addr); + } + } + + if (pak.idAckMessage) + { + HANDLE hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false); + if (hContact) + ProtoBroadcastAck(PROTONAME, hContact, pak.flIsUrl?ACKTYPE_URL:ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)pak.idAckMessage, 0); + } + + if (pak.strAwayMessage && cont) + { + CCSDATA ccs; + PROTORECVEVENT pre; + + ccs.hContact = FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status); + ccs.szProtoService = PSR_AWAYMSG; + ccs.wParam = 0; + ccs.lParam = (LPARAM)⪯ + + pre.flags = 0; + pre.timestamp = get_time(); + pre.szMessage = pak.strAwayMessage; + pre.lParam = pak.idAckAwayMessage; + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + } + + if (pak.idReqAwayMessage && cont) + { + HANDLE hContact = FindContact(cont->m_addr, cont->m_nick, true, false, false); + // Removed - it causes that whoisreadingawaymessage plugin was not working +// if (hContact) +// { +// int IcqStatus = 0; +// switch (m_mirStatus) +// { +// case ID_STATUS_AWAY: IcqStatus = ICQ_MSGTYPE_GETAWAYMSG; break; +// case ID_STATUS_NA: IcqStatus = ICQ_MSGTYPE_GETNAMSG; break; +// case ID_STATUS_OCCUPIED: IcqStatus = ICQ_MSGTYPE_GETOCCUMSG; break; +// case ID_STATUS_DND: IcqStatus = ICQ_MSGTYPE_GETDNDMSG; break; +// case ID_STATUS_FREECHAT: IcqStatus = ICQ_MSGTYPE_GETFFCMSG; break; +// } +// // HACK: this is a real hack +// DBWriteContactSettingDword(hContact, "ICQ", "UIN", 1/*0xffffffff*/); +// NotifyEventHooks(m_hookIcqMsgReq, IcqStatus, 1/*0xffffffff*/); +// DBDeleteContactSetting(hContact, "ICQ", "UIN"); +// } + + EnterCriticalSection(&m_csAccessAwayMes); + + char* mesAway = NULL; + switch (m_mirStatus) + { + case ID_STATUS_AWAY: mesAway = m_amesAway; break; + case ID_STATUS_NA: mesAway = m_amesNa; break; + case ID_STATUS_OCCUPIED: mesAway = m_amesOccupied; break; + case ID_STATUS_DND: mesAway = m_amesDnd; break; + case ID_STATUS_FREECHAT: mesAway = m_amesFfc; break; + } + + if (mesAway) + { + TPacket npak; + ZeroMemory(&npak, sizeof(npak)); + npak.idAckAwayMessage = pak.idReqAwayMessage; + npak.strAwayMessage = mesAway; + SendPacketExt(npak, cont->m_addr.S_un.S_addr); + } + + LeaveCriticalSection(&m_csAccessAwayMes); + +// CCSDATA ccs; +// PROTORECVEVENT pre; +// +// ccs.hContact = FindContact(cont->m_addr, cont->m_nick, false, true, cont->m_status); +// ccs.szProtoService = PSS_AWAYMSG; +// ccs.wParam = pak.idReqAwayMessage; +// ccs.lParam = (LPARAM)""; +// +// pre.flags = 0; +// pre.timestamp = get_time(); +// pre.szMessage = "Anus"; +// pre.lParam = ID_STATUS_AWAY; +// +// CallService(MS_PROTO_CHAINRECV, 0 ,(LPARAM)&ccs); + } + } + } + LeaveCriticalSection(&m_csReceiveThreadLock); +} + +void CMLan::RecvMessageUrl(CCSDATA* ccs) +{ + DBEVENTINFO dbei; + PROTORECVEVENT *pre=(PROTORECVEVENT*)ccs->lParam; + + ZeroMemory(&dbei,sizeof(dbei)); + + if (ccs->szProtoService==PSR_MESSAGE) + dbei.eventType = EVENTTYPE_MESSAGE; + else + dbei.eventType = EVENTTYPE_URL; + + dbei.cbSize = sizeof(dbei); + dbei.szModule = PROTONAME; + dbei.timestamp = pre->timestamp; + dbei.flags = pre->flags&PREF_CREATEREAD?DBEF_READ:0; + dbei.cbBlob = lstrlen(pre->szMessage)+1; + if (ccs->szProtoService==PSR_URL) + { + dbei.cbBlob += 2+lstrlen(pre->szMessage+dbei.cbBlob+1); + } + dbei.pBlob = (PBYTE)pre->szMessage; + + DBDeleteContactSetting(ccs->hContact,"CList","Hidden"); + + CallService(MS_DB_EVENT_ADD,(WPARAM)ccs->hContact,(LPARAM)&dbei); +} + +int CMLan::AddToContactList(u_int flags, EMPSEARCHRESULT* psr) +{ + if (psr->hdr.cbSize!=sizeof(EMPSEARCHRESULT)) + return (int)(HANDLE)NULL; + + in_addr addr; + addr.S_un.S_addr = psr->ipaddr; + + bool TempAdd = flags&PALF_TEMPORARY; + + HANDLE contact = FindContact(addr, psr->hdr.nick, true, !TempAdd, !TempAdd, psr->stat); + if (contact!=NULL) + { + DBWriteContactSettingWord(contact,PROTONAME,"Status", psr->stat ); + DBWriteContactSettingWord(contact,PROTONAME,"RemoteVersion", psr->ver ); + } + + return (int)contact; +} + +int CMLan::SendMessageUrl(CCSDATA* ccs, bool isUrl) +{ + DWORD th_id; + int cid = GetRandomProcId(); + int len; + if (isUrl) + { + len = lstrlen((char*)ccs->lParam); + ((char*)ccs->lParam)[len] = 1; + } + TDataHolder* hold = new TDataHolder(ccs, cid, isUrl?LEXT_SENDURL:LEXT_SENDMESSAGE, this); + if (isUrl) + { + ((char*)ccs->lParam)[len] = 0; + hold->msg[len] = 0; + } + CloseHandle(CreateThread(NULL,0,LaunchExt,(LPVOID)hold ,0,&th_id)); + return cid; +} + +int CMLan::Search(const char* name) +{ + DWORD th_id; + int cid = GetRandomProcId(); + CloseHandle(CreateThread(NULL,0,LaunchExt,(LPVOID)new TDataHolder(name, cid, LEXT_SEARCH, this),0,&th_id)); + return cid; +} + +int CMLan::GetAwayMsg(CCSDATA* ccs) +{ + DWORD th_id; + int cid = GetRandomProcId(); + CloseHandle(CreateThread(NULL,0,LaunchExt,(LPVOID)new TDataHolder(ccs, cid, LEXT_GETAWAYMSG, this),0,&th_id)); + return cid; +} + +//int CMLan::SendAwayMsg(CCSDATA* ccs) +//{ +// if (ccs->lParam) +// { +// TPacket pak; +// ZeroMemory(&pak, sizeof(pak)); +// +// pak.idAckAwayMessage = ccs->wParam; +// pak.strAwayMessage = (char*)ccs->lParam; +// u_long addr = db_get_dw(ccs->hContact, PROTONAME, "ipaddr", 0); +// SendPacketExt(pak, addr); +// } +// return 0; +//} + +int CMLan::RecvAwayMsg(CCSDATA* ccs) +{ + PROTORECVEVENT *pre=(PROTORECVEVENT*)ccs->lParam; + ProtoBroadcastAck(PROTONAME, ccs->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, (HANDLE)pre->lParam,(LPARAM)pre->szMessage); + return 0; +} + +DWORD WINAPI CMLan::LaunchExt(LPVOID lpParameter) +{ + TDataHolder* hold = (TDataHolder*)lpParameter; + switch (hold->op) + { + case LEXT_SENDMESSAGE: + case LEXT_SENDURL: + hold->lan->SendMessageExt(hold); + break; + case LEXT_SEARCH: + hold->lan->SearchExt(hold); + break; + case LEXT_GETAWAYMSG: + hold->lan->GetAwayMsgExt(hold); + break; + } + return 0; +} + +void CMLan::SearchExt(TDataHolder* hold) +{ + // TODO: Normal search must be added + + Sleep(0); + EMPSEARCHRESULT psr; + memset(&psr,0,sizeof(psr)); + psr.hdr.cbSize=sizeof(psr); + + TContact* cont = m_pRootContact; + while (cont) + { + if (strcmp(hold->msg, cont->m_nick)==0 || strcmp(hold->msg, "*")==0) + { + char buf[MAX_HOSTNAME_LEN]; + lstrcpy(buf, cont->m_nick); + int len = lstrlen(buf); + buf[len] = '@'; + lstrcpy(buf+len+1, inet_ntoa(cont->m_addr)); + psr.hdr.nick = cont->m_nick; + psr.hdr.firstName=""; + psr.hdr.lastName=""; + psr.hdr.email=buf; + psr.ipaddr = cont->m_addr.S_un.S_addr; + psr.stat = cont->m_status; + psr.ver = cont->m_ver; + + ProtoBroadcastAck(PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, (HANDLE)hold->id, (LPARAM)&psr); + } + cont = cont->m_prev; + } + ProtoBroadcastAck(PROTONAME, NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, (HANDLE)hold->id, 0); + delete hold; +} + +void CMLan::SendMessageExt(TDataHolder* hold) +{ + Sleep(0); + if (DBGetContactSettingWord((HANDLE)hold->hContact, PROTONAME, "Status", ID_STATUS_OFFLINE)==ID_STATUS_OFFLINE) + { + Sleep(20); + ProtoBroadcastAck(PROTONAME, hold->hContact, (hold->op==LEXT_SENDURL)?ACKTYPE_URL:ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)hold->id, 0); + } + else + { + TPacket pak; + ZeroMemory(&pak, sizeof(pak)); + u_long addr = db_get_dw((HANDLE)hold->hContact, PROTONAME, "ipaddr", 0); + pak.strMessage = hold->msg; + pak.idMessage = hold->id; + if (hold->op==LEXT_SENDURL) + pak.flIsUrl = true; + SendPacketExt(pak, addr); + } + delete hold; +} + +void CMLan::GetAwayMsgExt(TDataHolder* hold) +{ + // TODO: check all other params (offline user, offline protocol) + Sleep(0); + TPacket pak; + ZeroMemory(&pak, sizeof(pak)); + pak.idReqAwayMessage = hold->id; + u_long addr = db_get_dw((HANDLE)hold->hContact, PROTONAME, "ipaddr", 0); + SendPacketExt(pak, addr); + + ProtoBroadcastAck(PROTONAME, hold->hContact, ACKTYPE_AWAYMSG, ACKRESULT_SENTREQUEST, (HANDLE)hold->id, 0); + + delete hold; +} + +int CMLan::SetAwayMsg(u_int status, char* msg) +{ + char** ppMsg; + switch (status) + { + case ID_STATUS_AWAY: + ppMsg = &m_amesAway; + break; + case ID_STATUS_NA: + ppMsg = &m_amesNa; + break; + case ID_STATUS_OCCUPIED: + ppMsg = &m_amesOccupied; + break; + case ID_STATUS_DND: + ppMsg = &m_amesDnd; + break; + case ID_STATUS_FREECHAT: + ppMsg = &m_amesFfc; + break; + default: + return 1; + } + EnterCriticalSection(&m_csAccessAwayMes); + delete[] *ppMsg; + if (msg) + *ppMsg = _strdup(msg); + else + *ppMsg = NULL; + LeaveCriticalSection(&m_csAccessAwayMes); + return 0; +} + +////////////////////////////////////////////////////////////////////////// +// Packets + +u_char* CMLan::CreatePacket(TPacket& pak, int* pBufLen) +{ + int len = 1; + + if (pak.idVersion != -1) + pak.idVersion = VER; + else + pak.idVersion = 0; + if (pak.idStatus != -1) + pak.idStatus = m_mirStatus; + else + pak.idStatus = -1; + + // Searching for packet len + + if (pak.idVersion) + len += 1+1+4; + + if (pak.idStatus) + len += 1+1+2; + + int nameLen; + if (pak.strName) + { + nameLen = lstrlen(pak.strName); + len += 1+1+nameLen+1; + } + + if (pak.flReqStatus) + len += 1+1; + + int mesLen = 0; + if (pak.strMessage) + { + mesLen = lstrlen(pak.strMessage); + if (pak.flIsUrl) + mesLen += 1+lstrlen(pak.strMessage+mesLen+1); + len += 3+1+4+mesLen+1; + } + + if (pak.idAckMessage) + len += 1+1+4; + + if (pak.idReqAwayMessage) + len += 1+1+4; + + int awayLen = 0; + if (pak.strAwayMessage) + { + awayLen = lstrlen(pak.strAwayMessage); + len += 3+1+4+awayLen+1; + } + + // Creating packet + + u_char* buf = new u_char[len]; + u_char* pb = buf; + + if (pak.idVersion) + { + *pb++ = 1+4; + *pb++ = MCODE_SND_VERSION; + *((u_int*)pb) = pak.idVersion; + pb += sizeof(u_int); + } + + if (pak.idStatus) + { + *pb++ = 3; + *pb++ = MCODE_SND_STATUS; + *((u_short*)pb) = pak.idStatus; + pb += sizeof(u_short); + } + + if (pak.strName) + { + *pb++ = 1+nameLen+1; + *pb++ = MCODE_SND_NAME; + CopyMemory(pb, pak.strName, nameLen); + pb += nameLen; + *pb++ = 0; + } + + if (pak.flReqStatus) + { + *pb++ = 2; + *pb++ = MCODE_REQ_STATUS; + } + + if (pak.strMessage) + { + *pb++ = 255; + *((u_short*)pb) = 1+4+mesLen+1; + pb += sizeof(u_short); + if (pak.flIsUrl) + *pb++ = MCODE_SND_URL; + else + *pb++ = MCODE_SND_MESSAGE; + *((u_int*)pb) = pak.idMessage; + pb += sizeof(u_int); + if (mesLen) + CopyMemory(pb, pak.strMessage, mesLen); + pb += mesLen; + *pb++ = 0; + } + + if (pak.idAckMessage) + { + *pb++ = 1+4; + if (pak.flIsUrl) + *pb++ = MCODE_ACK_URL; + else + *pb++ = MCODE_ACK_MESSAGE; + *((u_int*)pb) = pak.idAckMessage; + pb += sizeof(u_int); + } + + if (pak.idReqAwayMessage) + { + *pb++ = 1+4; + *pb++ = MCODE_REQ_AWAYMSG; + *((u_int*)pb) = pak.idReqAwayMessage; + pb += sizeof(u_int); + } + + if (pak.strAwayMessage) + { + *pb++ = 255; + *((u_short*)pb) = 1+4+awayLen+1; + pb += sizeof(u_short); + *pb++ = MCODE_SND_AWAYMSG; + *((u_int*)pb) = pak.idAckAwayMessage; + pb += sizeof(u_int); + if (awayLen) + CopyMemory(pb, pak.strAwayMessage, awayLen); + pb += awayLen; + *pb++ = 0; + } + + *pb++ = 0; + + if (pBufLen) + *pBufLen = len; + + return buf; +} + +void CMLan::ParsePacket(TPacket& pak, u_char* buf, int len) +{ + ZeroMemory(&pak, sizeof(pak)); + u_char* buf_end = buf+len; + while (*buf && bufFileRemoveFromList(this); + } + delete[] m_szDescription; + if (m_szFiles) + { + char** cp = m_szFiles; + while (*cp) + { + delete[] *cp; + cp++; + } + delete[] m_szFiles; + } + + delete[] m_buf; + delete[] m_szDir; + delete[] m_szRenamedFile; + DeleteCriticalSection(&m_csAccess); +} + +int CMLan::TFileConnection::Recv(bool halt) +{ + // It is supposed that we're having not less then 2 bytes buffer size :) + EMLOG("Checking for data"); + while (1) + { + u_long len; + if (ioctlsocket(m_socket, FIONREAD, &len)!=0) + { + EMLOGERR(); + return FCS_TERMINATE; + } + if (len>=3) + break; + if (!halt) + { + EMLOG("No data - halting Recv (only " << len << " bytes)"); + m_recSize = -1; + delete[] m_buf; + m_buf = NULL; + return FCS_OK; + } + Sleep(10); + if (m_state==FCS_TERMINATE) + { + EMLOG("Terminate requested, exiting recv"); + return FCS_TERMINATE; + } + } + + u_short size; + int res; + EMLOG("Receiving packet size"); + res = recv(m_socket, (char*)&size, 3, 0); + if (res==SOCKET_ERROR) + { + EMLOGERR(); + return FCS_TERMINATE; + } + if (size==0) + { + EMLOG("Connection was gracefully closed - size is 0"); + delete m_buf; + m_buf = NULL; + m_recSize = 0; + return FCS_OK; + } + + Lock(); + delete[] m_buf; + m_buf = new u_char[size]; + m_recSize = size; + Unlock(); + + EMLOG("Waiting for the whole packet (" << size << " bytes)"); + int csize = 0; + while (csize!=size) + { + while(1) + { + u_long len; + if (ioctlsocket(m_socket, FIONREAD, &len) != 0) { + EMLOGERR(); + return FCS_TERMINATE; + } + if (len >= min(size,FILE_MIN_BLOCK)); + break; + Sleep(10); + if (m_state == FCS_TERMINATE) { + EMLOG("Terminate requested, exiting recv"); + return FCS_TERMINATE; + } + } + EMLOG("Getting data (approx " << size << " bytes)"); + Lock(); + res = recv(m_socket, (char*)m_buf+csize, size-csize, 0); + Unlock(); + EMLOGERR(res == SOCKET_ERROR); + EMLOGIF("Connection was gracefully closed", res==0); + if (res==0 || res==SOCKET_ERROR) + return FCS_TERMINATE; + EMLOG("Received " << res << " bytes"); + csize += res; + } + + EMLOG("Data recv OK"); + return FCS_OK; +} + +int CMLan::TFileConnection::SendRaw(u_char* buf, int size) +{ + while (size>0) + { + if (m_state==FCS_TERMINATE) + { + EMLOG("Terminate requested, exiting sendraw"); + return FCS_TERMINATE; + } + int err = send(m_socket, (char*)buf, size, 0); + if (err==SOCKET_ERROR) + { + EMLOGERR(); + return FCS_TERMINATE; + } + size -= err; + buf += err; + EMLOGIF("Send " << err << " bytes", size==0); + if (size>0) + { + EMLOG("Partial send (only " << err << " bytes"); + Sleep(10); + } + } + return FCS_OK; +} + +int CMLan::TFileConnection::Send(u_char* buf, int size) +{ + if (m_state==FCS_TERMINATE) + { + EMLOG("Terminate requested, exiting send"); + return FCS_TERMINATE; + } + + EMLOG("Sending 3 bytes of packet size (" << size << ")"); + if ( SendRaw((u_char*)&size, 3) != FCS_OK ) + return FCS_TERMINATE; + if ( SendRaw(buf, size) != FCS_OK ) + return FCS_TERMINATE; + + return FCS_OK; +} + +void CMLan::FileAddToList(TFileConnection* conn) +{ + EnterCriticalSection(&m_csFileConnectionList); + conn->Lock(); + conn->m_pNext = m_pFileConnectionList; + conn->m_pPrev = NULL; + if (m_pFileConnectionList) + m_pFileConnectionList->m_pPrev = conn; + m_pFileConnectionList = conn; + conn->m_pLan = this; + conn->Unlock(); + LeaveCriticalSection(&m_csFileConnectionList); +} + +void CMLan::FileRemoveFromList(TFileConnection* conn) +{ + EnterCriticalSection(&m_csFileConnectionList); + conn->Lock(); + if (conn->m_pPrev) + conn->m_pPrev->m_pNext = conn->m_pNext; + else + m_pFileConnectionList = conn->m_pNext; + if (conn->m_pNext) + conn->m_pNext->m_pPrev = conn->m_pPrev; + conn->m_pLan = NULL; + conn->m_pPrev = NULL; + conn->m_pNext = NULL; + conn->Unlock(); + LeaveCriticalSection(&m_csFileConnectionList); +} + +void CMLan::RecvFile(CCSDATA* ccs) +{ + DBEVENTINFO dbei; + PROTORECVEVENT *pre = (PROTORECVEVENT *)ccs->lParam; + char *szDesc, *szFile; + + DBDeleteContactSetting(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 = DWORD(sizeof(DWORD) + strlen(szFile) + strlen(szDesc) + 2); + dbei.pBlob = (PBYTE)pre->szMessage; + CallService(MS_DB_EVENT_ADD, (WPARAM)ccs->hContact, (LPARAM)&dbei); +} + +void CMLan::OnInTCPConnection(u_long addr, SOCKET in_sock) +{ + EMLOG("Received IN TCP connection"); + TContact* cont = m_pRootContact; + while (cont && cont->m_addr.S_un.S_addr!=addr) + cont = cont->m_prev; + + // There is no such user in cached list - can not identify him + if (cont==NULL) + return; + EMLOG("Passed contact search (cont is not NULL)"); + + TFileConnection* conn = new TFileConnection(); + conn->m_socket = in_sock; + conn->m_cid = GetRandomProcId(); + + if (conn->Recv() || conn->m_recSize==0 || conn->m_buf[0] != FCODE_SND_FILEREQ) + { + EMLOG("Not passed synchro data"); + EMLOGIF("Rec size is 0", conn->m_recSize==0); + EMLOGIF("Wrong data in packet", conn->m_buf[0] != FCODE_SND_FILEREQ); + delete conn; + return; + } + + EMLOG("File added to connectionn list"); + FileAddToList(conn); + + CCSDATA ccs; + PROTORECVEVENT pre; + + int rcTotalSize = *((int*)(conn->m_buf+1)); + int rcTotalFiles = *((int*)(conn->m_buf+1+4)); + pre.szMessage = new char[conn->m_recSize+rcTotalFiles]; + *((int*)pre.szMessage) = conn->m_cid; + char* pf_to = pre.szMessage+4; + char* pf_fr = (char*)conn->m_buf+1+4+4; + + conn->m_szFiles = new char* [rcTotalFiles+1]; + conn->m_szFiles[rcTotalFiles] = NULL; + + for (int i=0; im_szFiles[i] = _strdup(pf_fr); + if (i) + *pf_to++ = ' '; + while (*pf_fr) + *pf_to++ = *pf_fr++; + pf_fr++; + *pf_to++ = ';'; + } + *pf_to++ = 0; + + while (*pf_fr) + *pf_to++ = *pf_fr++; + *pf_to++ = *pf_fr++; + + conn->m_hContact = ccs.hContact = FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status); + ccs.szProtoService = PSR_FILE; + ccs.wParam = 0; + ccs.lParam =(LPARAM)⪯ + + pre.flags = 0; + pre.timestamp = get_time(); + pre.lParam = 0; + + CallService(MS_PROTO_CHAINRECV,0,(LPARAM)&ccs); + + delete[] pre.szMessage; + + while (!conn->m_state) + Sleep(10); + + if (conn->m_state!=TFileConnection::FCS_ALLOW) + { + conn->Send(NULL, 0); + delete conn; + return; + } + + conn->Lock(); + conn->m_state = TFileConnection::FCS_OK; + conn->Unlock(); + + u_char buf = FCODE_SND_ACCEPT; + if (conn->Send(&buf, 1)) + { + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + // Getting current directory + char path[MAX_PATH]; + char* pathpart; + GetFullPathName(conn->m_szDir, MAX_PATH, path, &pathpart); + if (!SetCurrentDirectory(path)) + { + if (rcTotalFiles==1) + conn->m_szRenamedFile = _strdup(pathpart); + *pathpart = 0; + if (!SetCurrentDirectory(path)) + { + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open output directory"); + delete conn; + return; + } + } + + //Starting from next file + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)conn->m_cid, 0); + + PROTOFILETRANSFERSTATUS fts; + fts.cbSize = sizeof(fts); + fts.totalBytes = rcTotalSize; + fts.totalFiles = rcTotalFiles; + fts.totalProgress = 0; + fts.szWorkingDir = conn->m_szDir; + fts.flags = false; + fts.hContact = conn->m_hContact; + fts.pszFiles = conn->m_szFiles; + + bool err = false; + + for (int fileNo=0; fileNoRecv() || conn->m_recSize==0 || conn->m_buf[0] != FCODE_SND_NEXTFILE) + { + err = true; + break; + } + EMLOG("Ok"); + + fts.szCurrentFile = fts.pszFiles[fileNo]; + fts.currentFileNumber = fileNo; + fts.currentFileProgress = 0; + fts.currentFileSize = *((int*)(conn->m_buf+1)); + fts.currentFileTime = get_time(); + + EMLOG("Waiting for ACCEPT"); + if (!ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (HANDLE)conn->m_cid, (LPARAM)&fts)) + { + conn->Lock(); + conn->m_state = TFileConnection::FCS_OVERWRITE; + conn->Unlock(); + } + else + { + while(!conn->m_state) + Sleep(10); + } + EMLOG("Ok"); + EMLOG("Checking if we're terminated"); + if (conn->m_state==TFileConnection::FCS_TERMINATE) + { + err = true; + break; + } + EMLOG("Still working"); + + u_char snd_buf[5]; + + EMLOG("Checking if we're skipping file"); + if (conn->m_state==TFileConnection::FCS_SKIP) + { + EMLOG("Skipped"); + conn->Lock(); + conn->m_state = TFileConnection::FCS_OK; + conn->Unlock(); + snd_buf[0] = FCODE_SND_FILESKIP; + if (conn->Send(snd_buf, 1)) + { + EMLOG("Error during sending 'skip' code'"); + err = true; + break; + } + continue; + } + EMLOG("Still processing"); + + char* filename = conn->m_szRenamedFile; + if (!filename) + filename = conn->m_szFiles[fileNo]; + + int mode_open = CREATE_ALWAYS; + if (conn->m_state==TFileConnection::FCS_RESUME) + mode_open = OPEN_ALWAYS; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_OK; + conn->Unlock(); + + EMLOG("Creating file"); + HANDLE hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, mode_open, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + EMLOG("Can't create file"); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't create file"); + delete conn; + return; + } + EMLOG("Ok"); + + snd_buf[0] = FCODE_SND_ACCEPT; + int fsize = GetFileSize(hFile, NULL); + *((int*)(snd_buf+1)) = fsize; + SetFilePointer(hFile, 0, NULL, FILE_END); + + fts.currentFileProgress = fsize; + fts.totalProgress += fsize; + + EMLOG("Sending ack"); + if (conn->Send(snd_buf, 5)) + { + EMLOG("Error sending ACK"); + CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + EMLOG("Broadcast ack internally"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + EMLOG("Ok"); + int refr = 0; + while (fts.currentFileProgressRecv(); + if (isErr || conn->m_recSize==0 || conn->m_buf[0]!=FCODE_SND_FILEDATA) + { + EMLOGIF("Error conn->Recv()", isErr); + EMLOGIF("Error conn->m_recSize!=0", conn->m_recSize==0); + EMLOGIF("Error conn->m_buf[0]==FCODE_SND_FILEDATA", conn->m_buf[0]!=FCODE_SND_FILEDATA); + EMLOG("Error"); + err = true; + break; + } + EMLOG("Received"); + DWORD written; + EMLOG("Writing to file"); + WriteFile(hFile, conn->m_buf+1, conn->m_recSize-1, &written, NULL); + EMLOG("Ok"); + fts.currentFileProgress += conn->m_recSize-1; + fts.totalProgress += conn->m_recSize-1; + refr += conn->m_recSize-1; + if (refr>=FILE_INFO_REFRESH) + { + EMLOG("Refreshing progress bar"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + refr = 0; + } + } + if (!err) + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + + EMLOG("Closing file handle"); + CloseHandle(hFile); + + if (err) + break; + + delete[] conn->m_szRenamedFile; + conn->m_szRenamedFile = NULL; + } + + if (err) + { + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)conn->m_cid, 0); + + delete conn; +} + +void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParameter) +{ + EMLOG("Sending OUT TCP connection"); + TFileConnection* conn = (TFileConnection*)lpParameter; + + if (out_socket == INVALID_SOCKET) + { + EMLOG("Can't create OUT socket"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't initiate transfer"); + delete conn; + return; + } + conn->m_socket = out_socket; + EMLOG("Socket is created"); + + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)conn->m_cid, 0); + + EMLOG("Added to list"); + FileAddToList(conn); + + u_char buf[FILE_SEND_BLOCK+1]; + char name[MAX_PATH+8]; + + buf[0] = FCODE_SND_FILEREQ; + int len = 1+4+4; + int size = 0; + int filecount = 0; + char** pf = conn->m_szFiles; + while (*pf) + { + // TODO: FIX IT ! + EMLOG("Opening file"); + HANDLE hFile = CreateFile(*pf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + EMLOG("Can't open file for reading"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open one of the files"); + delete conn; + return; + } + size += GetFileSize(hFile, NULL); + filecount++; + CloseHandle(hFile); + + char* filepart; + GetFullPathName(*pf, MAX_PATH, (char*)name, &filepart); + delete[] *pf; + *pf = _strdup(name); + strcpy((char*)buf+len, filepart); + len += (int)strlen(filepart)+1; + + pf++; + } + strcpy((char*)buf+len, conn->m_szDescription); + len += (int)strlen(conn->m_szDescription)+1; + + *((int*)(buf+1)) = size; + *((int*)(buf+1+4)) = filecount; + + GetCurrentDirectory(MAX_PATH, name); + conn->m_szDir = _strdup(name); + + PROTOFILETRANSFERSTATUS fts; + fts.cbSize = sizeof(fts); + fts.totalBytes = size; + fts.totalFiles = filecount; + fts.totalProgress = 0; + fts.szWorkingDir = conn->m_szDir; + fts.flags = PFTS_SENDING; + fts.hContact = conn->m_hContact; + fts.pszFiles = conn->m_szFiles; + + EMLOG("Sending file size"); + if (conn->Send(buf, len)) + { + EMLOG("Failed"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + EMLOG("Waiting for ACK"); + if (conn->Recv() || conn->m_recSize==0 || conn->m_buf[0]!=FCODE_SND_ACCEPT) + { + EMLOG("Failed"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)conn->m_cid, 0); + delete conn; + return; + } + + bool err = false; + + for (int fileNo=0; fileNom_szFiles[fileNo] , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + EMLOG("Failed"); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open file"); + delete conn; + return; + } + + EMLOG("Sending broadcast NEXT FILE"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)conn->m_cid, 0); + EMLOG("Ok"); + + u_char snd_buf[5]; + snd_buf[0] = FCODE_SND_NEXTFILE; + int fsize = GetFileSize(hFile, NULL); + *((int*)(snd_buf+1)) = fsize; + EMLOG("Sending file size"); + if (conn->Send(snd_buf, 5)) + { + CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + EMLOG("Waiting for ACK"); + if (conn->Recv() || conn->m_recSize==0 || (conn->m_buf[0]!=FCODE_SND_ACCEPT && conn->m_buf[0]!=FCODE_SND_FILESKIP)) + { + CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + if (conn->m_buf[0]!=FCODE_SND_FILESKIP) + { + EMLOG("File is not skipped"); + int filepos = *((int*)(conn->m_buf+1)); + SetFilePointer(hFile, filepos, NULL, FILE_BEGIN); + + fts.szCurrentFile = fts.pszFiles[fileNo]; + fts.currentFileTime = get_time(); + fts.currentFileNumber = fileNo; + fts.currentFileProgress = filepos; + fts.totalProgress += filepos; + fts.currentFileSize = fsize; + EMLOG("Starting data transfer"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + EMLOG("Ok"); + int refr = 0; + + fsize -= filepos; + + while (fsize>0) + { + DWORD readbytes; + int tosend = FILE_SEND_BLOCK; + if (tosend>fsize) + tosend = fsize; + EMLOG("Reading file data"); + ReadFile(hFile, buf+1, tosend, &readbytes, NULL); + EMLOG("Ok"); + buf[0] = FCODE_SND_FILEDATA; + + if (readbytes!=tosend) + { + EMLOG("Error during reading file. File was changed"); + CloseHandle(hFile); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't read file"); + delete conn; + return; + } + EMLOG("Sending data buffer"); + if (conn->Send(buf, tosend+1)) + { + //CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + fts.currentFileProgress += tosend; + fts.totalProgress += tosend; + fsize -= tosend; + refr += tosend; + if (refr>=FILE_INFO_REFRESH || fsize<=0) + { + EMLOG("Refreshing file info"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + refr = 0; + EMLOG("Checking for 'abort'"); + if (conn->Recv(false) || conn->m_recSize!=-1) + { + EMLOG("Aborted"); + //CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + } + + if (conn->m_state) + { + EMLOG("Interrupted by user"); + conn->Send(NULL, 0); + //CloseHandle(hFile); + err = true; + break; + } + } + } + if (err) + break; + CloseHandle(hFile); + } + + if (err) + { + EMLOG("There was error during file transfering"); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)conn->m_cid, 0); + + delete conn; +} + +int CMLan::SendFile(CCSDATA* ccs) +{ + int cid = GetRandomProcId(); + + TFileConnection* conn = new TFileConnection(); + conn->m_cid = cid; + conn->m_hContact = ccs->hContact; + + conn->m_szDescription = _strdup((char*)ccs->wParam); + int files = 0; + char** ppszFiles = (char**)ccs->lParam; + while (ppszFiles[files]) + files++; + conn->m_szFiles = new char* [files+1]; + for (int i=0; im_szFiles[i] = _strdup(ppszFiles[i]); + conn->m_szFiles[files] = NULL; + + u_long addr = db_get_dw(ccs->hContact, PROTONAME, "ipaddr", 0); + CreateTCPConnection(addr, (LPVOID)conn); + + return cid; +} + +int CMLan::FileAllow(CCSDATA* ccs) +{ + int cid = (int)ccs->wParam; + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_ALLOW; + conn->m_szDir = _strdup((char*)ccs->lParam); + conn->Unlock(); + return cid; +} + +int CMLan::FileDeny(CCSDATA* ccs) +{ + int cid = (int)ccs->wParam; + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_TERMINATE; + conn->Unlock(); + return 0; +} + +int CMLan::FileCancel(CCSDATA* ccs) +{ + int cid = (int)ccs->wParam; + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_TERMINATE; + conn->Unlock(); + return 0; +} + +int CMLan::FileResume(int cid, PROTOFILERESUME* pfr) +{ + //int cid = (int)ccs->wParam; + //PROTOFILERESUME* pfr = (PROTOFILERESUME*)ccs->lParam; + + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + switch (pfr->action) + { + case FILERESUME_OVERWRITE: + conn->m_state = TFileConnection::FCS_OVERWRITE; + break; + case FILERESUME_RESUME: + conn->m_state = TFileConnection::FCS_RESUME; + break; + case FILERESUME_RENAME: + conn->m_state = TFileConnection::FCS_RENAME; + delete[] conn->m_szRenamedFile; + conn->m_szRenamedFile = _strdup(pfr->szFilename); + break; + case FILERESUME_SKIP: + conn->m_state = TFileConnection::FCS_SKIP; + break; + } + conn->Unlock(); + + return 0; +} diff --git a/protocols/EmLanProto/src/mlan.h b/protocols/EmLanProto/src/mlan.h new file mode 100644 index 0000000000..21471cdc2f --- /dev/null +++ b/protocols/EmLanProto/src/mlan.h @@ -0,0 +1,200 @@ +////////////////////////////////////////////////////////////////////////// +// Miranda lan functions + +#ifndef __mlan_h__ +#define __mlan_h__ + +#include "lan.h" + +#define MLAN_TIMEOUT 5 +#define MLAN_CHECK 50 +#define MLAN_SLEEP 400 +#define MAX_HOSTNAME_LEN 128 + +#define FILE_SEND_BLOCK 4096 +//#define FILE_SEND_BLOCK 32768 +#define FILE_INFO_REFRESH 131072 +#define FILE_MIN_BLOCK 1024 + +class CMLan; + +typedef struct +{ + PROTOSEARCHRESULT hdr; + u_long ipaddr; + WORD stat; + u_long ver; +} EMPSEARCHRESULT; + +struct TDataHolder +{ +public: + long id; + long op; + + HANDLE hContact; + char* const msg; + CMLan* lan; + + explicit TDataHolder(const CCSDATA* cc,unsigned long _id, long _op, CMLan* _lan): + msg(_strdup((char*)cc->lParam)),hContact(cc->hContact),id(_id),op(_op),lan(_lan) + {} + explicit TDataHolder(const char* str,unsigned long _id, long _op, CMLan* _lan): + msg(_strdup(str)),hContact(0), id(_id), op(_op), lan(_lan) + {} + ~TDataHolder(){delete[] msg;} +}; + +class CMLan : public CLan +{ +public: + CMLan(); + ~CMLan(); + + int GetMirandaStatus(); + void SetMirandaStatus(u_int status); + void SetAllOffline(); + void RecvMessageUrl(CCSDATA* ccs); + int SendMessageUrl(CCSDATA* ccs, bool isUrl); + int GetAwayMsg(CCSDATA* ccs); + int RecvAwayMsg(CCSDATA* ccs); + int SetAwayMsg(u_int status, char* msg); + + int AddToContactList(u_int flags, EMPSEARCHRESULT* psr); + int Search(const char* name); + void LoadSettings(); + void SaveSettings(); + + char* GetName() { return m_name; } + bool GetUseHostName() { return m_UseHostName; } + void SetUseHostName(bool val) { m_UseHostName = val; } + void SetRequiredIp(u_long ip) { m_RequiredIp = ip; } + + int SendFile(CCSDATA* ccs); + void RecvFile(CCSDATA* ccs); + int FileAllow(CCSDATA* ccs); + int FileDeny(CCSDATA* ccs); + int FileCancel(CCSDATA* ccs); + int FileResume(int cid, PROTOFILERESUME* pfr); + +protected: + virtual void OnRecvPacket(u_char* mes, int len, in_addr from); + virtual void OnInTCPConnection(u_long addr, SOCKET in_socket); + virtual void OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParameter); +private: + struct TContact + { + in_addr m_addr; + u_int m_status; + int m_time; + u_long m_ver; + char* m_nick; + TContact* m_prev; + }; + u_int m_mirStatus; + TContact* m_pRootContact; + HANDLE m_hCheckThread; + + char m_name[MAX_HOSTNAME_LEN]; + int m_nameLen; + + CRITICAL_SECTION m_csAccessClass; + CRITICAL_SECTION m_csReceiveThreadLock; + CRITICAL_SECTION m_csAccessAwayMes; + + void RequestStatus(bool answer=false, u_long m_addr=INADDR_BROADCAST); + HANDLE FindContact(in_addr addr, const char* nick, bool add_to_list, bool make_permanent, bool make_visible, u_int status = ID_STATUS_ONLINE); + void DeleteCache(); + + void StartChecking(); + void StopChecking(); + static DWORD WINAPI CheckProc(LPVOID lpParameter); + void Check(); + + int m_handleId; + int GetRandomProcId() { return m_handleId++; } // TODO: must create propper CRITICAL SECTION, cause there may be collisions + + static DWORD WINAPI LaunchExt(LPVOID lpParameter); + void SearchExt(TDataHolder* hold); + void SendMessageExt(TDataHolder* hold); + void GetAwayMsgExt(TDataHolder* hold); + + struct TPacket + { + u_int idVersion; // -1 means version is not sent + u_int idStatus; // -1 means status is not sent + char* strName; // NULL means no name + bool flReqStatus; // false means no request + char* strMessage; // NULL means no message + int idMessage; + bool flIsUrl; // true if message is an URL + int idAckMessage; // 0 means no ack + int idReqAwayMessage; // 0 means no request + char* strAwayMessage; // NULL means no away message + int idAckAwayMessage; + }; + u_char* CreatePacket(TPacket& pak, int* pBufLen=NULL); + void ParsePacket(TPacket& pak, u_char* buf, int len=65536); + void SendPacketExt(TPacket& pak, u_long addr); + + bool m_UseHostName; + u_long m_RequiredIp; + + HANDLE m_hookIcqMsgReq; + char* m_amesAway; + char* m_amesNa; + char* m_amesOccupied; + char* m_amesDnd; + char* m_amesFfc; + + + struct TFileConnection + { + enum enumFileConnectionStates + { + FCS_OK = 0, + FCS_TERMINATE, + FCS_ALLOW, + + FCS_OVERWRITE, + FCS_RESUME, + FCS_RENAME, + FCS_SKIP, + }; + + TFileConnection(); + ~TFileConnection(); + void Lock() { EnterCriticalSection(&m_csAccess); } + void Unlock() { LeaveCriticalSection(&m_csAccess); } + void Terminate() { Lock(); m_state = FCS_TERMINATE; Unlock(); } + int Recv(bool halt=true); + int Send(u_char* buf, int size); + int SendRaw(u_char* buf, int size); + + CMLan* m_pLan; + TFileConnection* m_pPrev; + TFileConnection* m_pNext; + int m_state; + int m_cid; + SOCKET m_socket; + u_long m_addr; + HANDLE m_hContact; + + char* m_szDescription; + char** m_szFiles; + char* m_szDir; + char* m_szRenamedFile; + + u_char* m_buf; + int m_recSize; + + CRITICAL_SECTION m_csAccess; + }; + void FileAddToList(TFileConnection* conn); + void FileRemoveFromList(TFileConnection* conn); + + CRITICAL_SECTION m_csFileConnectionList; + TFileConnection* m_pFileConnectionList; +}; + +#endif //__mlan_h__ diff --git a/protocols/EmLanProto/src/packet.cpp b/protocols/EmLanProto/src/packet.cpp new file mode 100644 index 0000000000..be767bbbd4 --- /dev/null +++ b/protocols/EmLanProto/src/packet.cpp @@ -0,0 +1,2 @@ +////////////////////////////////////////////////////////////////////////// +// Packets parsing for the E-mage lan protocol diff --git a/protocols/EmLanProto/src/packet.h b/protocols/EmLanProto/src/packet.h new file mode 100644 index 0000000000..b4fcd2dc2c --- /dev/null +++ b/protocols/EmLanProto/src/packet.h @@ -0,0 +1,14 @@ +////////////////////////////////////////////////////////////////////////// +// Packets parsing for the E-mage lan protocol + +#ifndef __packet_h__ +#define __packet_h__ + +class CPacket +{ +public: + CPacket(); + ~CPacket(); +}; + +#endif //__packet_h__ diff --git a/protocols/EmLanProto/src/resource.h b/protocols/EmLanProto/src/resource.h new file mode 100644 index 0000000000..25a47d65eb --- /dev/null +++ b/protocols/EmLanProto/src/resource.h @@ -0,0 +1,25 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by amdproto.rc +// +#define IDI_ICON_ONLINE 101 +#define IDD_DIALOG1 102 +#define IDI_ICON_OFFLINE 103 +#define IDD_EMP_FORM_OPT 104 +#define IDC_LIST_IP 1001 +#define IDC_RADIO_USECOMPNAME 1004 +#define IDC_RADIO_USEOWN 1005 +#define IDC_EDIT2 1006 +#define IDC_EDIT_NAME 1006 +#define IDC_EDIT1 1007 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1008 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/EmLanProto/src/stdafx.cpp b/protocols/EmLanProto/src/stdafx.cpp new file mode 100644 index 0000000000..fc3e963191 --- /dev/null +++ b/protocols/EmLanProto/src/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// amdproto.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/protocols/EmLanProto/src/stdafx.h b/protocols/EmLanProto/src/stdafx.h new file mode 100644 index 0000000000..f6c9db86be --- /dev/null +++ b/protocols/EmLanProto/src/stdafx.h @@ -0,0 +1,80 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#define _CRT_SECURE_NO_WARNINGS +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include + +#include "newpluginapi.h" + +#include "m_options.h" +#include "m_system.h" + +#include "m_database.h" +#include "m_protomod.h" +#include "statusmodes.h" +#include "m_protosvc.h" +#include "m_options.h" +#include "m_langpack.h" +#include + +#define PROTONAME "EM_LAN_PROTO" +#define VER PLUGIN_MAKE_VERSION(0, 0, 1, 1) + +//#define ME_ICQ_STATUSMSGREQ "ICQ/StatusMsgReq" +// +//#define ICQ_MSGTYPE_GETAWAYMSG 0xE8 +//#define ICQ_MSGTYPE_GETOCCUMSG 0xE9 +//#define ICQ_MSGTYPE_GETNAMSG 0xEA +//#define ICQ_MSGTYPE_GETDNDMSG 0xEB +//#define ICQ_MSGTYPE_GETFFCMSG 0xEC + +//#define VERBOSE + +#ifdef VERBOSE +#include +extern std::fstream emlanLog; +#define EMLOG(x) emlanLog << "[" << __FUNCTION__ << "] [" << __FILE__ << ":" << __LINE__ << "] " << x << std::endl +#define EMLOGIF(x, y) if (y) EMLOG(x) +inline const char* showErrName(int err) +{ + const char* name = "unknown"; + switch (err) + { + case 0: name = "NOERROR"; break; + case WSANOTINITIALISED: name = "WSANOTINITIALIZED"; break; + case WSAENETDOWN: name = "WSAENETDOWN"; break; + case WSAEACCES: name = "WSAEACCES"; break; + case WSAEFAULT: name = "WSAEFAULT"; break; + case WSAENOTCONN: name = "WSAENOTCONN"; break; + case WSAEINTR: name = "WSAEINTR"; break; + case WSAEINPROGRESS: name = "WSAEINPROGRESS"; break; + case WSAENETRESET: name = "WSAENETRESET"; break; + case WSAENOTSOCK: name = "WSAENOTSOCK"; break; + case WSAEOPNOTSUPP: name = "WSAEOPNOTSUPP"; break; + case WSAESHUTDOWN: name = "WSAESHUTDOWN"; break; + case WSAEWOULDBLOCK: name = "WSAEWOULDBLOCK"; break; + case WSAEMSGSIZE: name = "WSAEMSGSIZE"; break; + case WSAEINVAL: name = "WSAEINVAL"; break; + case WSAECONNABORTED: name = "WSAECONNABORTED"; break; + case WSAETIMEDOUT: name = "WSAETIMEDOUT"; break; + case WSAECONNRESET: name = "WSAECONNRESET"; break; + case WSAENOBUFS: name = "WSAENOBUFS"; break; + case WSAEHOSTUNREACH: name = "WSAEHOSTUNREACH"; break; + } + return name; +} +#define EMLOGERR() { int err = WSAGetLastError(); const char* name = showErrName(err); EMLOG( "Error: " << err << '(' << name << ')' ); } +#define EMLOGERRIF(y) if (y) EMLOGERR() +#else +#define EMLOG(x) +#define EMLOGIF(x, y) +#define EMLOGERR() +#define EMLOGERRIF() +#endif -- cgit v1.2.3