summaryrefslogtreecommitdiff
path: root/protocols/EmLanProto
diff options
context:
space:
mode:
authorRozhuk Ivan <rozhuk.im@gmail.com>2014-11-25 16:54:27 +0000
committerRozhuk Ivan <rozhuk.im@gmail.com>2014-11-25 16:54:27 +0000
commiteeeccf7d250ecee33e0fa306906dffdc43ddf09a (patch)
treed95046d069fb6061b3bddc860a00af0458acb02e /protocols/EmLanProto
parent9b048d56368949c544bdf6e85489405a5fd99ace (diff)
EmLanProto fix, need for review.
git-svn-id: http://svn.miranda-ng.org/main/trunk@11063 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'protocols/EmLanProto')
-rw-r--r--protocols/EmLanProto/src/mlan.cpp3460
1 files changed, 1730 insertions, 1730 deletions
diff --git a/protocols/EmLanProto/src/mlan.cpp b/protocols/EmLanProto/src/mlan.cpp
index 539c82bf97..669f873090 100644
--- a/protocols/EmLanProto/src/mlan.cpp
+++ b/protocols/EmLanProto/src/mlan.cpp
@@ -1,1730 +1,1730 @@
-//////////////////////////////////////////////////////////////////////////
-// Miranda lan functions
-
-#include "stdafx.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()
-{
- for (MCONTACT hContact = db_find_first(PROTONAME); hContact; hContact = db_find_next(hContact, PROTONAME)) {
- db_set_w(hContact, PROTONAME, "Status", ID_STATUS_OFFLINE);
- db_unset(hContact, PROTONAME, "IP");
- }
- 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;
- MCONTACT hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false);
- if (hContact)
- {
- db_set_w(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;
-}
-
-MCONTACT CMLan::FindContact(in_addr addr, const char* nick, bool add_to_list, bool make_permanent, bool make_visible, u_int status)
-{
- for (MCONTACT res = db_find_first(PROTONAME); res; res = db_find_next(res, PROTONAME)) {
- u_long caddr = db_get_dw(res, PROTONAME, "ipaddr", -1);
- if (caddr==addr.S_un.S_addr) {
- if (make_permanent)
- db_unset(res,"CList","NotOnList");
- if (make_visible)
- db_unset(res,"CList","Hidden");
- return res;
- }
- }
-
- if (add_to_list) {
- MCONTACT res=(MCONTACT)CallService(MS_DB_CONTACT_ADD,0,0);
- CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)res,(LPARAM)PROTONAME);
- db_set_dw(res,PROTONAME, "ipaddr", addr.S_un.S_addr);
- db_set_s(res,PROTONAME, "Nick", nick);
-
- if (!make_permanent)
- db_set_b(res,"CList","NotOnList",1);
- if (!make_visible)
- db_set_b(res,"CList","Hidden",1);
-
- db_set_w(res,PROTONAME, "Status", status);
- return res;
- }
-
- return NULL;
-}
-
-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;
- MCONTACT hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false);
- if (hContact)
- {
- db_set_w(hContact,PROTONAME, "Status", cont->m_status);
- if (db_get_dw(hContact,PROTONAME, "RemoteVersion", 0)!=cont->m_ver)
- db_set_dw(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);
- db_set_dw(hContact, PROTONAME, "IP", tip);
-// HOSTENT* host = gethostbyaddr((const char*)&rip, sizeof(rip), AF_INET);
-// if (host)
-// db_set_s(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
- {
- PROTORECVEVENT pre = { 0 };
- pre.timestamp = get_time();
- pre.szMessage = pak.strMessage;
- ProtoChainRecv( FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status),
- pak.flIsUrl ? PSR_URL : PSR_MESSAGE, 0, (LPARAM)&pre );
-
- TPacket npak;
- ZeroMemory(&npak, sizeof(npak));
- npak.idAckMessage = pak.idMessage;
- npak.flIsUrl = pak.flIsUrl;
- SendPacketExt(npak, from.S_un.S_addr);
- }
- }
-
- if (pak.idAckMessage)
- {
- MCONTACT 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)
- {
- PROTORECVEVENT pre = { 0 };
- pre.timestamp = get_time();
- pre.szMessage = pak.strAwayMessage;
- pre.lParam = pak.idAckAwayMessage;
- ProtoChainRecv( FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status), PSR_AWAYMSG, 0, (LPARAM)&pre);
- }
-
- if (pak.idReqAwayMessage && cont)
- {
- MCONTACT 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
-// db_set_dw(hContact, "ICQ", "UIN", 1/*0xffffffff*/);
-// NotifyEventHooks(m_hookIcqMsgReq, IcqStatus, 1/*0xffffffff*/);
-// db_unset(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);
- }
- }
- }
- LeaveCriticalSection(&m_csReceiveThreadLock);
-}
-
-void CMLan::RecvMessageUrl(CCSDATA* ccs)
-{
- DBEVENTINFO dbei;
- PROTORECVEVENT *pre=(PROTORECVEVENT*)ccs->lParam;
-
- ZeroMemory(&dbei,sizeof(dbei));
-
- if (!lstrcmpA(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 (!lstrcmpA(ccs->szProtoService, PSR_URL))
- {
- dbei.cbBlob += 2+lstrlen(pre->szMessage+dbei.cbBlob+1);
- }
- dbei.pBlob = (PBYTE)pre->szMessage;
-
- db_unset(ccs->hContact,"CList","Hidden");
-
- db_event_add(ccs->hContact, &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;
-
- MCONTACT contact = FindContact(addr, psr->hdr.nick, true, !TempAdd, !TempAdd, psr->stat);
- if (contact != NULL) {
- db_set_w(contact,PROTONAME,"Status", psr->stat );
- db_set_w(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::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 (db_get_w((MCONTACT)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((MCONTACT)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((MCONTACT)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 = __FILEVERSION_DWORD;
- 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 ( db_get_s(NULL, PROTONAME, "Nick", &dbv)) {
- if (db_get_s(NULL, PROTONAME, "Name", &dbv))
- dbv.pszVal = "EmLan_User";
- else
- db_unset(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()
-{
- db_set_dw(NULL, PROTONAME, "ipaddr", m_RequiredIp);
- db_set_b(NULL, PROTONAME, "UseHostName", m_UseHostName);
- db_set_s(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();
- 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)
-{
- PROTORECVEVENT *pre = (PROTORECVEVENT *)ccs->lParam;
- char *szDesc, *szFile;
-
- db_unset(ccs->hContact, "CList", "Hidden");
-
- szFile = pre->szMessage + sizeof(DWORD);
- szDesc = szFile + strlen(szFile) + 1;
-
- DBEVENTINFO dbei = { 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;
- db_event_add(ccs->hContact, &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);
-
- 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 = FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status);
- pre.flags = 0;
- pre.timestamp = get_time();
- pre.lParam = 0;
- ProtoChainRecv(conn->m_hContact, PSR_FILE, 0, (LPARAM)&pre);
-
- 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;
-}
+//////////////////////////////////////////////////////////////////////////
+// Miranda lan functions
+
+#include "stdafx.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()
+{
+ for (MCONTACT hContact = db_find_first(PROTONAME); hContact; hContact = db_find_next(hContact, PROTONAME)) {
+ db_set_w(hContact, PROTONAME, "Status", ID_STATUS_OFFLINE);
+ db_unset(hContact, PROTONAME, "IP");
+ }
+ 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;
+ MCONTACT hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false);
+ if (hContact)
+ {
+ db_set_w(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;
+}
+
+MCONTACT CMLan::FindContact(in_addr addr, const char* nick, bool add_to_list, bool make_permanent, bool make_visible, u_int status)
+{
+ for (MCONTACT res = db_find_first(PROTONAME); res; res = db_find_next(res, PROTONAME)) {
+ u_long caddr = db_get_dw(res, PROTONAME, "ipaddr", -1);
+ if (caddr==addr.S_un.S_addr) {
+ if (make_permanent)
+ db_unset(res,"CList","NotOnList");
+ if (make_visible)
+ db_unset(res,"CList","Hidden");
+ return res;
+ }
+ }
+
+ if (add_to_list) {
+ MCONTACT res=(MCONTACT)CallService(MS_DB_CONTACT_ADD,0,0);
+ CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)res,(LPARAM)PROTONAME);
+ db_set_dw(res,PROTONAME, "ipaddr", addr.S_un.S_addr);
+ db_set_s(res,PROTONAME, "Nick", nick);
+
+ if (!make_permanent)
+ db_set_b(res,"CList","NotOnList",1);
+ if (!make_visible)
+ db_set_b(res,"CList","Hidden",1);
+
+ db_set_w(res,PROTONAME, "Status", status);
+ return res;
+ }
+
+ return NULL;
+}
+
+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;
+ MCONTACT hContact = FindContact(cont->m_addr, cont->m_nick, false, false, false);
+ if (hContact)
+ {
+ db_set_w(hContact,PROTONAME, "Status", cont->m_status);
+ if (db_get_dw(hContact,PROTONAME, "RemoteVersion", 0)!=cont->m_ver)
+ db_set_dw(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);
+ db_set_dw(hContact, PROTONAME, "IP", tip);
+// HOSTENT* host = gethostbyaddr((const char*)&rip, sizeof(rip), AF_INET);
+// if (host)
+// db_set_s(hContact, PROTONAME, "UID", host->h_name);
+ }
+ }
+ LeaveCriticalSection(&m_csAccessClass);
+ }
+ if (pak.flReqStatus)
+ RequestStatus(false, from.S_un.S_addr);
+
+ if (pak.strMessage)
+ {
+ if (!cont)
+ RequestStatus(true, from.S_un.S_addr);
+ else
+ {
+ PROTORECVEVENT pre = { 0 };
+ pre.timestamp = get_time();
+ pre.szMessage = pak.strMessage;
+ ProtoChainRecv( FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status),
+ pak.flIsUrl ? PSR_URL : PSR_MESSAGE, 0, (LPARAM)&pre );
+
+ TPacket npak;
+ ZeroMemory(&npak, sizeof(npak));
+ npak.idAckMessage = pak.idMessage;
+ npak.flIsUrl = pak.flIsUrl;
+ SendPacketExt(npak, from.S_un.S_addr);
+ }
+ }
+
+ if (pak.idAckMessage && cont)
+ {
+ MCONTACT 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)
+ {
+ PROTORECVEVENT pre = { 0 };
+ pre.timestamp = get_time();
+ pre.szMessage = pak.strAwayMessage;
+ pre.lParam = pak.idAckAwayMessage;
+ ProtoChainRecv( FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status), PSR_AWAYMSG, 0, (LPARAM)&pre);
+ }
+
+ if (pak.idReqAwayMessage && cont)
+ {
+ MCONTACT 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
+// db_set_dw(hContact, "ICQ", "UIN", 1/*0xffffffff*/);
+// NotifyEventHooks(m_hookIcqMsgReq, IcqStatus, 1/*0xffffffff*/);
+// db_unset(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);
+ }
+ }
+ }
+ LeaveCriticalSection(&m_csReceiveThreadLock);
+}
+
+void CMLan::RecvMessageUrl(CCSDATA* ccs)
+{
+ DBEVENTINFO dbei;
+ PROTORECVEVENT *pre=(PROTORECVEVENT*)ccs->lParam;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+
+ if (!lstrcmpA(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 (!lstrcmpA(ccs->szProtoService, PSR_URL))
+ {
+ dbei.cbBlob += 2+lstrlen(pre->szMessage+dbei.cbBlob+1);
+ }
+ dbei.pBlob = (PBYTE)pre->szMessage;
+
+ db_unset(ccs->hContact,"CList","Hidden");
+
+ db_event_add(ccs->hContact, &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;
+
+ MCONTACT contact = FindContact(addr, psr->hdr.nick, true, !TempAdd, !TempAdd, psr->stat);
+ if (contact != NULL) {
+ db_set_w(contact,PROTONAME,"Status", psr->stat );
+ db_set_w(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::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 (db_get_w((MCONTACT)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((MCONTACT)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((MCONTACT)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 = __FILEVERSION_DWORD;
+ 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 ( db_get_s(NULL, PROTONAME, "Nick", &dbv)) {
+ if (db_get_s(NULL, PROTONAME, "Name", &dbv))
+ dbv.pszVal = "EmLan_User";
+ else
+ db_unset(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()
+{
+ db_set_dw(NULL, PROTONAME, "ipaddr", m_RequiredIp);
+ db_set_b(NULL, PROTONAME, "UseHostName", m_UseHostName);
+ db_set_s(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();
+ 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)
+{
+ PROTORECVEVENT *pre = (PROTORECVEVENT *)ccs->lParam;
+ char *szDesc, *szFile;
+
+ db_unset(ccs->hContact, "CList", "Hidden");
+
+ szFile = pre->szMessage + sizeof(DWORD);
+ szDesc = szFile + strlen(szFile) + 1;
+
+ DBEVENTINFO dbei = { 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;
+ db_event_add(ccs->hContact, &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);
+
+ 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 = FindContact(cont->m_addr, cont->m_nick, true, false, false, cont->m_status);
+ pre.flags = 0;
+ pre.timestamp = get_time();
+ pre.lParam = 0;
+ ProtoChainRecv(conn->m_hContact, PSR_FILE, 0, (LPARAM)&pre);
+
+ 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;
+}