diff options
Diffstat (limited to 'protocols/EmLanProto/src')
-rw-r--r-- | protocols/EmLanProto/src/amdproto.cpp | 394 | ||||
-rw-r--r-- | protocols/EmLanProto/src/get_time.cpp | 70 | ||||
-rw-r--r-- | protocols/EmLanProto/src/get_time.h | 25 | ||||
-rw-r--r-- | protocols/EmLanProto/src/lan.cpp | 301 | ||||
-rw-r--r-- | protocols/EmLanProto/src/lan.h | 128 | ||||
-rw-r--r-- | protocols/EmLanProto/src/mlan.cpp | 1807 | ||||
-rw-r--r-- | protocols/EmLanProto/src/mlan.h | 200 | ||||
-rw-r--r-- | protocols/EmLanProto/src/packet.cpp | 2 | ||||
-rw-r--r-- | protocols/EmLanProto/src/packet.h | 14 | ||||
-rw-r--r-- | protocols/EmLanProto/src/resource.h | 25 | ||||
-rw-r--r-- | protocols/EmLanProto/src/stdafx.cpp | 8 | ||||
-rw-r--r-- | protocols/EmLanProto/src/stdafx.h | 80 |
12 files changed, 3054 insertions, 0 deletions
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; i<count; i++)
+ {
+ in_addr addr = g_lan->GetHostAddress(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 <basetsd.h>
+#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;i<year;i++) ret+=365+IsLeapYear(i);
+ for(i=0;i<month-1;i++) ret+=daysInMonth[i];
+ if (month>2 && 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_hostAddrCount<MAX_INTERNAL_IP)
+ {
+ in_addr addr;
+ addr.S_un.S_addr = *((u_long*)(*pAddr));
+ m_hostAddr[m_hostAddrCount++] = addr;
+ pAddr++;
+ }
+ m_curAddr = m_hostAddr[0];
+ }
+ else
+ {
+ m_status = LS_CANT_GET_HOSTADDR;
+ }
+ }
+ else
+ {
+ m_status = LS_OK;
+ m_mode = LM_OFF;
+ }
+}
+
+void CLan::Shutdown()
+{
+ if (m_mode == LM_OFF)
+ return;
+
+ m_hostAddrCount = 0;
+ StopListen();
+ WSACleanup();
+ m_status = LS_OK;
+ m_mode = LM_OFF;
+}
+
+void CLan::StopListen()
+{
+ if (m_mode==LM_OFF)
+ return;
+
+ if (m_hListenThread)
+ {
+ TerminateThread(m_hListenThread, 0);
+ m_hListenThread = NULL;
+ }
+ if (m_hAcceptTCPThread)
+ {
+ EnterCriticalSection(&m_csAcceptTCPThread);
+ TerminateThread(m_hAcceptTCPThread, 0);
+ m_hAcceptTCPThread = NULL;
+ LeaveCriticalSection(&m_csAcceptTCPThread);
+ }
+ if (m_income != INVALID_SOCKET)
+ {
+ closesocket(m_income);
+ m_income = INVALID_SOCKET;
+ }
+ if (m_filesoc != INVALID_SOCKET)
+ {
+ closesocket(m_filesoc);
+ m_filesoc = INVALID_SOCKET;
+ }
+ m_mode = LM_ON;
+}
+
+void CLan::StartListen()
+{
+ if (m_mode!=LM_ON)
+ return;
+
+ m_income = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ m_filesoc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_income == INVALID_SOCKET || m_filesoc == INVALID_SOCKET)
+ {
+ m_status = LS_CANT_CREATE_SOCKET;
+ StopListen();
+ }
+ else
+ {
+ int enable = 1;
+ if (setsockopt(m_income, SOL_SOCKET, SO_BROADCAST, (const char*)&enable, sizeof(enable))!=0)
+ {
+ m_mode = LM_ON;
+ m_status = LS_CANT_TURN_ON_BROADCAST;
+ StopListen();
+ return;
+ }
+ m_mode = LM_LISTEN;
+ sockaddr_in addr;
+ addr.sin_addr = m_curAddr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = PORT_NUMBER;
+ if (bind(m_income, (sockaddr*)&addr, sizeof(addr))!=0)
+ {
+ m_mode = LM_ON;
+ m_status = LS_CANT_BIND_SOCKET;
+ StopListen();
+ return;
+ }
+
+ if (bind(m_filesoc, (sockaddr*)&addr, sizeof(addr))!=0)
+ {
+ m_mode = LM_ON;
+ m_status = LS_CANT_BIND_SOCKET;
+ StopListen();
+ return;
+ }
+
+ if (listen(m_filesoc, SOMAXCONN)!=0)
+ {
+ m_mode = LM_ON;
+ m_status = LS_CANT_START_LISTEN;
+ StopListen();
+ return;
+ }
+
+ DWORD threadId;
+ m_hListenThread = CreateThread(NULL, 0, ListenProc, (LPVOID)this, 0, &threadId);
+ m_hAcceptTCPThread = CreateThread(NULL, 0, AcceptTCPProc, (LPVOID)this, 0, &threadId);
+ if (m_hListenThread==NULL || m_hAcceptTCPThread==NULL)
+ {
+ m_mode = LM_ON;
+ m_status = LS_CANT_CREATE_THREADS;
+ StopListen();
+ return;
+ }
+ }
+}
+
+void CLan::SetCurHostAddress(in_addr addr)
+{
+ if (m_mode!=LM_OFF)
+ {
+ int oldMode = m_mode;
+ StopListen();
+ m_curAddr = addr;
+ if (oldMode==LM_LISTEN)
+ StartListen();
+ }
+}
+
+DWORD WINAPI CLan::ListenProc(LPVOID lpParameter)
+{
+ CLan* lan = (CLan*)lpParameter;
+ lan->Listen();
+ 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 && buf<buf_end)
+ {
+ int tlen = *buf++;
+ if (tlen==255)
+ {
+ tlen = *((u_short*)buf);
+ buf += sizeof(u_short);
+ }
+ u_char* pb = buf;
+ int comm = *pb++;
+ switch (comm)
+ {
+ case MCODE_SND_STATUS:
+ pak.idStatus = *((u_short*)pb);
+ break;
+ case MCODE_SND_NAME:
+ pak.strName = (char*)pb;
+ break;
+ case MCODE_REQ_STATUS:
+ pak.flReqStatus = true;
+ break;
+ case MCODE_SND_URL:
+ pak.flIsUrl = true;
+ case MCODE_SND_MESSAGE:
+ pak.idMessage = *((u_int*)pb);
+ pb += sizeof(u_int);
+ pak.strMessage = (char*)pb;
+ break;
+ case MCODE_ACK_URL:
+ pak.flIsUrl = true;
+ case MCODE_ACK_MESSAGE:
+ pak.idAckMessage = *((u_int*)pb);
+ //pb += sizeof(u_int);
+ break;
+ case MCODE_SND_VERSION:
+ pak.idVersion = *((u_int*)pb);
+ //pb += sizeof(u_int);
+ break;
+ case MCODE_REQ_AWAYMSG:
+ pak.idReqAwayMessage = *((u_int*)pb);
+ //pb += sizeof(u_int);
+ break;
+ case MCODE_SND_AWAYMSG:
+ pak.idAckAwayMessage = *((u_int*)pb);
+ pb += sizeof(u_int);
+ pak.strAwayMessage = (char*)pb;
+ break;
+ }
+ buf += tlen;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////
+// Settings
+
+void CMLan::LoadSettings()
+{
+ m_RequiredIp = db_get_dw(NULL, PROTONAME, "ipaddr", 0);
+ m_UseHostName = db_get_b(NULL, PROTONAME, "UseHostName", 1) != 0;
+ if (m_UseHostName) {
+ gethostname(m_name, MAX_HOSTNAME_LEN);
+ CharLower(m_name);
+ }
+ else {
+ DBVARIANT dbv;
+ // Deleting old 'Name' value - using 'Nick' instead of it now
+ if ( DBGetContactSettingString(NULL, PROTONAME, "Nick", &dbv)) {
+ if (DBGetContactSettingString(NULL, PROTONAME, "Name", &dbv))
+ dbv.pszVal = "EmLan_User";
+ else
+ DBDeleteContactSetting(NULL, PROTONAME, "Name");
+ }
+ if (!dbv.pszVal[0])
+ dbv.pszVal = "EmLan_User";
+ lstrcpy(m_name, dbv.pszVal);
+ }
+ m_nameLen = lstrlen(m_name);
+
+ if (GetStatus()!=LM_LISTEN)
+ {
+ int ipcount = GetHostAddrCount();
+ for (int i=0; i<ipcount; i++)
+ {
+ in_addr addr = GetHostAddress(i);
+ if (addr.S_un.S_addr == m_RequiredIp)
+ {
+ SetCurHostAddress(addr);
+ break;
+ }
+ }
+ }
+}
+
+void CMLan::SaveSettings()
+{
+ DBWriteContactSettingDword(NULL, PROTONAME, "ipaddr", m_RequiredIp);
+ DBWriteContactSettingByte(NULL, PROTONAME, "UseHostName", m_UseHostName);
+ DBWriteContactSettingString(NULL, PROTONAME, "Nick", m_name);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+CMLan::TFileConnection::TFileConnection()
+{
+ ZeroMemory(this, sizeof(TFileConnection));
+ InitializeCriticalSection(&m_csAccess);
+ m_state = FCS_OK;
+}
+
+CMLan::TFileConnection::~TFileConnection()
+{
+ if (m_pLan)
+ {
+ m_pLan->FileRemoveFromList(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; i<rcTotalFiles; i++)
+ {
+ conn->m_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; fileNo<rcTotalFiles; fileNo++)
+ {
+ EMLOG("Waiting for 'next file'");
+ if (conn->Recv() || 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.currentFileProgress<fts.currentFileSize)
+ {
+ EMLOG("Waiting for data");
+ bool isErr = conn->Recv();
+ 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; fileNo<filecount; fileNo++)
+ {
+ EMLOG("Opening file for reading (once more)");
+ HANDLE hFile = CreateFile(conn->m_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; i<files; i++)
+ conn->m_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 <windows.h>
+#include <winsock2.h>
+
+#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 <prsht.h>
+
+#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 <fstream>
+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
|