diff options
author | Rozhuk Ivan <rozhuk.im@gmail.com> | 2014-11-25 16:54:27 +0000 |
---|---|---|
committer | Rozhuk Ivan <rozhuk.im@gmail.com> | 2014-11-25 16:54:27 +0000 |
commit | eeeccf7d250ecee33e0fa306906dffdc43ddf09a (patch) | |
tree | d95046d069fb6061b3bddc860a00af0458acb02e /protocols/EmLanProto | |
parent | 9b048d56368949c544bdf6e85489405a5fd99ace (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.cpp | 3460 |
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; +} |