/* file: mbftRecv.cpp */

#include "mbftpch.h"

#include "mbftrecv.hpp"
#include "fileio.hpp"
#include "messages.hpp"
#include "mbftper.h"

extern TCHAR s_szMSFT[64];

extern HRESULT GetRecvFolder(LPTSTR pszInFldr, LPTSTR pszOutFldr);
extern void OnChangeFolder(void);
extern int MyLoadString(UINT idStr, LPTSTR pszDstStr, LPTSTR pszElement);

LPTSTR GetRootDirPath(LPTSTR pszDirPath, LPTSTR pszRootDirPath, int nSize);

MBFTPrivateReceive::MBFTPrivateReceive
(
    LPMBFTENGINE            lpParentEngine,
    MBFTEVENTHANDLE         EventHandle,
    T120ChannelID           wControlChannel,
    T120ChannelID           wDataChannel
)
:
    MBFTSession(lpParentEngine, EventHandle, MBFT_PRIVATE_RECV_TYPE),
    m_PrivateMBFTControlChannel(wControlChannel),
    m_PrivateMBFTDataChannel(wDataChannel),

    m_MBFTControlSenderID(0),
    m_MBFTDataSenderID(0),
    m_ProshareSenderID(0),
    m_LocalMBFTUserID(0),

    m_bProshareTransfer(FALSE),
    m_JoinedToDataChannel(FALSE),
    m_bOKToLeaveDataChannel(FALSE),
    m_CurrentReceiveEvent(NULL),

    m_bEventEndPosted(FALSE),
    m_CurrentAcceptHandle(0),
    m_CurrentRejectHandle(0),
    m_CurrentFileEndHandle(0),

    m_PreviousRejectState(EnumIdleNotInitialized),

    m_State(EnumWaitAdmitControlChannel)
{
	m_PrivateMBFTDataChannelList.Append(m_PrivateMBFTDataChannel);
}

MBFTPrivateReceive::~MBFTPrivateReceive(void)
{
    m_ReceiveList.DeleteAll();
}

void MBFTPrivateReceive::JoinControlChannel(void)
{
    if(m_lpParentEngine->MCSChannelJoinRequest(m_PrivateMBFTControlChannel))
    {
        m_State = EnumWaitJoinControlChannel;
    }
    else
    {
        m_State = EnumInitializationFailed;
    }
}

void MBFTPrivateReceive::JoinDataChannel(void)
{
    if(m_lpParentEngine->MCSChannelJoinRequest(m_PrivateMBFTDataChannel))
    {
        if(m_State == EnumWaitAdmitDataChannelIndication)
        {
            m_State = EnumWaitJoinDataChannel;
        }
    }
    else
    {
        m_State = EnumInitializationFailed;
    }
}

BOOL MBFTPrivateReceive::OnMCSChannelJoinConfirm
(
    T120ChannelID           wChannelID,
    BOOL                    bSuccess
)
{
    BOOL bReturn = FALSE;

    if(m_State == EnumWaitJoinControlChannel)
    {
        if(wChannelID == m_PrivateMBFTControlChannel)
        {
            bReturn = TRUE;

            m_State = bSuccess ? EnumWaitAdmitDataChannelIndication :
                                 EnumInitializationFailed;

            // data channel admit indication may come earlier than this state change.
            // look for unserviced channel admit indication
            if (EnumWaitAdmitDataChannelIndication == m_State)
            {
                UINT_PTR chid_uid;
                m_AdmittedChannelQueue.Reset();
                while (0 != (chid_uid = m_AdmittedChannelQueue.Iterate()))
                {
                    if (m_PrivateMBFTDataChannelList.Find(LOWORD(chid_uid)))
                    {
                        OnMCSChannelAdmitIndication(LOWORD(chid_uid), HIWORD(chid_uid));
                        m_AdmittedChannelQueue.Remove(chid_uid);
                        break;
                    }
                }
            }
        }
    }
    else if(m_State == EnumWaitJoinDataChannel || m_State == EnumWaitRejoinDataChannel)
    {
        if(m_PrivateMBFTDataChannelList.Find(wChannelID))
        {
            bReturn = TRUE;

            if(bSuccess)
            {
                m_JoinedToDataChannel = TRUE;

                if(m_State == EnumWaitJoinDataChannel)
                {
                    m_State = EnumWaitSendChannelResponsePDU;
                }
                else if(m_State == EnumWaitRejoinDataChannel)
                {
                    TRACERECEIVE(" Rejoined Data Channel [%u]\n",wChannelID);

                    if(m_CurrentReceiveEvent)
                    {
                        SendFileAcceptPDU((unsigned)m_CurrentReceiveEvent->m_hFile);
                        m_CurrentReceiveEvent->m_State = EnumWaitFileStartPDU;
                    }
                    else
                    {
                        TRACE(" *** WARNING: Receive Event deleted before Data Channel was rejoined! ***\n");
                    }

                    //m_State = EnumWaitFileOfferPDU;
                }
            }
            else
            {
                m_State = EnumInitializationFailed;
            }
        }
    }

    return(bReturn);
}

void MBFTPrivateReceive::UnInitialize
(
    BOOL            bIsShutDown
)
{
    if(m_State != EnumWaitForTermination)
    {
        m_State = EnumWaitForTermination;

        MBFTReceiveSubEvent * lpReceive;
        m_ReceiveList.Reset();
        while (NULL != (lpReceive = m_ReceiveList.Iterate()))
        {
            if(!lpReceive->m_UserAccepted)
            {
                lpReceive->m_lpFile->DeleteFile();
            }
        }

        m_PrivateMBFTDataChannelList.Clear();

        if(!bIsShutDown)
        {
            DBG_SAVE_FILE_LINE
            m_lpParentEngine->SafePostMessage(new DeleteSessionMsg(this));

            if(!m_bEventEndPosted)
            {
                DBG_SAVE_FILE_LINE
                m_lpParentEngine->SafePostNotifyMessage(
                                    new FileEventEndNotifyMsg(m_EventHandle));
                m_bEventEndPosted   =   TRUE;
            }
        }
    }
}



MBFTReceiveSubEvent::MBFTReceiveSubEvent
(
    MBFTFILEHANDLE          hFile,
    LONG                    FileSize,
    LPCSTR                  lpszFileName,
    time_t                  FileDateTime,
    T120UserID              SenderID,
    BOOL                    bIsBroadcast,
    BOOL                    bIsCompressed,
    BOOL                    bEOFAcknowledge
)
:
    m_bIsBroadcast(bIsBroadcast),
    m_hFile(MAKELONG(hFile,SenderID)),
    m_FileSize(FileSize),
    m_FileDateTime(FileDateTime),
    m_TotalBytesReceived(0),
    m_cbRecvLastNotify(0),
    m_bFileCompressed(bIsCompressed),
    m_bEOFAcknowledge(bEOFAcknowledge),
    m_SenderID(SenderID),
    m_lpFile(NULL),
    m_UserAccepted(FALSE)
{
    if(lpszFileName)
    {
        ::lstrcpynA(m_szFileName,lpszFileName,sizeof(m_szFileName));
    }
    else
    {
        m_szFileName[0] = '\0';
    }

    m_szFileDirectory[0] = '\0';

    m_State = (! bIsBroadcast) ? MBFTPrivateReceive::EnumWaitUserConfirmation :
                                 MBFTPrivateReceive::EnumWaitFileStartPDU;
}


BOOL MBFTReceiveSubEvent::Init(void)
{
    DBG_SAVE_FILE_LINE
	m_lpFile = new CMBFTFile;
	return(m_lpFile != NULL);
}


MBFTReceiveSubEvent::~MBFTReceiveSubEvent(void)
{
    if(m_lpFile)
    {
		// if the file wasn't completely received, delete it
		if (m_TotalBytesReceived < m_FileSize)
			m_lpFile->Close(FALSE);

        delete m_lpFile;
    }
}

BOOL MBFTReceiveSubEvent::IsEqual
(
    MBFTReceiveSubEvent         *lpObject
)
{
    BOOL bReturn = FALSE;

    if(!lpObject->m_SenderID || !m_SenderID)
    {
        bReturn = (lpObject->m_hFile == (MBFTFILEHANDLE)MAKELONG(m_hFile, lpObject->m_SenderID));
    }
    else
    {
        bReturn = (lpObject->m_hFile == m_hFile) && (lpObject->m_SenderID == m_SenderID);
    }

    return(bReturn);
}

BOOL MBFTPrivateReceive::OnReceivedFileOfferPDU
(
    T120ChannelID           wChannelID,
    T120Priority            iPriority,
    T120UserID              SenderID,
	T120NodeID				NodeID,
    LPFILEOFFERPDU          lpFileOfferPDU,
    BOOL                    IsUniformSendData
)
{
    BOOL bReturn = FALSE;
    MBFT_ERROR_CODE iErrorCode  = iMBFT_OK;
    MBFT_ERROR_TYPES iErrorType = MBFT_INFORMATIVE_ERROR;

    if(wChannelID == m_PrivateMBFTControlChannel)
    {
        bReturn     =   TRUE;

        if(m_State == EnumWaitFileOfferPDU)
        {
			// Sanity checking
			DWORD res;
			// Windows 95 can't take NULL pointers for these
			DWORD SecPerCluster, BytePerSector, FreeCluster, TotalFreeCluster;
			TCHAR  szDirPath[MAX_PATH];
            TCHAR  szRootDirPath[MAX_PATH], *pszRootDir;

			::GetRecvFolder(NULL, szDirPath);

			res = GetFileAttributes(szDirPath);
			if ((0xffffffff == res)||!(res | FILE_ATTRIBUTE_DIRECTORY))
			{   // invalid directory name
				iErrorCode = iMBFT_INVALID_PATH;
				goto ERRORPROCESS;
			}

			pszRootDir = GetRootDirPath(szDirPath, szRootDirPath, MAX_PATH);
			if (GetDiskFreeSpace(pszRootDir, &SecPerCluster,
								&BytePerSector, &FreeCluster, &TotalFreeCluster))
			{
				if (!(BytePerSector && SecPerCluster))
				{
					WARNING_OUT(("BytePerSector %d, SecPerCluster %d\n", BytePerSector,
						SecPerCluster));
				}
				else if ((ULONG)lpFileOfferPDU->GetFileSize()/BytePerSector/SecPerCluster + 1 > FreeCluster)
				{   // not enough space to save the file
					iErrorCode = iMBFT_DIRECTORY_FULL_ERROR;
					goto ERRORPROCESS;
				}
			}
			else
			{
				ERROR_OUT(("GetDiskSpace Failed, error %d\n", GetLastError()));
			}

            BOOL bAckRequired = lpFileOfferPDU->GetAcknowledge();

            m_bOKToLeaveDataChannel = bAckRequired;

            //Change compression handling later -- for now, we assume that a Proshare send is
            //always compressed....

            BOOL bEOFAcknowledge = FALSE;
            CPeerList *pPeerList = m_lpParentEngine->GetPeerList();
            CPeerData *lpPeer;
            pPeerList->Reset();
            while (NULL != (lpPeer = pPeerList->Iterate()))
            {
                if(lpPeer->GetUserID() == SenderID)
                {
                    bEOFAcknowledge = lpPeer->GetEOFAcknowledge();
                    break;
                }
            }

            DBG_SAVE_FILE_LINE
            MBFTReceiveSubEvent * lpNewReceive = new MBFTReceiveSubEvent(lpFileOfferPDU->GetFileHandle(),
                                                                         lpFileOfferPDU->GetFileSize(),
                                                                         lpFileOfferPDU->GetFileName(),
                                                                         lpFileOfferPDU->GetFileDateTime(),
                                                                         SenderID,
                                                                         !bAckRequired,
                                                                         lpFileOfferPDU->GetCompressionFlags() & _MBFT_FILE_COMPRESSED,
                                                                         bEOFAcknowledge);
            if(lpNewReceive)
            {
                if(lpNewReceive->Init())
                {
                    m_ReceiveList.Append(lpNewReceive);
	
                    // lonchanc: how can you use static char szTemp[] here???
					char szRecvDir[MAX_PATH];
					::GetRecvFolder(NULL, szRecvDir);

                    if(lpNewReceive->m_lpFile->Create(szRecvDir, lpNewReceive->m_szFileName))
					{
						DBG_SAVE_FILE_LINE
						m_lpParentEngine->SafePostNotifyMessage(
									   new FileOfferNotifyMsg(m_EventHandle,
															  SenderID,
															  NodeID,
															  lpNewReceive->m_hFile,
															  lpNewReceive->m_lpFile->GetFileName(),
															  lpNewReceive->m_FileSize,
															  lpNewReceive->m_FileDateTime,
															  bAckRequired));
					}
					else
					{
						iErrorCode = iMBFT_FILE_ACCESS_DENIED;
						goto ERRORPROCESS;
					}
                }
                else
                {
                    delete  lpNewReceive;
                }
            }
         }
         else if(m_State == EnumWaitChannelDisband)
         {
			SendFileRejectPDU(lpFileOfferPDU->GetFileHandle());
         }
    }

    return(bReturn);


ERRORPROCESS:
	ReportError(NULL,iErrorType,iErrorCode, TRUE, 0,
			    lpFileOfferPDU->GetFileName(),
				lpFileOfferPDU->GetFileSize());
	SendFileRejectPDU(lpFileOfferPDU->GetFileHandle());
	return (bReturn);
}

BOOL MBFTPrivateReceive::OnReceivedFileStartPDU
(
    T120ChannelID           wChannelId,
    T120Priority            iPriority,
    T120UserID              SenderID,
    LPFILESTARTPDU          lpFileStartPDU,
    BOOL                    IsUniformSendData
)
{
     BOOL bReturn = FALSE;
     MBFTReceiveSubEvent * lpReceiveEvent;
     MBFT_ERROR_CODE iErrorCode  = iMBFT_OK;
     MBFT_ERROR_TYPES iErrorType = MBFT_INFORMATIVE_ERROR;

    if (m_PrivateMBFTDataChannelList.Find(wChannelId))
    {
        if(m_State != EnumWaitForTermination && m_State != EnumWaitChannelDisband)
        {
            bReturn     =   TRUE;

            MBFTReceiveSubEvent TempReceive(lpFileStartPDU->GetFileHandle(),0,NULL,0,SenderID,FALSE,m_bProshareTransfer,FALSE);

            lpReceiveEvent = m_ReceiveList.FindEquiv(&TempReceive);
            if(lpReceiveEvent)
            {
                if(lpReceiveEvent->m_State == EnumWaitFileStartPDU)
                {
                    //Double check to make sure....
                    lpReceiveEvent->m_bFileCompressed = lpFileStartPDU->GetCompressionFlags() & _MBFT_FILE_COMPRESSED;
                    if(lpReceiveEvent->m_bFileCompressed)
                    {
    					// We don't handle compressed files
    					iErrorCode = iMBFT_MEMORY_ALLOCATION_ERROR;
                    }

                    BOOL bSuccess = FALSE;
                    int BytesWritten = 0;

                    if(lpReceiveEvent->m_bFileCompressed)
    				{
    					// We don't handle compressed files
    					iErrorCode = iMBFT_MEMORY_ALLOCATION_ERROR;
    				}
    				else
                    {
                        BytesWritten = lpFileStartPDU->GetDataSize();
                        if(BytesWritten)
                        {
                            if(!lpReceiveEvent->m_lpFile->Write(lpFileStartPDU->GetDataBuffer(),
                                                                lpFileStartPDU->GetDataSize()))
                            {
                                iErrorCode = (MBFT_ERROR_CODE)lpReceiveEvent->m_lpFile->GetLastErrorCode();

                                //iMBFT_FILE_IO_ERROR;
                            }
                        }
                    }

                    //lpReceiveEvent->m_TotalBytesReceived += BytesWritten;

                    lpReceiveEvent->m_TotalBytesReceived   =  lpReceiveEvent->m_lpFile->Seek(0L,CMBFTFile::SeekMode::SeekFromCurrent);
                    lpReceiveEvent->m_FileSize = lpFileStartPDU->GetFileSize();

                    if(iErrorCode == iMBFT_OK)
                    {
                        if(m_State != EnumWaitForTermination)
                        {
                            DBG_SAVE_FILE_LINE
                            m_lpParentEngine->SafePostNotifyMessage(
                                            new FileTransmitMsg(m_EventHandle,
                                                               lpReceiveEvent->m_hFile,
                                                               lpReceiveEvent->m_FileSize,
                                                               lpReceiveEvent->m_TotalBytesReceived,
                                                               iMBFT_FILE_RECEIVE_BEGIN,
                                                               lpReceiveEvent->m_SenderID,
                                                               lpReceiveEvent->m_bIsBroadcast));
                        }

                        if(lpFileStartPDU->GetIsEOF())
                        {
                            lpReceiveEvent->m_lpFile->SetFileDateTime(lpReceiveEvent->m_FileDateTime);

                            lpReceiveEvent->m_lpFile->Close();
                            lpReceiveEvent->m_State = EnumWaitForTermination;

        					if(lpReceiveEvent->m_bEOFAcknowledge && m_JoinedToDataChannel)
        					{
        						SendFileEndAcknowledgePDU(lpReceiveEvent->m_hFile);
        					}
        					DeleteReceiveEvent(lpReceiveEvent,TRUE);
                        }
                        else
                        {
                            lpReceiveEvent->m_State = EnumWaitFileDataPDU;
                        }
                    }

                }
            }    //lpReceiveEvent
        }   //m_State != EnumWaitForTermination

        if(iErrorCode != iMBFT_OK)
        {
            BOOL bSendChannelLeave  =   lpReceiveEvent->m_bEOFAcknowledge;

            ReportError(lpReceiveEvent,iErrorType,iErrorCode);
            ReportReceiverError(lpReceiveEvent,iErrorType,iErrorCode);
            lpReceiveEvent->m_lpFile->Close(FALSE);
            DeleteReceiveEvent(lpReceiveEvent,TRUE);

            if(m_bOKToLeaveDataChannel)
            {
                if(bSendChannelLeave && m_JoinedToDataChannel)
                {
                    SendChannelLeavePDU();
                }
                LeaveDataChannel();
            }
        }

    }        //wChannelId == m_PrivateMBFTDataChannel

    return(bReturn);
}



void MBFTPrivateReceive::ReportError
(
    MBFTReceiveSubEvent    *lpReceiveEvent,
    int                     iErrorType,
    int                     iErrorCode,
    BOOL                    bIsLocalError,
    T120UserID              SenderID,
	const char*				pFileName,
	ULONG					lFileSize
)
{
    if(m_State != EnumWaitForTermination)
    {
        MBFTMsg * lpNewMessage;
		T120UserID id = SenderID ? SenderID : m_LocalMBFTUserID;

        DBG_SAVE_FILE_LINE
        m_lpParentEngine->SafePostNotifyMessage(
                        		new FileErrorMsg(m_EventHandle,
                        			(lpReceiveEvent) ? lpReceiveEvent->m_hFile : 0, iErrorType,
                        			iErrorCode,
                        			bIsLocalError,
                        			id,
                        			(lpReceiveEvent) ?  lpReceiveEvent->m_bIsBroadcast : 0,
									pFileName, lFileSize));
    }
    else
    {
        TRACERECEIVE(" Waiting for termination, not reporting error");
    }
}

void MBFTPrivateReceive::ReportReceiverError
(
    MBFTReceiveSubEvent    *lpReceive,
    int                     iErrorType,
    int                     iErrorCode,
    MBFTFILEHANDLE          iFileHandle
)
{
    if(m_State != EnumWaitForTermination)
    {
        if(lpReceive)
        {
            DBG_SAVE_FILE_LINE
            FileErrorPDU * lpNewPDU = new FileErrorPDU(iFileHandle ? iFileHandle : lpReceive->m_hFile,
                                                       iErrorType,iErrorCode);
			if(lpNewPDU)
			{
	            if(lpNewPDU->Encode())
    	        {
        	        m_lpParentEngine->SendDataRequest(m_MBFTControlSenderID,
        	                                          APPLET_HIGH_PRIORITY,
              	                                      (LPBYTE)lpNewPDU->GetBuffer(),
                   	                                  lpNewPDU->GetBufferLength());
	            }
	            delete lpNewPDU;
			}
        }
    }
    else
    {
        TRACERECEIVE(" Waiting for termination, not reporting receiver error");
    }
}

void MBFTPrivateReceive::DeleteReceiveEvent
(
    MBFTReceiveSubEvent    *lpReceive,
    BOOL                    bNotifyUser
)
{

    if(lpReceive)
    {
        if(bNotifyUser)
        {
            DBG_SAVE_FILE_LINE
            m_lpParentEngine->SafePostNotifyMessage(
                                     new FileTransmitMsg(m_EventHandle,
                                                         lpReceive->m_hFile,
                                                         lpReceive->m_FileSize,
                                                         lpReceive->m_TotalBytesReceived,
                                                         iMBFT_FILE_RECEIVE_END,
                                                         lpReceive->m_SenderID,
                                                         lpReceive->m_bIsBroadcast));
        }

        m_ReceiveList.Delete(lpReceive);

        if(m_CurrentReceiveEvent == lpReceive)
        {
            m_CurrentReceiveEvent = NULL;
        }
    }
}

BOOL MBFTPrivateReceive::OnReceivedFileDataPDU
(
    T120ChannelID           wChannelId,
    T120Priority            iPriority,
    T120UserID              SenderID,
    LPFILEDATAPDU           lpNewPDU,
    BOOL                    IsUniformSendData
)
{
    BOOL bReturn = FALSE;
    MBFTReceiveSubEvent * lpReceiveEvent;
    MBFT_ERROR_CODE iErrorCode  = iMBFT_OK;
    MBFT_ERROR_TYPES iErrorType = MBFT_INFORMATIVE_ERROR;
    BOOL bLocalError = TRUE;

    if(m_PrivateMBFTDataChannelList.Find(wChannelId))
    {
            if(m_State != EnumWaitForTermination && m_State != EnumWaitChannelDisband)
            {
                bReturn     =   TRUE;

                MBFTReceiveSubEvent TempReceive(lpNewPDU->GetFileHandle(),0,NULL,0,SenderID,FALSE,FALSE,FALSE);

                lpReceiveEvent = m_ReceiveList.FindEquiv(&TempReceive);
                if(lpReceiveEvent)
                {
                    if(lpReceiveEvent->m_State == EnumWaitFileDataPDU)
                    {
                        MBFTMsg * lpNewMessage;

                        if(!lpNewPDU->GetIsAbort())
                        {
                            BOOL bSuccess = FALSE;
                            int  BytesWritten = 0;

                            if(lpReceiveEvent->m_bFileCompressed)
							{
								// We don't handle compressed files
								iErrorCode = iMBFT_MEMORY_ALLOCATION_ERROR;
							}
							else
                            {
                                BytesWritten = lpNewPDU->GetDataSize();

                                if(BytesWritten)
                                {
                                    if(!lpReceiveEvent->m_lpFile->Write(lpNewPDU->GetDataBuffer(),
                                                                        lpNewPDU->GetDataSize()))
                                    {
                                        iErrorCode = (MBFT_ERROR_CODE) lpReceiveEvent->m_lpFile->GetLastErrorCode();

                                        //iMBFT_FILE_IO_ERROR;
                                    }
                                }
                            }

                            //lpReceiveEvent->m_TotalBytesReceived += BytesWritten;

                            lpReceiveEvent->m_TotalBytesReceived   =  lpReceiveEvent->m_lpFile->Seek(0L,CMBFTFile::SeekMode::SeekFromCurrent);

                            if(m_State != EnumWaitForTermination)
                            {
                                ASSERT(lpReceiveEvent->m_TotalBytesReceived >= lpReceiveEvent->m_cbRecvLastNotify);
                                ULONG nNotifyDelta = lpReceiveEvent->m_TotalBytesReceived - lpReceiveEvent->m_cbRecvLastNotify;
                                ULONG nNotifyThreshold = lpReceiveEvent->m_FileSize / 100; // 1%
                                if (nNotifyDelta >= nNotifyThreshold ||
                                    lpReceiveEvent->m_TotalBytesReceived >= lpReceiveEvent->m_FileSize)
                                {
                                    DBG_SAVE_FILE_LINE
                                    if (S_OK == m_lpParentEngine->SafePostNotifyMessage(
                                                    new FileTransmitMsg(m_EventHandle,
                                                                       lpReceiveEvent->m_hFile,
                                                                       lpReceiveEvent->m_FileSize,
                                                                       lpReceiveEvent->m_TotalBytesReceived,
                                                                       iMBFT_FILE_RECEIVE_PROGRESS,
                                                                       lpReceiveEvent->m_SenderID,
                                                                       lpReceiveEvent->m_bIsBroadcast)))
                                    {
                                        lpReceiveEvent->m_cbRecvLastNotify = lpReceiveEvent->m_TotalBytesReceived;
                                    }
                                }
                            }

                            if(iErrorCode == iMBFT_OK)
                            {
                                if(lpNewPDU->GetIsEOF())
                                {
                                    lpReceiveEvent->m_lpFile->SetFileDateTime(lpReceiveEvent->m_FileDateTime);

                                    lpReceiveEvent->m_lpFile->Close();
                                    lpReceiveEvent->m_State = EnumWaitForTermination;

									if(lpReceiveEvent->m_bEOFAcknowledge && m_JoinedToDataChannel)
									{
										SendFileEndAcknowledgePDU(lpReceiveEvent->m_hFile);
									}
									DeleteReceiveEvent(lpReceiveEvent,TRUE);
                                }
                            }
                        }
                        else
                        {
                            ReportError(lpReceiveEvent,MBFT_INFORMATIVE_ERROR,iMBFT_SENDER_ABORTED,
                                        FALSE,SenderID);

                            if(!lpReceiveEvent->m_bFileCompressed)
                            {
                                lpReceiveEvent->m_lpFile->Write(lpNewPDU->GetDataBuffer(),
                                                                lpNewPDU->GetDataSize());
                            }
                            else
                            {
								// We don't handle compressed files
								iErrorCode = iMBFT_MEMORY_ALLOCATION_ERROR;
                            }

                            lpReceiveEvent->m_lpFile->Close(FALSE);
                            lpReceiveEvent->m_State = EnumWaitForTermination;

                            DeleteReceiveEvent(lpReceiveEvent,TRUE);
                        }
                    }
                }   //lpReceiveEvent
            } //m_State != EnumWaitForTermination

        if(iErrorCode != iMBFT_OK)
        {
			T120UserID id = bLocalError ? m_LocalMBFTUserID : SenderID;
			ReportError(lpReceiveEvent, iErrorType, iErrorCode, bLocalError, id);

            if(bLocalError)
            {
                ReportReceiverError(lpReceiveEvent,iErrorType,iErrorCode);
            }

            if(m_bOKToLeaveDataChannel)
            {
                if(lpReceiveEvent->m_bEOFAcknowledge && m_JoinedToDataChannel)
                {
                    SendChannelLeavePDU();
                }
                LeaveDataChannel();
            }

            DeleteReceiveEvent(lpReceiveEvent,TRUE);
        }
    }   //wChannelId == m_PrivateMBFTDataChannel

    return(bReturn);
}

int MBFTPrivateReceive::DecompressAndWrite
(
    MBFTReceiveSubEvent    *lpReceiveEvent,
    LPCSTR                  lpBuffer,
    LONG                    BufferLength,
    LPINT                   lpDecompressedSize
)
{
    return(iMBFT_MEMORY_ALLOCATION_ERROR);
}



BOOL MBFTPrivateReceive::OnReceivedFileErrorPDU
(
    T120ChannelID           wChannelId,
    T120Priority            iPriority,
    T120UserID              SenderID,
    LPFILEERRORPDU          lpNewPDU,
    BOOL                    IsUniformSendData
)
{
    BOOL bReturn = FALSE;

    MBFTReceiveSubEvent TempReceive(lpNewPDU->GetFileHandle(),0,NULL,0,SenderID,FALSE,FALSE,FALSE);
    MBFTReceiveSubEvent *lpReceiveEvent = m_ReceiveList.FindEquiv(&TempReceive);
    if(lpReceiveEvent)
    {
        bReturn = TRUE;

        ReportError(lpReceiveEvent,lpNewPDU->GetErrorType(),
                    lpNewPDU->GetErrorCode(),
                    FALSE,SenderID);
    }
    else if(m_bProshareTransfer && m_ProshareSenderID == SenderID &&
            lpNewPDU->GetFileHandle() == LOWORD(_iMBFT_PROSHARE_ALL_FILES))
    {
        ReportError(&TempReceive,lpNewPDU->GetErrorType(),
                    lpNewPDU->GetErrorCode(),
                    FALSE,SenderID);

        bReturn = TRUE;
    }

    return(bReturn);
}

void MBFTPrivateReceive::DoStateMachine(void)
{
    switch(m_State)
    {
    case EnumWaitSendChannelResponsePDU:
        SendChannelResponsePDU();
        break;

    case EnumWaitSendFileAcceptPDU:
        SendFileAcceptPDU();
        break;

    case EnumWaitSendFileRejectPDU:
        SendFileRejectPDU();
        break;

    case EnumWaitSendFileEndAcknowledgePDU:
        SendFileEndAcknowledgePDU();
        break;

    case EnumWaitSendChannelLeavePDU:
        SendChannelLeavePDU();
        break;

    // caseEnumInitializationFailed:
    default:
        break;
    }
}

BOOL MBFTPrivateReceive::OnMCSChannelAdmitIndication
(
    T120ChannelID           wChannelId,
    T120UserID              ManagerID
)
{
    BOOL fHandled = FALSE;
 	//
	// More data channels
	//
	if(m_State == EnumWaitFileOfferPDU)
	{
		if(m_MBFTDataSenderID == ManagerID)
		{
			//
			// Add the data channel to the list
			//
			m_PrivateMBFTDataChannelList.Append(wChannelId);
			T120ChannelID oldChannel = m_PrivateMBFTDataChannel;
			m_PrivateMBFTDataChannel = wChannelId;
			JoinDataChannel();
			m_PrivateMBFTDataChannel = oldChannel;
			fHandled = TRUE;
		}
	}
    else
    if(m_State == EnumWaitAdmitControlChannel)
    {
        if(m_PrivateMBFTControlChannel == wChannelId)
        {
            m_MBFTControlSenderID = ManagerID;

            JoinControlChannel();
            fHandled = TRUE;
        }
    }
    else if(m_State == EnumWaitAdmitDataChannelIndication)
    {
        if (m_PrivateMBFTDataChannelList.Find(wChannelId))
        {
            m_MBFTDataSenderID = ManagerID;

			T120ChannelID oldChannel = m_PrivateMBFTDataChannel;
			m_PrivateMBFTDataChannel = wChannelId;
			JoinDataChannel();
			m_PrivateMBFTDataChannel = oldChannel;
			fHandled = TRUE;
        }
    }

    if (! fHandled)
    {
        UINT chid_uid = MAKELONG(wChannelId, ManagerID);
        m_AdmittedChannelQueue.Append(chid_uid);
    }

    return fHandled;
}

BOOL MBFTPrivateReceive::OnMCSChannelExpelIndication
(
    T120ChannelID           wChannelId,
    Reason                  iReason
)
{
    BOOL bReturn = FALSE;

    if(/*(wChannelId == m_PrivateMBFTControlChannel) ||*/
       m_PrivateMBFTDataChannelList.Find(wChannelId))
    {
        TRACERECEIVE(" Channel [%u] disbanded, terminating receive session\n",wChannelId);

        //Added by Atul to fix this problem:
        //If the sender aborts all files, or the send is aborted when the
        //last file is being sent, the sender sends a FileDataPDU with the
        ///AbortFlag set to TRUE and proceeds to disband the channel. However,
        //on account of a MCS bug, the receiver never sees the PDU (sic).
        //Therefore, when we receive a channel expel indication, we check to
        //see if we were receiving a file and post a iMBFT_SENDER_ABORTED if necessary...

        if(m_CurrentReceiveEvent /* && m_bProshareTransfer */ )
        {
            if(m_CurrentReceiveEvent->m_State == EnumWaitFileDataPDU ||
               m_CurrentReceiveEvent->m_State == EnumWaitFileStartPDU)
            {
                TRACE(" Unexpected channel disband encountered, posting SENDER_ABORTED message\n");

                ReportError(m_CurrentReceiveEvent,MBFT_INFORMATIVE_ERROR,iMBFT_SENDER_ABORTED,
                            FALSE,m_ProshareSenderID);

                m_CurrentReceiveEvent->m_lpFile->Close(FALSE);
                m_CurrentReceiveEvent->m_State = EnumWaitForTermination;
                DeleteReceiveEvent(m_CurrentReceiveEvent,TRUE);
            }
        }

        UnInitialize();

        bReturn = TRUE;
    }

    m_AdmittedChannelQueue.RemoveByChannelID(wChannelId);

    return(bReturn);
}


void MBFTPrivateReceive::SendChannelResponsePDU(void)
{
		if(m_PrivateMBFTControlChannel >= MIN_ASNDynamicChannelID &&
			m_PrivateMBFTControlChannel <= MAX_ASNDynamicChannelID)
		{
			T127_PRIVATE_CHANNEL_RESPONSE ChannelJoinResponsePDU;
			ChannelJoinResponsePDU.pduType = T127_PRIVATE_CHANNEL_JOIN_RESPONSE;
			ChannelJoinResponsePDU.ControlChannel = SWAPWORD(m_PrivateMBFTControlChannel - MIN_ASNDynamicChannelID);
			ChannelJoinResponsePDU.Response = (ASNPrivate_Channel_Join_ResponsePDU_result_successful << 5);
            // if the Mode is FALSE we should use ASNinvitation_rejected
            if(m_lpParentEngine->SendDataRequest(m_MBFTControlSenderID,
                                                 APPLET_HIGH_PRIORITY,
                                                 (LPBYTE)&ChannelJoinResponsePDU,
                                                 4))
            {
                TRACERECEIVE(" Sent Channel response PDU on [%u]\n",m_MBFTControlSenderID);
                m_State = EnumWaitFileOfferPDU;
            }
        }
        else
        {
            TRACE(" Receive: Fatal Encoding Failure\n");
            m_State = EnumInitializationFailed;
            //Encoding failed....
        }
}

BOOL MBFTPrivateReceive::SendFileAcceptPDU
(
    MBFTFILEHANDLE          iFileHandle
)
{
    m_State     =   EnumWaitSendFileAcceptPDU;

    if(iFileHandle)
    {
        m_CurrentAcceptHandle   =   iFileHandle;
    }

    BOOL bReturn = FALSE;

    DBG_SAVE_FILE_LINE
    LPFILEACCEPTPDU lpNewPDU = new FileAcceptPDU(m_CurrentAcceptHandle);
    if(lpNewPDU)
    {
        if(lpNewPDU->Encode())
        {
            if(m_lpParentEngine->SendDataRequest(m_MBFTControlSenderID,
                                                 APPLET_HIGH_PRIORITY,
                                                 (LPBYTE)lpNewPDU->GetBuffer(),
                                                 lpNewPDU->GetBufferLength()))
            {
                bReturn = TRUE;
                TRACERECEIVE(" Sent file accept PDU on [%u]\n",m_MBFTControlSenderID);
                m_State = EnumWaitFileOfferPDU;
            }
        }
        else
        {
            ReportError(m_CurrentReceiveEvent,MBFT_PERMANENT_ERROR,iMBFT_ASN1_ENCODING_ERROR);
        }

        delete lpNewPDU;
    }

    return(bReturn);
}

void MBFTPrivateReceive::OnControlNotification
(
    MBFTFILEHANDLE  hFile,
    FileTransferControlMsg::FileTransferControl iControlCommand,
    LPCSTR          lpszDirectory,
    LPCSTR          lpszFileName
)
{
    MBFTReceiveSubEvent * lpReceiveEvent = NULL;
    MBFTFILEHANDLE iFileHandle;
    BOOL bAbortHack =   FALSE;

    if(m_State  !=  EnumWaitChannelDisband && m_State  !=  EnumWaitForTermination)
    {
		MBFTReceiveSubEvent TempReceive(hFile,0,NULL,0,0,FALSE,FALSE,FALSE);

		lpReceiveEvent = m_ReceiveList.FindEquiv(&TempReceive);
        if(lpReceiveEvent)
        {
            iFileHandle = (MBFTFILEHANDLE)lpReceiveEvent->m_hFile;

            if(iControlCommand == FileTransferControlMsg::EnumAcceptFile)
            {
                if(lpReceiveEvent->m_State == EnumWaitUserConfirmation)
                {
                    ::lstrcpynA(lpReceiveEvent->m_szFileDirectory,lpszDirectory,
                             sizeof(lpReceiveEvent->m_szFileDirectory));

                    int Length = ::lstrlenA(lpReceiveEvent->m_szFileDirectory);

                    if(Length >= 3)
                    {
                    	PCHAR pch = SzFindLastCh(lpReceiveEvent->m_szFileDirectory, '\\');
                    	if ('\0' == *(pch+1))
                        {
                            lpReceiveEvent->m_szFileDirectory[Length - 1] = '\0';
                        }
                    }

                    if (::lstrlenA(lpszFileName))
                    {
                        ::lstrcpynA(lpReceiveEvent->m_szFileName, lpszFileName, sizeof(lpReceiveEvent->m_szFileName));
                    }

                    TRACERECEIVE(" File accept notification for [%u]\n",iFileHandle);
                    lpReceiveEvent->m_UserAccepted = TRUE;
                    m_CurrentReceiveEvent = lpReceiveEvent;

                    if(m_JoinedToDataChannel)
                    {
                        SendFileAcceptPDU(iFileHandle);
                        lpReceiveEvent->m_State = EnumWaitFileStartPDU;
                    }
                    else
                    {
                        m_State = EnumWaitRejoinDataChannel;
                        //m_CurrentReceiveEvent = lpReceiveEvent;
                        JoinDataChannel();
                    }
                }
            }
            else if(iControlCommand == FileTransferControlMsg::EnumRejectFile)
            {
                if((lpReceiveEvent->m_State == EnumWaitUserConfirmation) ||
                   (lpReceiveEvent->m_bIsBroadcast && lpReceiveEvent->m_State == EnumWaitFileStartPDU))
                {
                    if(hFile == _iMBFT_PROSHARE_ALL_FILES)
                    {
                        iFileHandle = LOWORD(_iMBFT_PROSHARE_ALL_FILES);
                    }

                    TRACERECEIVE(" Rejecting file [%u]\n",lpReceiveEvent->m_hFile);

                    if(m_bOKToLeaveDataChannel)
                    {
                        LeaveDataChannel();
                    }

                    SendFileRejectPDU(iFileHandle);

                    if(hFile == _iMBFT_PROSHARE_ALL_FILES)
                    {
                        TerminateReceiveSession();
                    }
                    else
                    {
                        DeleteReceiveEvent(lpReceiveEvent,FALSE);
                    }
                }
            }
            else if(iControlCommand == FileTransferControlMsg::EnumAbortFile)
            {
                if(hFile == _iMBFT_PROSHARE_ALL_FILES)
                {
                    iFileHandle = LOWORD(_iMBFT_PROSHARE_ALL_FILES);
                }

                if((lpReceiveEvent->m_State == EnumWaitFileDataPDU) ||
                   (lpReceiveEvent->m_State == EnumWaitFileStartPDU) ||
                   (hFile == _iMBFT_PROSHARE_ALL_FILES))
                {
                    TRACERECEIVE(" Aborting file [%u]\n",iFileHandle);
                    if(lpReceiveEvent->m_State == MBFTPrivateReceive::EnumWaitUserConfirmation)
                    {
                        TRACERECEIVE(" Rejecting file [%u]\n",lpReceiveEvent->m_hFile);
                        SendFileRejectPDU(iFileHandle);
                    }
                    else
                    {
                        if(hFile == _iMBFT_PROSHARE_ALL_FILES)
                        {
                            //If the AbortHack flag is set, we are on a sticky wicket.
                            //We have already aborted the current file and are waiting
                            //for another file offer. Therefore we don't inform the sender
                            //about this one...
                            if(!bAbortHack)
                            {
                                ReportReceiverError(lpReceiveEvent,
                                                    MBFT_PERMANENT_ERROR,
                                                    iMBFT_RECEIVER_ABORTED,
                                                    iFileHandle);
                            }
                        }
                        else
                        {
                            ReportReceiverError(lpReceiveEvent,
                                                MBFT_PERMANENT_ERROR,
                                                iMBFT_RECEIVER_ABORTED);
                        }
                    }

                    ReportError(lpReceiveEvent,MBFT_INFORMATIVE_ERROR,iMBFT_RECEIVER_ABORTED);

                    if(m_bOKToLeaveDataChannel)
                    {
                        if(lpReceiveEvent->m_bEOFAcknowledge && m_JoinedToDataChannel)
                        {
                            SendChannelLeavePDU();
                        }
                        LeaveDataChannel();
                    }

                    if(hFile != _iMBFT_PROSHARE_ALL_FILES)
                    {
                        DeleteNotificationMessages(iMBFT_FILE_RECEIVE_PROGRESS);

                        lpReceiveEvent->m_lpFile->Close(FALSE);
    //                    lpReceiveEvent->m_lpFile->DeleteFile();
                        DeleteReceiveEvent(lpReceiveEvent,TRUE);
                    }
                    else if(m_CurrentReceiveEvent)
                    {
                        m_CurrentReceiveEvent->m_lpFile->Close(FALSE);
    //                    m_CurrentReceiveEvent->m_lpFile->DeleteFile();
                        DeleteReceiveEvent(m_CurrentReceiveEvent,TRUE);
                    }
                }

                if(hFile == _iMBFT_PROSHARE_ALL_FILES)
                {
                    DeleteNotificationMessages(iMBFT_FILE_RECEIVE_PROGRESS);
                    DeleteNotificationMessages(iMBFT_FILE_OFFER);
                    TerminateReceiveSession();
                }
            }
        }
    }
}

void MBFTPrivateReceive::DeleteNotificationMessages
(
    MBFT_NOTIFICATION       iNotificationType
)
{
#if 0 // lonchanc: no way we can delete notify messages which are already in the queue
    MBFTMsg * lpNewMessage;
    CMsgQueue *pNotifyMsgList = m_lpParentEngine->GetNotificationMsgList();
    CMsgQueue DeleteList;

    pNotifyMsgList->Reset();
    while (NULL != (lpNewMessage = pNotifyMsgList->Iterate()))
    {
        switch (lpNewMessage->GetMsgType())
        {
        case EnumFileTransmitMsg:
            {
                FileTransmitMsg *lpFileMsg = (FileTransmitMsg *)lpNewMessage;
                if(lpFileMsg->m_EventHandle == m_EventHandle)
                {
                    if(iNotificationType == lpFileMsg->m_TransmitStatus)
                    {
                        TRACERECEIVE(" NUKING Notification [%x] from Event [%ld], Handle: [%ld] FileSize: [%ld], Bytes Xfered[%ld]\n",
                                     lpFileMsg->m_TransmitStatus,lpFileMsg->m_EventHandle,
                                     lpFileMsg->m_hFile,
                                     lpFileMsg->m_FileSize,
                                     lpFileMsg->m_BytesTransmitted);
                        DeleteList.Append(lpNewMessage);
                    }
                }
            }
            break;

        case EnumFileOfferNotifyMsg:
            {
                FileOfferNotifyMsg *lpFileOfferMsg = (FileOfferNotifyMsg *)lpNewMessage;
                if(lpFileOfferMsg->m_EventHandle == m_EventHandle)
                {
                    if(iNotificationType == iMBFT_FILE_OFFER)
                    {
                        TRACERECEIVE(" NUKING File Offer Notification for [%s], Event: [%ld], Size: [%ld], Handle [%Fp]\n",
                                     lpFileOfferMsg->m_szFileName,lpFileOfferMsg->m_EventHandle,
                                     lpFileOfferMsg->m_FileSize,lpFileOfferMsg->m_hFile);
                        DeleteList.Append(lpNewMessage);
                    }
                }
            }
            break;

        default:
            ASSERT(0);
            break;
        } // switch
    } //for loop

    // remove handled messages
    pNotifyMsgList->DeleteSubset(&DeleteList);
#endif // 0
}

void MBFTPrivateReceive::SendFileRejectPDU
(
    MBFTFILEHANDLE      iFileHandle
)
{
    if(m_State !=  EnumWaitSendFileRejectPDU)
    {
        m_PreviousRejectState     =   m_State;
        m_State                   =   EnumWaitSendFileRejectPDU;
    }

    if(iFileHandle)
    {
        m_CurrentRejectHandle   =   iFileHandle;
    }

    FileRejectPDU * lpNewPDU = NULL;

    DBG_SAVE_FILE_LINE
    lpNewPDU = new FileRejectPDU(m_CurrentRejectHandle);
    if(lpNewPDU)
    {
        if(lpNewPDU->Encode())
        {
            if(m_lpParentEngine->SendDataRequest(m_MBFTControlSenderID,
                                                 APPLET_HIGH_PRIORITY,
                                                 (LPBYTE)lpNewPDU->GetBuffer(),
                                                 lpNewPDU->GetBufferLength()))
            {
                m_State = (m_PreviousRejectState != EnumWaitChannelDisband) ?
                          EnumWaitFileOfferPDU : EnumWaitChannelDisband;
            }
        }
        else
        {
            ReportError(m_CurrentReceiveEvent,MBFT_PERMANENT_ERROR,iMBFT_ASN1_ENCODING_ERROR);
        }
    }

    delete lpNewPDU;
}

void MBFTPrivateReceive::SendFileEndAcknowledgePDU
(
    MBFTFILEHANDLE      iFileHandle
)
{
    if(iFileHandle)
    {
        m_CurrentFileEndHandle =   LOWORD(iFileHandle);
    }

    m_State =  EnumWaitSendFileEndAcknowledgePDU;

    DBG_SAVE_FILE_LINE
    FileEndAcknowledgeStruct * lpNewStruct  =   new FileEndAcknowledgeStruct;

    lpNewStruct->m_FileHandle   =  m_CurrentFileEndHandle;

    DBG_SAVE_FILE_LINE
    NonStandardPDU * lpNewPDU = new NonStandardPDU(NULL,
                                                   PROSHARE_FILE_END_STRING,
                                                   lpNewStruct,
                                                   sizeof(FileEndAcknowledgeStruct));
    if(lpNewPDU)
    {
        if(lpNewPDU->Encode())
        {
            if(m_lpParentEngine->SendDataRequest(m_PrivateMBFTControlChannel,
                                                 APPLET_HIGH_PRIORITY,
                                                 (LPBYTE)lpNewPDU->GetBuffer(),
                                                 lpNewPDU->GetBufferLength()))
            {
                TRACERECEIVE( " Sent FileEndAcknowledgePDU for [%u] on [%u]\n",m_CurrentFileEndHandle,m_PrivateMBFTControlChannel);

                m_State = EnumWaitFileOfferPDU;
            }
        }
        else
        {
            ReportError(m_CurrentReceiveEvent,MBFT_PERMANENT_ERROR,iMBFT_ASN1_ENCODING_ERROR);
        }

        delete  lpNewPDU;
    }

    delete  lpNewStruct;
}

void MBFTPrivateReceive::SendChannelLeavePDU(void)
{
    m_State =  EnumWaitSendChannelLeavePDU;

    DBG_SAVE_FILE_LINE
    ChannelLeaveStruct * lpNewStruct  =   new ChannelLeaveStruct;

    lpNewStruct->m_ChannelID   =    m_PrivateMBFTDataChannel;
    lpNewStruct->m_ErrorCode   =    iMBFT_RECEIVER_ABORTED;

    DBG_SAVE_FILE_LINE
    NonStandardPDU * lpNewPDU = new NonStandardPDU(NULL,
                                                   PROSHARE_CHANNEL_LEAVE_STRING,
                                                   lpNewStruct,
                                                   sizeof(ChannelLeaveStruct));
    if(lpNewPDU)
    {
        if(lpNewPDU->Encode())
        {
            if(m_lpParentEngine->SendDataRequest(m_PrivateMBFTControlChannel,
                                                 APPLET_HIGH_PRIORITY,
                                                 (LPBYTE)lpNewPDU->GetBuffer(),
                                                 lpNewPDU->GetBufferLength()))
            {
                TRACERECEIVE( " Sent ChannelLeavePDU for [%u] on [%u]\n",m_PrivateMBFTDataChannel,m_PrivateMBFTControlChannel);

                m_State = EnumWaitFileOfferPDU;
            }
        }
        else
        {
            ReportError(m_CurrentReceiveEvent,MBFT_PERMANENT_ERROR,iMBFT_ASN1_ENCODING_ERROR);
        }

        delete  lpNewPDU;
    }

    delete  lpNewStruct;
}

void MBFTPrivateReceive::LeaveDataChannel(void)
{
    if(m_JoinedToDataChannel)
    {
        if(m_lpParentEngine->MCSChannelLeaveRequest(m_PrivateMBFTDataChannel))
        {
            TRACERECEIVE(" Left data channel\n");
            m_JoinedToDataChannel = FALSE;
        }
    }
}

void MBFTPrivateReceive::TerminateReceiveSession(void)
{
    //if(m_lpParentEngine->MCSChannelLeaveRequest(m_PrivateMBFTControlChannel))
    //{
        //TRACERECEIVE(" Left control channel\n");
    //}

    //Keep the clients happy....

    if(!m_bEventEndPosted)
    {
        DBG_SAVE_FILE_LINE
        m_lpParentEngine->SafePostNotifyMessage(new FileEventEndNotifyMsg(m_EventHandle));
        m_bEventEndPosted   =   TRUE;
    }

    LeaveDataChannel();

    m_State     =   EnumWaitChannelDisband;

    //UnInitialize();
}


void MBFTPrivateReceive::OnPeerDeletedNotification
(
    CPeerData           *lpPeerData
)
{
    if(m_bProshareTransfer)
    {
        if(m_ProshareSenderID == lpPeerData->GetUserID())
        {
            if(m_CurrentReceiveEvent)
            {
                if((m_CurrentReceiveEvent->m_State == EnumWaitFileDataPDU) ||
                  (m_CurrentReceiveEvent->m_State == EnumWaitFileStartPDU))
                {
                    ReportError(m_CurrentReceiveEvent,MBFT_INFORMATIVE_ERROR,iMBFT_SENDER_ABORTED,
                                FALSE,m_ProshareSenderID);

                    m_CurrentReceiveEvent->m_lpFile->Close(FALSE);
                    m_CurrentReceiveEvent->m_State = EnumWaitForTermination;
                    DeleteReceiveEvent(m_CurrentReceiveEvent,TRUE);
                }
            }

            DeleteNotificationMessages(iMBFT_FILE_RECEIVE_PROGRESS);
            DeleteNotificationMessages(iMBFT_FILE_OFFER);
            TerminateReceiveSession();
        }
    }
}




#ifdef USE_BROADCAST_RECEIVE
MBFTBroadcastReceive::MBFTBroadcastReceive
(
    LPMBFTENGINE            lpParentEngine,
    MBFTEVENTHANDLE         EventHandle,
    T120ChannelID           wControlChannel,
    T120ChannelID           wDataChannel,
    T120UserID              SenderID,
    MBFTFILEHANDLE          FileHandle
)
:
    MBFTPrivateReceive(lpParentEngine, EventHandle, wControlChannel, wDataChannel),
    m_SenderID(SenderID),
    m_FileHandle(FileHandle)
{
    m_MBFTControlSenderID = m_SenderID;
    m_State = MBFTPrivateReceive::EnumWaitFileOfferPDU;
}

BOOL MBFTBroadcastReceive::OnReceivedFileOfferPDU
(
    T120ChannelID           wChannelId,
    T120Priority            iPriority,
    T120UserID              SenderID,
	T120NodeID				NodeID,
    LPFILEOFFERPDU          lpNewPDU,
    BOOL                    IsUniformSendData
)
{
    BOOL bReturn = FALSE;

    if(m_State == MBFTPrivateReceive::EnumWaitFileOfferPDU)
    {
        bReturn = (wChannelId == m_PrivateMBFTControlChannel) &&
                  (lpNewPDU->GetFileHandle() ==  m_FileHandle) &&
                  (SenderID == m_SenderID);

        if(bReturn)
        {
            MBFTPrivateReceive::OnReceivedFileOfferPDU(wChannelId,
                                                       iPriority,
                                                       SenderID,
													   NodeID,
                                                       lpNewPDU,
                                                       IsUniformSendData);

            m_CurrentReceiveEvent = m_ReceiveList.PeekHead();
            if(m_CurrentReceiveEvent)
            {
                ::lstrcpyA(m_CurrentReceiveEvent->m_szFileName,lpNewPDU->GetFileName());
                if(!lpNewPDU->GetAcknowledge())
                {
                    m_State = m_CurrentReceiveEvent->m_State = MBFTPrivateReceive::EnumWaitFileStartPDU;
                }
                else
                {
                    m_State  =  m_CurrentReceiveEvent->m_State = MBFTPrivateReceive::EnumWaitUserConfirmation;
                }
            }
            else
            {
                UnInitialize();
                //m_State = MBFTPrivateReceive::EnumWaitForTermination;
            }
        }
    }

    return(bReturn);
}

BOOL MBFTBroadcastReceive::OnMCSChannelJoinConfirm
(
    T120ChannelID           wChannelId,
    BOOL                    bSuccess
)
{
    BOOL bReturn = FALSE;

    if(m_State == MBFTPrivateReceive::EnumWaitJoinDataChannel &&
    	m_PrivateMBFTDataChannelList.Find(wChannelId))
    {
        bReturn                 = TRUE;
        m_JoinedToDataChannel   = TRUE;

        if(bSuccess && m_CurrentReceiveEvent)
        {
            m_State = MBFTPrivateReceive::EnumWaitSendFileAcceptPDU;
        }
        else
        {
            //m_State  =   MBFTPrivateReceive::EnumWaitForTermination;

            LeaveDataChannel();
            UnInitialize();
        }
    }

    return(bReturn);
}

BOOL MBFTBroadcastReceive::OnReceivedFileStartPDU
(
    T120ChannelID           wChannelId,
    T120Priority            iPriority,
    T120UserID              SenderID,
    LPFILESTARTPDU          lpFileStartPDU,
    BOOL                    IsUniformSendData
)
{
    BOOL bReturn = FALSE;

    if(m_State == MBFTPrivateReceive::EnumWaitFileStartPDU && m_CurrentReceiveEvent)
    {
        bReturn = m_PrivateMBFTDataChannelList.Find(wChannelId) &&
                  (lpFileStartPDU->GetFileHandle() ==  m_FileHandle) &&
                  (SenderID == m_SenderID);

        if(bReturn)
        {
            if(!lstrlen(m_CurrentReceiveEvent->m_szFileName))
            {
                lstrcpy(m_CurrentReceiveEvent->m_szFileName,lpFileStartPDU->GetFileName());
            }

            if(!lstrlen(m_CurrentReceiveEvent->m_szFileDirectory))
            {
                lstrcpy(m_CurrentReceiveEvent->m_szFileDirectory,m_CurrentReceiveEvent->m_lpFile->GetTempDirectory());
            }

            MBFTPrivateReceive::OnReceivedFileStartPDU(wChannelId,
                                                       iPriority,
                                                       SenderID,
                                                       lpFileStartPDU,
                                                       IsUniformSendData);

            //Assumption: m_CurrentReceiveEvent == NULL indicates an error.

            if(!m_CurrentReceiveEvent || lpFileStartPDU->GetIsEOF())
            {
                //m_State = MBFTPrivateReceive::EnumWaitForTermination;
                UnInitialize();
            }
            else
            {
                m_State = m_CurrentReceiveEvent->m_State = MBFTPrivateReceive::EnumWaitFileDataPDU;
            }
        }
    }

    return(bReturn);
}

BOOL MBFTBroadcastReceive::OnReceivedFileDataPDU
(
    T120ChannelID           wChannelId,
    T120Priority            iPriority,
    T120UserID              SenderID,
    LPFILEDATAPDU           lpNewPDU,
    BOOL                    IsUniformSendData
)
{
    BOOL bReturn = FALSE;

    if(m_State == MBFTPrivateReceive::EnumWaitFileDataPDU && m_CurrentReceiveEvent)
    {
        bReturn = m_PrivateMBFTDataChannelList.Find(wChannelId) &&
                  (lpNewPDU->GetFileHandle() ==  m_FileHandle) &&
                  (SenderID == m_SenderID);

        if(bReturn)
        {
            MBFTPrivateReceive::OnReceivedFileDataPDU(wChannelId,
                                                      iPriority,
                                                      SenderID,
                                                      lpNewPDU,
                                                      IsUniformSendData);

            if(!m_CurrentReceiveEvent || lpNewPDU->GetIsEOF())
            {
                //m_State = MBFTPrivateReceive::EnumWaitForTermination;

                //LeaveDataChannel();

                UnInitialize();
            }
        }
    }

    return(bReturn);
}

void MBFTBroadcastReceive::UnInitialize
(
    BOOL        bIsShutDown
)
{
    if(m_State != EnumWaitForTermination)
    {
        m_State = EnumWaitForTermination;

        if(!bIsShutDown)
        {
            DBG_SAVE_FILE_LINE
            m_lpParentEngine->SafePostMessage(new DeleteSessionMsg(this));
            if(!m_bEventEndPosted)
            {
                DBG_SAVE_FILE_LINE
                m_lpParentEngine->SafePostNotifyMessage(new FileEventEndNotifyMsg(m_EventHandle));
                m_bEventEndPosted   =   TRUE;
            }
        }
    }
}

void MBFTBroadcastReceive::DoStateMachine(void)
{
    if(m_State == MBFTPrivateReceive::EnumWaitSendFileAcceptPDU)
    {
        if(m_CurrentReceiveEvent)
        {
            if(SendFileAcceptPDU(m_FileHandle))
            {
                m_State = m_CurrentReceiveEvent->m_State = MBFTPrivateReceive::EnumWaitFileStartPDU;
            }
        }
        else
        {
            //m_State = MBFTPrivateReceive::EnumWaitForTermination;
            UnInitialize();
        }
    }
}

void MBFTBroadcastReceive::OnControlNotification
(
    MBFTFILEHANDLE          hFile,
    FileTransferControlMsg::FileTransferControl iControlCommand,
    LPCSTR                  lpszDirectory,
    LPCSTR                  lpszFileName
)
{
    if(m_State != MBFTPrivateReceive::EnumWaitForTermination)
    {
        if(m_CurrentReceiveEvent)
        {
            MBFTFILEHANDLE iFileHandle = (MBFTFILEHANDLE) m_CurrentReceiveEvent->m_hFile;

            if(iControlCommand == FileTransferControlMsg::EnumAcceptFile)
            {
                if(m_CurrentReceiveEvent->m_State == MBFTPrivateReceive::EnumWaitUserConfirmation)
                {
                    ::lstrcpynA(m_CurrentReceiveEvent->m_szFileDirectory,lpszDirectory,
                             sizeof(m_CurrentReceiveEvent->m_szFileDirectory));

                    int Length = ::lstrlenA(m_CurrentReceiveEvent->m_szFileDirectory);

                    if(Length >= 3)
                    {
                    	PCHAR pch = SzFindLastCh(m_CurrentReceiveEvent->m_szFileDirectory, '\\');
                    	if ('\0' == *(pch+1))
                        {
                            m_CurrentReceiveEvent->m_szFileDirectory[Length - 1] = '\0';
                        }
                    }

                    if (::lstrlenA(lpszFileName))
                    {
                        ::lstrcpynA(m_CurrentReceiveEvent->m_szFileName, lpszFileName, sizeof(m_CurrentReceiveEvent->m_szFileName));
                    }

                    TRACERECEIVE(" File accept notification for [%u]\n",iFileHandle);

                    m_CurrentReceiveEvent->m_UserAccepted = TRUE;

                    JoinDataChannel();

                    m_State     =   MBFTPrivateReceive::EnumWaitJoinDataChannel;
                }
            }
#if 0
            else if(iControlCommand == FileTransferControlMsg::EnumRejectFile)
            {
                if((m_CurrentReceiveEvent->m_State == MBFTPrivateReceive::EnumWaitUserConfirmation))
                {
                    LeaveDataChannel();
                    SendFileRejectPDU(iFileHandle);
                    DeleteReceiveEvent(m_CurrentReceiveEvent,FALSE);
                    UnInitialize();
                }
            }
#endif
            else if((iControlCommand == FileTransferControlMsg::EnumAbortFile)
                    || (iControlCommand == FileTransferControlMsg::EnumRejectFile))
            {
                if((m_CurrentReceiveEvent->m_State == MBFTPrivateReceive::EnumWaitFileDataPDU) ||
                   (m_CurrentReceiveEvent->m_State == MBFTPrivateReceive::EnumWaitFileStartPDU) ||
                   (m_CurrentReceiveEvent->m_State == EnumWaitUserConfirmation))
                {
                    TRACERECEIVE(" Aborting file [%u]\n",iFileHandle);

                    if(m_CurrentReceiveEvent->m_State == MBFTPrivateReceive::EnumWaitUserConfirmation)
                    {
                        //LeaveDataChannel();

                        SendFileRejectPDU(iFileHandle);

                        //DeleteReceiveEvent(m_CurrentReceiveEvent,FALSE);
                        //UnInitialize();
                    }
                    else
                    {
                        ReportReceiverError(m_CurrentReceiveEvent,
                                            MBFT_PERMANENT_ERROR,
                                            iMBFT_RECEIVER_ABORTED);
                    }

                    ReportError(m_CurrentReceiveEvent,MBFT_INFORMATIVE_ERROR,iMBFT_RECEIVER_ABORTED);

                    LeaveDataChannel();

                    DeleteNotificationMessages(iMBFT_FILE_RECEIVE_PROGRESS);
                    m_CurrentReceiveEvent->m_lpFile->Close(FALSE);
                    DeleteReceiveEvent(m_CurrentReceiveEvent,TRUE);
                    UnInitialize();
                 }
            }
        }
    }
}

void MBFTBroadcastReceive::OnPeerDeletedNotification
(
    CPeerData           *lpPeerData
)
{
    if(lpPeerData->GetUserID() == m_SenderID)
    {
        if(m_CurrentReceiveEvent)
        {
            if(m_State == MBFTPrivateReceive::EnumWaitFileStartPDU ||
               m_State == MBFTPrivateReceive::EnumWaitFileDataPDU)
            {
                ReportError(m_CurrentReceiveEvent,MBFT_INFORMATIVE_ERROR,iMBFT_SENDER_ABORTED,
                            FALSE,m_ProshareSenderID);

                m_CurrentReceiveEvent->m_lpFile->Close(FALSE);
                DeleteReceiveEvent(m_CurrentReceiveEvent,TRUE);
            }

            DeleteNotificationMessages(iMBFT_FILE_RECEIVE_PROGRESS);

            UnInitialize();
        }
    }
}

#endif	// USE_BROADCAST_RECEIVE


MBFTReceiveSubEvent * CRecvSubEventList::FindEquiv
(
    MBFTReceiveSubEvent         *pEvent
)
{
    MBFTReceiveSubEvent *p;
    Reset();
    while (NULL != (p = Iterate()))
    {
        if (p->IsEqual(pEvent))
        {
            return p;
        }
    }
    return NULL;
}

void CRecvSubEventList::Delete
(
    MBFTReceiveSubEvent         *pEvent
)
{
    if (Remove(pEvent))
    {
        delete pEvent;
    }
}

void CRecvSubEventList::DeleteAll(void)
{
    MBFTReceiveSubEvent *p;
    while (NULL != (p = Get()))
    {
        delete p;
    }
}



BOOL CChannelUidQueue::RemoveByChannelID(T120ChannelID nChannelID)
{
    UINT_PTR chid_uid;
    Reset();
    while (0 != (chid_uid = Iterate()))
    {
        if (LOWORD(chid_uid) == nChannelID)
        {
            return Remove(chid_uid);
        }
    }
    return FALSE;
}

UINT_PTR CChannelUidQueue::FindByChannelID(T120ChannelID nChannelID)
{
    UINT_PTR chid_uid;
    Reset();
    while (0 != (chid_uid = Iterate()))
    {
        if (LOWORD(chid_uid) == nChannelID)
        {
            return chid_uid;
        }
   }
   return 0;
}

LPTSTR GetRootDirPath(LPTSTR pszDirPath, LPTSTR pszRootDirPath, int nSize)
{
	::lstrcpy(pszRootDirPath, pszDirPath);
	if (pszRootDirPath[0] == TEXT('\\'))
	{
		if (pszRootDirPath[1] != TEXT('\\'))
		{
			return NULL;
		}

		// the path starts with two '\\'
		BOOL fFirstSlash = FALSE;
		LPTSTR psz = pszRootDirPath + 2;
		while (*psz && !(fFirstSlash && *psz == TEXT('\\')))
		{
			if (*psz == TEXT('\\'))
			{
				fFirstSlash = TRUE;
			}
			psz = ::CharNext(psz);
		}

		*psz++ = '\\';
		*psz = '\0';
		return pszRootDirPath;
	}

	// the first char is not a '\\', it could be driver letter followed by ':'
	if (pszRootDirPath[1] == TEXT(':'))
	{
		pszRootDirPath[2] = TEXT('\\');
		pszRootDirPath[3] = TEXT('\0');
		return pszRootDirPath;
	}

	// the second char is not a ':' , must be a sub directory
	return NULL;
}