From eeeccf7d250ecee33e0fa306906dffdc43ddf09a Mon Sep 17 00:00:00 2001 From: Rozhuk Ivan Date: Tue, 25 Nov 2014 16:54:27 +0000 Subject: EmLanProto fix, need for review. git-svn-id: http://svn.miranda-ng.org/main/trunk@11063 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/EmLanProto/src/mlan.cpp | 3460 ++++++++++++++++++------------------- 1 file changed, 1730 insertions(+), 1730 deletions(-) (limited to 'protocols/EmLanProto/src') 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 && bufFileRemoveFromList(this); - } - delete[] m_szDescription; - if (m_szFiles) - { - char** cp = m_szFiles; - while (*cp) - { - delete[] *cp; - cp++; - } - delete[] m_szFiles; - } - - delete[] m_buf; - delete[] m_szDir; - delete[] m_szRenamedFile; - DeleteCriticalSection(&m_csAccess); -} - -int CMLan::TFileConnection::Recv(bool halt) -{ - // It is supposed that we're having not less then 2 bytes buffer size :) - EMLOG("Checking for data"); - while (1) - { - u_long len; - if (ioctlsocket(m_socket, FIONREAD, &len)!=0) - { - EMLOGERR(); - return FCS_TERMINATE; - } - if (len>=3) - break; - if (!halt) - { - EMLOG("No data - halting Recv (only " << len << " bytes)"); - m_recSize = -1; - delete[] m_buf; - m_buf = NULL; - return FCS_OK; - } - Sleep(10); - if (m_state==FCS_TERMINATE) - { - EMLOG("Terminate requested, exiting recv"); - return FCS_TERMINATE; - } - } - - u_short size; - int res; - EMLOG("Receiving packet size"); - res = recv(m_socket, (char*)&size, 3, 0); - if (res==SOCKET_ERROR) - { - EMLOGERR(); - return FCS_TERMINATE; - } - if (size==0) - { - EMLOG("Connection was gracefully closed - size is 0"); - delete m_buf; - m_buf = NULL; - m_recSize = 0; - return FCS_OK; - } - - Lock(); - delete[] m_buf; - m_buf = new u_char[size]; - m_recSize = size; - Unlock(); - - EMLOG("Waiting for the whole packet (" << size << " bytes)"); - int csize = 0; - while (csize!=size) - { - while(1) - { - u_long len; - if (ioctlsocket(m_socket, FIONREAD, &len) != 0) { - EMLOGERR(); - return FCS_TERMINATE; - } - if (len >= min(size,FILE_MIN_BLOCK)) - break; - Sleep(10); - if (m_state == FCS_TERMINATE) { - EMLOG("Terminate requested, exiting recv"); - return FCS_TERMINATE; - } - } - EMLOG("Getting data (approx " << size << " bytes)"); - Lock(); - res = recv(m_socket, (char*)m_buf+csize, size-csize, 0); - Unlock(); - EMLOGERR(); - 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; im_szFiles[i] = _strdup(pf_fr); - if (i) - *pf_to++ = ' '; - while (*pf_fr) - *pf_to++ = *pf_fr++; - pf_fr++; - *pf_to++ = ';'; - } - *pf_to++ = 0; - - while (*pf_fr) - *pf_to++ = *pf_fr++; - *pf_to++ = *pf_fr++; - - conn->m_hContact = 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; fileNoRecv() || conn->m_recSize==0 || conn->m_buf[0] != FCODE_SND_NEXTFILE) - { - err = true; - break; - } - EMLOG("Ok"); - - fts.szCurrentFile = fts.pszFiles[fileNo]; - fts.currentFileNumber = fileNo; - fts.currentFileProgress = 0; - fts.currentFileSize = *((int*)(conn->m_buf+1)); - fts.currentFileTime = get_time(); - - EMLOG("Waiting for ACCEPT"); - if (!ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (HANDLE)conn->m_cid, (LPARAM)&fts)) - { - conn->Lock(); - conn->m_state = TFileConnection::FCS_OVERWRITE; - conn->Unlock(); - } - else - { - while(!conn->m_state) - Sleep(10); - } - EMLOG("Ok"); - EMLOG("Checking if we're terminated"); - if (conn->m_state==TFileConnection::FCS_TERMINATE) - { - err = true; - break; - } - EMLOG("Still working"); - - u_char snd_buf[5]; - - EMLOG("Checking if we're skipping file"); - if (conn->m_state==TFileConnection::FCS_SKIP) - { - EMLOG("Skipped"); - conn->Lock(); - conn->m_state = TFileConnection::FCS_OK; - conn->Unlock(); - snd_buf[0] = FCODE_SND_FILESKIP; - if (conn->Send(snd_buf, 1)) - { - EMLOG("Error during sending 'skip' code'"); - err = true; - break; - } - continue; - } - EMLOG("Still processing"); - - char* filename = conn->m_szRenamedFile; - if (!filename) - filename = conn->m_szFiles[fileNo]; - - int mode_open = CREATE_ALWAYS; - if (conn->m_state==TFileConnection::FCS_RESUME) - mode_open = OPEN_ALWAYS; - - conn->Lock(); - conn->m_state = TFileConnection::FCS_OK; - conn->Unlock(); - - EMLOG("Creating file"); - HANDLE hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, mode_open, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile==INVALID_HANDLE_VALUE) - { - EMLOG("Can't create file"); - conn->Send(NULL, 0); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't create file"); - delete conn; - return; - } - EMLOG("Ok"); - - snd_buf[0] = FCODE_SND_ACCEPT; - int fsize = GetFileSize(hFile, NULL); - *((int*)(snd_buf+1)) = fsize; - SetFilePointer(hFile, 0, NULL, FILE_END); - - fts.currentFileProgress = fsize; - fts.totalProgress += fsize; - - EMLOG("Sending ack"); - if (conn->Send(snd_buf, 5)) - { - EMLOG("Error sending ACK"); - CloseHandle(hFile); - err = true; - break; - } - EMLOG("Ok"); - - EMLOG("Broadcast ack internally"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); - EMLOG("Ok"); - int refr = 0; - while (fts.currentFileProgressRecv(); - if (isErr || conn->m_recSize==0 || conn->m_buf[0]!=FCODE_SND_FILEDATA) - { - EMLOGIF("Error conn->Recv()", isErr); - EMLOGIF("Error conn->m_recSize!=0", conn->m_recSize==0); - EMLOGIF("Error conn->m_buf[0]==FCODE_SND_FILEDATA", conn->m_buf[0]!=FCODE_SND_FILEDATA); - EMLOG("Error"); - err = true; - break; - } - EMLOG("Received"); - DWORD written; - EMLOG("Writing to file"); - WriteFile(hFile, conn->m_buf+1, conn->m_recSize-1, &written, NULL); - EMLOG("Ok"); - fts.currentFileProgress += conn->m_recSize-1; - fts.totalProgress += conn->m_recSize-1; - refr += conn->m_recSize-1; - if (refr>=FILE_INFO_REFRESH) - { - EMLOG("Refreshing progress bar"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); - refr = 0; - } - } - if (!err) - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); - - EMLOG("Closing file handle"); - CloseHandle(hFile); - - if (err) - break; - - delete[] conn->m_szRenamedFile; - conn->m_szRenamedFile = NULL; - } - - if (err) - { - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); - delete conn; - return; - } - - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)conn->m_cid, 0); - - delete conn; -} - -void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParameter) -{ - EMLOG("Sending OUT TCP connection"); - TFileConnection* conn = (TFileConnection*)lpParameter; - - if (out_socket == INVALID_SOCKET) - { - EMLOG("Can't create OUT socket"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't initiate transfer"); - delete conn; - return; - } - conn->m_socket = out_socket; - EMLOG("Socket is created"); - - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)conn->m_cid, 0); - - EMLOG("Added to list"); - FileAddToList(conn); - - u_char buf[FILE_SEND_BLOCK+1]; - char name[MAX_PATH+8]; - - buf[0] = FCODE_SND_FILEREQ; - int len = 1+4+4; - int size = 0; - int filecount = 0; - char** pf = conn->m_szFiles; - while (*pf) - { - // TODO: FIX IT ! - EMLOG("Opening file"); - HANDLE hFile = CreateFile(*pf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); - if (hFile==INVALID_HANDLE_VALUE) - { - EMLOG("Can't open file for reading"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open one of the files"); - delete conn; - return; - } - size += GetFileSize(hFile, NULL); - filecount++; - CloseHandle(hFile); - - char* filepart; - GetFullPathName(*pf, MAX_PATH, (char*)name, &filepart); - delete[] *pf; - *pf = _strdup(name); - strcpy((char*)buf+len, filepart); - len += (int)strlen(filepart)+1; - - pf++; - } - strcpy((char*)buf+len, conn->m_szDescription); - len += (int)strlen(conn->m_szDescription)+1; - - *((int*)(buf+1)) = size; - *((int*)(buf+1+4)) = filecount; - - GetCurrentDirectory(MAX_PATH, name); - conn->m_szDir = _strdup(name); - - PROTOFILETRANSFERSTATUS fts; - fts.cbSize = sizeof(fts); - fts.totalBytes = size; - fts.totalFiles = filecount; - fts.totalProgress = 0; - fts.szWorkingDir = conn->m_szDir; - fts.flags = PFTS_SENDING; - fts.hContact = conn->m_hContact; - fts.pszFiles = conn->m_szFiles; - - EMLOG("Sending file size"); - if (conn->Send(buf, len)) - { - EMLOG("Failed"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); - delete conn; - return; - } - - EMLOG("Waiting for ACK"); - if (conn->Recv() || conn->m_recSize==0 || conn->m_buf[0]!=FCODE_SND_ACCEPT) - { - EMLOG("Failed"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)conn->m_cid, 0); - delete conn; - return; - } - - bool err = false; - - for (int fileNo=0; fileNom_szFiles[fileNo] , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile==INVALID_HANDLE_VALUE) - { - EMLOG("Failed"); - conn->Send(NULL, 0); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open file"); - delete conn; - return; - } - - EMLOG("Sending broadcast NEXT FILE"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)conn->m_cid, 0); - EMLOG("Ok"); - - u_char snd_buf[5]; - snd_buf[0] = FCODE_SND_NEXTFILE; - int fsize = GetFileSize(hFile, NULL); - *((int*)(snd_buf+1)) = fsize; - EMLOG("Sending file size"); - if (conn->Send(snd_buf, 5)) - { - CloseHandle(hFile); - err = true; - break; - } - EMLOG("Ok"); - - EMLOG("Waiting for ACK"); - if (conn->Recv() || conn->m_recSize==0 || (conn->m_buf[0]!=FCODE_SND_ACCEPT && conn->m_buf[0]!=FCODE_SND_FILESKIP)) - { - CloseHandle(hFile); - err = true; - break; - } - EMLOG("Ok"); - - if (conn->m_buf[0]!=FCODE_SND_FILESKIP) - { - EMLOG("File is not skipped"); - int filepos = *((int*)(conn->m_buf+1)); - SetFilePointer(hFile, filepos, NULL, FILE_BEGIN); - - fts.szCurrentFile = fts.pszFiles[fileNo]; - fts.currentFileTime = get_time(); - fts.currentFileNumber = fileNo; - fts.currentFileProgress = filepos; - fts.totalProgress += filepos; - fts.currentFileSize = fsize; - EMLOG("Starting data transfer"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); - EMLOG("Ok"); - int refr = 0; - - fsize -= filepos; - - while (fsize>0) - { - DWORD readbytes; - int tosend = FILE_SEND_BLOCK; - if (tosend>fsize) - tosend = fsize; - EMLOG("Reading file data"); - ReadFile(hFile, buf+1, tosend, &readbytes, NULL); - EMLOG("Ok"); - buf[0] = FCODE_SND_FILEDATA; - - if (readbytes!=tosend) - { - EMLOG("Error during reading file. File was changed"); - CloseHandle(hFile); - conn->Send(NULL, 0); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't read file"); - delete conn; - return; - } - EMLOG("Sending data buffer"); - if (conn->Send(buf, tosend+1)) - { - //CloseHandle(hFile); - err = true; - break; - } - EMLOG("Ok"); - - fts.currentFileProgress += tosend; - fts.totalProgress += tosend; - fsize -= tosend; - refr += tosend; - if (refr>=FILE_INFO_REFRESH || fsize<=0) - { - EMLOG("Refreshing file info"); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); - refr = 0; - EMLOG("Checking for 'abort'"); - if (conn->Recv(false) || conn->m_recSize!=-1) - { - EMLOG("Aborted"); - //CloseHandle(hFile); - err = true; - break; - } - EMLOG("Ok"); - } - - if (conn->m_state) - { - EMLOG("Interrupted by user"); - conn->Send(NULL, 0); - //CloseHandle(hFile); - err = true; - break; - } - } - } - if (err) - break; - CloseHandle(hFile); - } - - if (err) - { - EMLOG("There was error during file transfering"); - conn->Send(NULL, 0); - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); - delete conn; - return; - } - - ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)conn->m_cid, 0); - - delete conn; -} - -int CMLan::SendFile(CCSDATA* ccs) -{ - int cid = GetRandomProcId(); - - TFileConnection* conn = new TFileConnection(); - conn->m_cid = cid; - conn->m_hContact = ccs->hContact; - - conn->m_szDescription = _strdup((char*)ccs->wParam); - int files = 0; - char** ppszFiles = (char**)ccs->lParam; - while (ppszFiles[files]) - files++; - conn->m_szFiles = new char* [files+1]; - for (int i=0; im_szFiles[i] = _strdup(ppszFiles[i]); - conn->m_szFiles[files] = NULL; - - u_long addr = db_get_dw(ccs->hContact, PROTONAME, "ipaddr", 0); - CreateTCPConnection(addr, (LPVOID)conn); - - return cid; -} - -int CMLan::FileAllow(CCSDATA* ccs) -{ - int cid = (int)ccs->wParam; - TFileConnection* conn = m_pFileConnectionList; - while (conn) - { - if (conn->m_cid == cid) - break; - conn = conn->m_pNext; - } - if (!conn) - return 0; - - conn->Lock(); - conn->m_state = TFileConnection::FCS_ALLOW; - conn->m_szDir = _strdup((char*)ccs->lParam); - conn->Unlock(); - return cid; -} - -int CMLan::FileDeny(CCSDATA* ccs) -{ - int cid = (int)ccs->wParam; - TFileConnection* conn = m_pFileConnectionList; - while (conn) - { - if (conn->m_cid == cid) - break; - conn = conn->m_pNext; - } - if (!conn) - return 0; - - conn->Lock(); - conn->m_state = TFileConnection::FCS_TERMINATE; - conn->Unlock(); - return 0; -} - -int CMLan::FileCancel(CCSDATA* ccs) -{ - int cid = (int)ccs->wParam; - TFileConnection* conn = m_pFileConnectionList; - while (conn) - { - if (conn->m_cid == cid) - break; - conn = conn->m_pNext; - } - if (!conn) - return 0; - - conn->Lock(); - conn->m_state = TFileConnection::FCS_TERMINATE; - conn->Unlock(); - return 0; -} - -int CMLan::FileResume(int cid, PROTOFILERESUME* pfr) -{ - //int cid = (int)ccs->wParam; - //PROTOFILERESUME* pfr = (PROTOFILERESUME*)ccs->lParam; - - TFileConnection* conn = m_pFileConnectionList; - while (conn) - { - if (conn->m_cid == cid) - break; - conn = conn->m_pNext; - } - if (!conn) - return 0; - - conn->Lock(); - switch (pfr->action) - { - case FILERESUME_OVERWRITE: - conn->m_state = TFileConnection::FCS_OVERWRITE; - break; - case FILERESUME_RESUME: - conn->m_state = TFileConnection::FCS_RESUME; - break; - case FILERESUME_RENAME: - conn->m_state = TFileConnection::FCS_RENAME; - delete[] conn->m_szRenamedFile; - conn->m_szRenamedFile = _strdup(pfr->szFilename); - break; - case FILERESUME_SKIP: - conn->m_state = TFileConnection::FCS_SKIP; - break; - } - conn->Unlock(); - - return 0; -} +////////////////////////////////////////////////////////////////////////// +// 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 && bufFileRemoveFromList(this); + } + delete[] m_szDescription; + if (m_szFiles) + { + char** cp = m_szFiles; + while (*cp) + { + delete[] *cp; + cp++; + } + delete[] m_szFiles; + } + + delete[] m_buf; + delete[] m_szDir; + delete[] m_szRenamedFile; + DeleteCriticalSection(&m_csAccess); +} + +int CMLan::TFileConnection::Recv(bool halt) +{ + // It is supposed that we're having not less then 2 bytes buffer size :) + EMLOG("Checking for data"); + while (1) + { + u_long len; + if (ioctlsocket(m_socket, FIONREAD, &len)!=0) + { + EMLOGERR(); + return FCS_TERMINATE; + } + if (len>=3) + break; + if (!halt) + { + EMLOG("No data - halting Recv (only " << len << " bytes)"); + m_recSize = -1; + delete[] m_buf; + m_buf = NULL; + return FCS_OK; + } + Sleep(10); + if (m_state==FCS_TERMINATE) + { + EMLOG("Terminate requested, exiting recv"); + return FCS_TERMINATE; + } + } + + u_short size; + int res; + EMLOG("Receiving packet size"); + res = recv(m_socket, (char*)&size, 3, 0); + if (res==SOCKET_ERROR) + { + EMLOGERR(); + return FCS_TERMINATE; + } + if (size==0) + { + EMLOG("Connection was gracefully closed - size is 0"); + delete m_buf; + m_buf = NULL; + m_recSize = 0; + return FCS_OK; + } + + Lock(); + delete[] m_buf; + m_buf = new u_char[size]; + m_recSize = size; + Unlock(); + + EMLOG("Waiting for the whole packet (" << size << " bytes)"); + int csize = 0; + while (csize!=size) + { + while(1) + { + u_long len; + if (ioctlsocket(m_socket, FIONREAD, &len) != 0) { + EMLOGERR(); + return FCS_TERMINATE; + } + if (len >= min(size,FILE_MIN_BLOCK)) + break; + Sleep(10); + if (m_state == FCS_TERMINATE) { + EMLOG("Terminate requested, exiting recv"); + return FCS_TERMINATE; + } + } + EMLOG("Getting data (approx " << size << " bytes)"); + Lock(); + res = recv(m_socket, (char*)m_buf+csize, size-csize, 0); + Unlock(); + EMLOGERR(); + 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; im_szFiles[i] = _strdup(pf_fr); + if (i) + *pf_to++ = ' '; + while (*pf_fr) + *pf_to++ = *pf_fr++; + pf_fr++; + *pf_to++ = ';'; + } + *pf_to++ = 0; + + while (*pf_fr) + *pf_to++ = *pf_fr++; + *pf_to++ = *pf_fr++; + + conn->m_hContact = 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; fileNoRecv() || conn->m_recSize==0 || conn->m_buf[0] != FCODE_SND_NEXTFILE) + { + err = true; + break; + } + EMLOG("Ok"); + + fts.szCurrentFile = fts.pszFiles[fileNo]; + fts.currentFileNumber = fileNo; + fts.currentFileProgress = 0; + fts.currentFileSize = *((int*)(conn->m_buf+1)); + fts.currentFileTime = get_time(); + + EMLOG("Waiting for ACCEPT"); + if (!ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, (HANDLE)conn->m_cid, (LPARAM)&fts)) + { + conn->Lock(); + conn->m_state = TFileConnection::FCS_OVERWRITE; + conn->Unlock(); + } + else + { + while(!conn->m_state) + Sleep(10); + } + EMLOG("Ok"); + EMLOG("Checking if we're terminated"); + if (conn->m_state==TFileConnection::FCS_TERMINATE) + { + err = true; + break; + } + EMLOG("Still working"); + + u_char snd_buf[5]; + + EMLOG("Checking if we're skipping file"); + if (conn->m_state==TFileConnection::FCS_SKIP) + { + EMLOG("Skipped"); + conn->Lock(); + conn->m_state = TFileConnection::FCS_OK; + conn->Unlock(); + snd_buf[0] = FCODE_SND_FILESKIP; + if (conn->Send(snd_buf, 1)) + { + EMLOG("Error during sending 'skip' code'"); + err = true; + break; + } + continue; + } + EMLOG("Still processing"); + + char* filename = conn->m_szRenamedFile; + if (!filename) + filename = conn->m_szFiles[fileNo]; + + int mode_open = CREATE_ALWAYS; + if (conn->m_state==TFileConnection::FCS_RESUME) + mode_open = OPEN_ALWAYS; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_OK; + conn->Unlock(); + + EMLOG("Creating file"); + HANDLE hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, mode_open, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + EMLOG("Can't create file"); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't create file"); + delete conn; + return; + } + EMLOG("Ok"); + + snd_buf[0] = FCODE_SND_ACCEPT; + int fsize = GetFileSize(hFile, NULL); + *((int*)(snd_buf+1)) = fsize; + SetFilePointer(hFile, 0, NULL, FILE_END); + + fts.currentFileProgress = fsize; + fts.totalProgress += fsize; + + EMLOG("Sending ack"); + if (conn->Send(snd_buf, 5)) + { + EMLOG("Error sending ACK"); + CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + EMLOG("Broadcast ack internally"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + EMLOG("Ok"); + int refr = 0; + while (fts.currentFileProgressRecv(); + if (isErr || conn->m_recSize==0 || conn->m_buf[0]!=FCODE_SND_FILEDATA) + { + EMLOGIF("Error conn->Recv()", isErr); + EMLOGIF("Error conn->m_recSize!=0", conn->m_recSize==0); + EMLOGIF("Error conn->m_buf[0]==FCODE_SND_FILEDATA", conn->m_buf[0]!=FCODE_SND_FILEDATA); + EMLOG("Error"); + err = true; + break; + } + EMLOG("Received"); + DWORD written; + EMLOG("Writing to file"); + WriteFile(hFile, conn->m_buf+1, conn->m_recSize-1, &written, NULL); + EMLOG("Ok"); + fts.currentFileProgress += conn->m_recSize-1; + fts.totalProgress += conn->m_recSize-1; + refr += conn->m_recSize-1; + if (refr>=FILE_INFO_REFRESH) + { + EMLOG("Refreshing progress bar"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + refr = 0; + } + } + if (!err) + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + + EMLOG("Closing file handle"); + CloseHandle(hFile); + + if (err) + break; + + delete[] conn->m_szRenamedFile; + conn->m_szRenamedFile = NULL; + } + + if (err) + { + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)conn->m_cid, 0); + + delete conn; +} + +void CMLan::OnOutTCPConnection(u_long addr, SOCKET out_socket, LPVOID lpParameter) +{ + EMLOG("Sending OUT TCP connection"); + TFileConnection* conn = (TFileConnection*)lpParameter; + + if (out_socket == INVALID_SOCKET) + { + EMLOG("Can't create OUT socket"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't initiate transfer"); + delete conn; + return; + } + conn->m_socket = out_socket; + EMLOG("Socket is created"); + + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_CONNECTED, (HANDLE)conn->m_cid, 0); + + EMLOG("Added to list"); + FileAddToList(conn); + + u_char buf[FILE_SEND_BLOCK+1]; + char name[MAX_PATH+8]; + + buf[0] = FCODE_SND_FILEREQ; + int len = 1+4+4; + int size = 0; + int filecount = 0; + char** pf = conn->m_szFiles; + while (*pf) + { + // TODO: FIX IT ! + EMLOG("Opening file"); + HANDLE hFile = CreateFile(*pf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + EMLOG("Can't open file for reading"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open one of the files"); + delete conn; + return; + } + size += GetFileSize(hFile, NULL); + filecount++; + CloseHandle(hFile); + + char* filepart; + GetFullPathName(*pf, MAX_PATH, (char*)name, &filepart); + delete[] *pf; + *pf = _strdup(name); + strcpy((char*)buf+len, filepart); + len += (int)strlen(filepart)+1; + + pf++; + } + strcpy((char*)buf+len, conn->m_szDescription); + len += (int)strlen(conn->m_szDescription)+1; + + *((int*)(buf+1)) = size; + *((int*)(buf+1+4)) = filecount; + + GetCurrentDirectory(MAX_PATH, name); + conn->m_szDir = _strdup(name); + + PROTOFILETRANSFERSTATUS fts; + fts.cbSize = sizeof(fts); + fts.totalBytes = size; + fts.totalFiles = filecount; + fts.totalProgress = 0; + fts.szWorkingDir = conn->m_szDir; + fts.flags = PFTS_SENDING; + fts.hContact = conn->m_hContact; + fts.pszFiles = conn->m_szFiles; + + EMLOG("Sending file size"); + if (conn->Send(buf, len)) + { + EMLOG("Failed"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + EMLOG("Waiting for ACK"); + if (conn->Recv() || conn->m_recSize==0 || conn->m_buf[0]!=FCODE_SND_ACCEPT) + { + EMLOG("Failed"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DENIED, (HANDLE)conn->m_cid, 0); + delete conn; + return; + } + + bool err = false; + + for (int fileNo=0; fileNom_szFiles[fileNo] , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + EMLOG("Failed"); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't open file"); + delete conn; + return; + } + + EMLOG("Sending broadcast NEXT FILE"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, (HANDLE)conn->m_cid, 0); + EMLOG("Ok"); + + u_char snd_buf[5]; + snd_buf[0] = FCODE_SND_NEXTFILE; + int fsize = GetFileSize(hFile, NULL); + *((int*)(snd_buf+1)) = fsize; + EMLOG("Sending file size"); + if (conn->Send(snd_buf, 5)) + { + CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + EMLOG("Waiting for ACK"); + if (conn->Recv() || conn->m_recSize==0 || (conn->m_buf[0]!=FCODE_SND_ACCEPT && conn->m_buf[0]!=FCODE_SND_FILESKIP)) + { + CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + if (conn->m_buf[0]!=FCODE_SND_FILESKIP) + { + EMLOG("File is not skipped"); + int filepos = *((int*)(conn->m_buf+1)); + SetFilePointer(hFile, filepos, NULL, FILE_BEGIN); + + fts.szCurrentFile = fts.pszFiles[fileNo]; + fts.currentFileTime = get_time(); + fts.currentFileNumber = fileNo; + fts.currentFileProgress = filepos; + fts.totalProgress += filepos; + fts.currentFileSize = fsize; + EMLOG("Starting data transfer"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + EMLOG("Ok"); + int refr = 0; + + fsize -= filepos; + + while (fsize>0) + { + DWORD readbytes; + int tosend = FILE_SEND_BLOCK; + if (tosend>fsize) + tosend = fsize; + EMLOG("Reading file data"); + ReadFile(hFile, buf+1, tosend, &readbytes, NULL); + EMLOG("Ok"); + buf[0] = FCODE_SND_FILEDATA; + + if (readbytes!=tosend) + { + EMLOG("Error during reading file. File was changed"); + CloseHandle(hFile); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Can't read file"); + delete conn; + return; + } + EMLOG("Sending data buffer"); + if (conn->Send(buf, tosend+1)) + { + //CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + + fts.currentFileProgress += tosend; + fts.totalProgress += tosend; + fsize -= tosend; + refr += tosend; + if (refr>=FILE_INFO_REFRESH || fsize<=0) + { + EMLOG("Refreshing file info"); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_DATA, (HANDLE)conn->m_cid, (LPARAM)&fts); + refr = 0; + EMLOG("Checking for 'abort'"); + if (conn->Recv(false) || conn->m_recSize!=-1) + { + EMLOG("Aborted"); + //CloseHandle(hFile); + err = true; + break; + } + EMLOG("Ok"); + } + + if (conn->m_state) + { + EMLOG("Interrupted by user"); + conn->Send(NULL, 0); + //CloseHandle(hFile); + err = true; + break; + } + } + } + if (err) + break; + CloseHandle(hFile); + } + + if (err) + { + EMLOG("There was error during file transfering"); + conn->Send(NULL, 0); + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_FAILED, (HANDLE)conn->m_cid, (LPARAM)"Connection aborted"); + delete conn; + return; + } + + ProtoBroadcastAck(PROTONAME, conn->m_hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, (HANDLE)conn->m_cid, 0); + + delete conn; +} + +int CMLan::SendFile(CCSDATA* ccs) +{ + int cid = GetRandomProcId(); + + TFileConnection* conn = new TFileConnection(); + conn->m_cid = cid; + conn->m_hContact = ccs->hContact; + + conn->m_szDescription = _strdup((char*)ccs->wParam); + int files = 0; + char** ppszFiles = (char**)ccs->lParam; + while (ppszFiles[files]) + files++; + conn->m_szFiles = new char* [files+1]; + for (int i=0; im_szFiles[i] = _strdup(ppszFiles[i]); + conn->m_szFiles[files] = NULL; + + u_long addr = db_get_dw(ccs->hContact, PROTONAME, "ipaddr", 0); + CreateTCPConnection(addr, (LPVOID)conn); + + return cid; +} + +int CMLan::FileAllow(CCSDATA* ccs) +{ + int cid = (int)ccs->wParam; + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_ALLOW; + conn->m_szDir = _strdup((char*)ccs->lParam); + conn->Unlock(); + return cid; +} + +int CMLan::FileDeny(CCSDATA* ccs) +{ + int cid = (int)ccs->wParam; + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_TERMINATE; + conn->Unlock(); + return 0; +} + +int CMLan::FileCancel(CCSDATA* ccs) +{ + int cid = (int)ccs->wParam; + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + conn->m_state = TFileConnection::FCS_TERMINATE; + conn->Unlock(); + return 0; +} + +int CMLan::FileResume(int cid, PROTOFILERESUME* pfr) +{ + //int cid = (int)ccs->wParam; + //PROTOFILERESUME* pfr = (PROTOFILERESUME*)ccs->lParam; + + TFileConnection* conn = m_pFileConnectionList; + while (conn) + { + if (conn->m_cid == cid) + break; + conn = conn->m_pNext; + } + if (!conn) + return 0; + + conn->Lock(); + switch (pfr->action) + { + case FILERESUME_OVERWRITE: + conn->m_state = TFileConnection::FCS_OVERWRITE; + break; + case FILERESUME_RESUME: + conn->m_state = TFileConnection::FCS_RESUME; + break; + case FILERESUME_RENAME: + conn->m_state = TFileConnection::FCS_RENAME; + delete[] conn->m_szRenamedFile; + conn->m_szRenamedFile = _strdup(pfr->szFilename); + break; + case FILERESUME_SKIP: + conn->m_state = TFileConnection::FCS_SKIP; + break; + } + conn->Unlock(); + + return 0; +} -- cgit v1.2.3