/*

    File: ftpp/datacmd.cc

    Copyright (C) 2002  Dmitry Udalov
    Email: uddm@penza.net
  
    This software is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
 */


#include "ftpproxy.h"


//check abort signal by data transffer
int isAbort(struct ClientParam *Session){
    char szFTPCmd[BUF_SIZE],cBuf[BUF_SIZE];
    struct timeval TimeOut;
    TimeOut.tv_sec=0;
    TimeOut.tv_usec=0;
    if(waitread(Session->hCtrlClientSocket,TimeOut)==FALSE)
        return FALSE;
    int iLen=recv(Session->hCtrlClientSocket,cBuf,BUF_SIZE,0);
    if((iLen==-1)&&(errno==ENOTCONN)){
        fClientDisconnected=TRUE;
	return FALSE;
    }
    cBuf[iLen]='\0';
    if(iLen>=4){
        logex(iClientNum,"> Check ABOR ");
        if(strstr(cBuf,ABORCMD)!=NULL){//if received command ABORT then
            logex(iClientNum,"> ABOR ");
            cBuf[0]=255;//IAC
            cBuf[1]=244;//IP
            //send Interrupt Process signal to server
            iLen=send(Session->hCtrlServerSocket,cBuf,2,MSG_OOB);
            cBuf[0]=255;//IAC
            cBuf[1]=242;//DM
            iLen=send(Session->hCtrlServerSocket,cBuf,2,0);
            strcpy(cBuf,"ABOR");
            strcat(cBuf,"\r\n");
            //send ABOR command to server
            iLen=send(Session->hCtrlServerSocket,cBuf,strlen(cBuf),0);
            fsync(Session->hCtrlServerSocket);
            return TRUE;
        }
    }
    else
        return FALSE;
}

//process PORT h,h,h,h,p,p command
int portcmdprocces(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam){
    char cAddr[STR_SIZE],cBuf[BUF_SIZE];
    char *lpszAddr=lpszParam;
    char cIPAddr[STR_SIZE],cPort[STR_SIZE],*lpszPtr,cAddrBuf[STR_SIZE];
    int iRes=TRUE;
    lpszPtr=lpszAddr;
    cAddr[0]='\0';
    //parse command parametrs
    //parse host ip addres
    for(int i=1;i<=4;i++){
        lpszPtr=strchr(lpszAddr,',');
        strncpy(cAddrBuf,lpszAddr,lpszPtr-lpszAddr);
        cAddrBuf[lpszPtr-lpszAddr]='\0';
        if(i<4)
            strcat(cAddrBuf,".");
        strcat(cAddr,cAddrBuf);
        lpszAddr=lpszPtr+1;
    }
    lpszPtr=strchr(lpszAddr,',');
    if(lpszPtr==NULL){
        sendreply(Session,S501MSG);
	logex(iClientNum,"Logged %s(%s) < %s 1",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S501MSG);
        return TRUE;
    }
    //select portnumber
    strncpy(cAddrBuf,lpszAddr,lpszPtr-lpszAddr);
    cAddrBuf[lpszPtr-lpszAddr]='\0';
    lpszAddr=lpszPtr+1;
    long int iPort=0;
    iPort=atoi(cAddrBuf);
    try{
        //calc real port number
        iPort=(iPort << 8) + atoi(lpszAddr);
    }
    catch(char * pcex){
        sendreply(Session,S501MSG);
	logex(iClientNum,"Logged %s(%s) < %s 2",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S501MSG);
        return TRUE;
    }
    //fill addres structure
    memset(&(Session->ClientDataAddr),0,sizeof(Session->ClientDataAddr));
    Session->ClientDataAddr.sin_family=AF_INET;
    Session->ClientDataAddr.sin_addr.s_addr=inet_addr(cAddr);
    Session->ClientDataAddr.sin_port=htons(iPort);
    //send to server PORT xxx.xxx.xxx.xxx.x.xxx
    memset(&(Session->ListeningDataAddr),0,sizeof(Session->ListeningDataAddr));
    Session->ListeningDataAddr.sin_family=AF_INET;
    Session->ListeningDataAddr.sin_addr.s_addr=inet_addr(szWorkingAddr);
    Session->ListeningDataAddr.sin_port=htons(0);
    //create socket
    Session->hListeningServerSocket=socket(PF_INET,SOCK_STREAM,0);
    //bind port for data transfer's
    if(bind(Session->hListeningServerSocket,(struct sockaddr *)&(Session->ListeningDataAddr),sizeof(Session->ListeningDataAddr))!=0){
        sendreply(Session,S425MSG);
	logex(iClientNum,"Logged %s(%s) < %s 3",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S425MSG);
        shutdown(Session->hListeningServerSocket,SHUT_RDWR);
        close(Session->hListeningServerSocket);
        return TRUE;
    }
    //listen data transffer socket
    if(listen(Session->hListeningServerSocket,2)!=0){
        sendreply(Session,S425MSG);
        shutdown(Session->hListeningServerSocket,SHUT_RDWR);
        close(Session->hListeningServerSocket);
        return TRUE;
    }
    //send PORT xxx.xxx.xxx.xxx.x.xxx to server
    socklen_t AddrLen=sizeof(Session->ListeningDataAddr);
    getsockname(Session->hListeningServerSocket,(struct sockaddr *)&(Session->ListeningDataAddr),&AddrLen);
    sprintf(cBuf,"PORT %s,%d,%d",inet_ntoa(Session->ListeningDataAddr.sin_addr),htons(Session->ListeningDataAddr.sin_port)/256,htons(Session->ListeningDataAddr.sin_port)%256);
    strcat(cBuf,"\r\n");
    //change '.' char to ',' char
    for(int i=0;i<strlen(cBuf);i++)
        if(cBuf[i]=='.')
            cBuf[i]=',';
    //send command PORT to server
    sendcmd(Session,cBuf);
    logex(iClientNum,"Logged %s(%s) > %s 5",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    //get server reply
    int iRetCode=getreply(Session,cBuf);
    logex(iClientNum," iRetCode %d",iRetCode);
    if(iRetCode==-1)
        return FALSE;
    logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    //while no reply read reply
    while(iRetCode==0){
       iRetCode=getreply(Session,cBuf);
       sendreply(Session,cBuf);
       logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    }
    if(iRetCode==200){//OK
	sendreply(Session,cBuf);
        Session->fActiveMode=TRUE;
        return TRUE;
    }
    else{//Error
	sendreply(Session,S501MSG);
	logex(iClientNum,"Logged %s(%s) < %s 4",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
        shutdown(Session->hListeningServerSocket,SHUT_RDWR);
        close(Session->hListeningServerSocket);
        return FALSE;
    }
}


//process PASV command
int pasvcmdprocces(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam){
    //1. send to server command
    char cBuf[BUF_SIZE];
    //send PASV command
    sendcmd(Session,PASVCMD);
    logex(iClientNum,"Logged %s(%s) > %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),PASVCMD);
    //get server reply
    int iRetCode=getreply(Session,cBuf);
    if(iRetCode==-1)
        return FALSE;
//    logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    //while no reply read again
    while(iRetCode==0){
       iRetCode=getreply(Session,cBuf);
       sendreply(Session,cBuf);
//       logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    }
    //check code of reply
    if(iRetCode!=227){
        sendreply(Session,S501MSG);//error
        return TRUE;
    }
    //reply
    char cAddr[STR_SIZE];
    char cIPAddrPrt[STR_SIZE],cPort[STR_SIZE],*lpszPtr,cAddrBuf[STR_SIZE];
    char *lpszAddr=strchr(cBuf,'(');
    if(lpszAddr==NULL){
        sendreply(Session,S501MSG);
        return TRUE;
    }
    lpszAddr=lpszAddr+1;
    lpszPtr=strchr(lpszAddr,')');
    if(lpszPtr==NULL){
        sendreply(Session,S501MSG);
        return TRUE;
    }
    strncpy(cIPAddrPrt,lpszAddr,lpszPtr-lpszAddr);
    cIPAddrPrt[lpszPtr-lpszAddr]='\0';
    lpszAddr=cIPAddrPrt;

    lpszPtr=lpszAddr;
    cAddr[0]='\0';
    //select addres
    for(int i=1;i<=4;i++){
        lpszPtr=strchr(lpszAddr,',');
        strncpy(cAddrBuf,lpszAddr,lpszPtr-lpszAddr);
        cAddrBuf[lpszPtr-lpszAddr]='\0';
        if(i<4)
            strcat(cAddrBuf,".");
        strcat(cAddr,cAddrBuf);
        lpszAddr=lpszPtr+1;
    }
    lpszPtr=strchr(lpszAddr,',');
    if(lpszPtr==NULL){
        sendreply(Session,S501MSG);
        return TRUE;
    }
    //select port
    strncpy(cAddrBuf,lpszAddr,lpszPtr-lpszAddr);
    cAddrBuf[lpszPtr-lpszAddr]='\0';
    lpszAddr=lpszPtr+1;
    int iPort=0;
    iPort=atoi(cAddrBuf);
    try{
        iPort=(iPort << 8) + atoi(lpszAddr);
    }
    catch(char * pcex){
        sendreply(Session,S501MSG);
        return TRUE;
    }
    //fill server data address
    memset(&(Session->ServerDataAddr),0,sizeof(Session->ServerDataAddr));
    Session->ServerDataAddr.sin_family=AF_INET;
    Session->ServerDataAddr.sin_addr.s_addr=inet_addr(cAddr);
    Session->ServerDataAddr.sin_port=htons(iPort);
    //generate self address for client
    memset(&(Session->ListeningDataAddr),0,sizeof(Session->ServerDataAddr));
    Session->ListeningDataAddr.sin_family=AF_INET;
    Session->ListeningDataAddr.sin_addr.s_addr=inet_addr(szWorkingAddr);
    Session->ListeningDataAddr.sin_port=htons(iWorkingPort-1);//0
    //create socket
    Session->hListeningClientSocket=socket(PF_INET,SOCK_STREAM,0);
    //Set socket options
    int iOn=1;
    if(setsockopt(Session->hListeningClientSocket,SOL_SOCKET,SO_REUSEADDR,&iOn,sizeof(iOn))==-1){
        logex(iClientNum,"sersockopt error");
    }
    //bind
    if(bind(Session->hListeningClientSocket,(struct sockaddr *)&(Session->ListeningDataAddr),sizeof(Session->ListeningDataAddr))!=0){
        sendreply(Session,S425MSG);
        logex(iClientNum,"Can't bind");
        shutdown(Session->hListeningServerSocket,SHUT_RDWR);
        close(Session->hListeningServerSocket);
        return TRUE;
    }
    //listen
    if(listen(Session->hListeningClientSocket,2)!=0){
        sendreply(Session,S425MSG);
        logex(iClientNum,"Can't listen");
        shutdown(Session->hListeningServerSocket,SHUT_RDWR);
        close(Session->hListeningServerSocket);
        return TRUE;
    }
    //send PASV reply to client (hhh.hhh.hhh.hhh.ppp.ppp)
    socklen_t AddrLen=sizeof(Session->ListeningDataAddr);    
    getsockname(Session->hListeningClientSocket,(struct sockaddr *)&(Session->ListeningDataAddr),&AddrLen);
    sprintf(cAddr,"%s,%d,%d",inet_ntoa(Session->ListeningDataAddr.sin_addr),htons(Session->ListeningDataAddr.sin_port)/256,htons(Session->ListeningDataAddr.sin_port)%256);
//    sprintf(cAddr,"%s,%d,%d",inet_ntoa(Session->ListeningDataAddr.sin_addr),htons(20)/256,htons(20)%256);
    for(int i=0;i<strlen(cAddr);i++)
        if(cAddr[i]=='.')
            cAddr[i]=',';
    sprintf(cBuf,S227MSG,cAddr);
    //send reply to client
    sendreply(Session,cBuf);
    logex(iClientNum,"Logged %s(%s) < %s xx",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    Session->fActiveMode=FALSE;
    return TRUE;
}

//data transffer routine
int datatransfercmd(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam,int fStor){
    int hSrcDataSocket=-1,hDstDataSocket=-1;
    char cBuf[BUF_SIZE];
    int iLen=0,fAbort=FALSE,iSize=0,iStat=0;
    time_t BegTime=0,EndTime=0;
    if(Session->fActiveMode==FALSE){
        //if Active mode then connect to server data socket
        Session->hDataServerSocket=socket(PF_INET,SOCK_STREAM,0);
        if(connect(Session->hDataServerSocket,(struct sockaddr *)&(Session->ServerDataAddr),sizeof(Session->ServerDataAddr))!=0){
            //error
	    sendreply(Session,S425MSG);
            logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S425MSG);
            shutdown(Session->hListeningServerSocket,SHUT_RDWR);
            close(Session->hListeningServerSocket);
            return TRUE;
        }
    }
    sprintf(cBuf,"%s %s",lpszFTPCmd,lpszParam);
    trim(cBuf,cBuf);
    logex(iClientNum,"Logged %s(%s) > %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    //send command to server
    sendcmd(Session,cBuf);
    //get server reply
    int iRetCode=getreply(Session,cBuf);
    if(iRetCode==-1){//if error then close all connections
        sendreply(Session,S425MSG);
        logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S425MSG);
	if(Session->fActiveMode){
	    shutdown(Session->hListeningServerSocket,SHUT_RDWR);
	    close(Session->hListeningServerSocket);
        }
	else{
	    shutdown(Session->hListeningClientSocket,SHUT_RDWR);
	    close(Session->hListeningClientSocket);
        }
        return FALSE;
    }
    while(iRetCode==0){
        iRetCode=getreply(Session,cBuf);
    }
    logex(iClientNum,"iRetCode %d",iRetCode);
    //check reply code
    if((iRetCode!=150)&&(iRetCode!=226)&&(iRetCode!=225)&&(iRetCode!=125)&&(iRetCode!=250)){
        //if error code then close all data connections
	sendreply(Session,cBuf);
        logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
	if(Session->fActiveMode){
	    shutdown(Session->hListeningServerSocket,SHUT_RDWR);
            close(Session->hListeningServerSocket);
        }
	else{
	    shutdown(Session->hListeningClientSocket,SHUT_RDWR);
	    close(Session->hListeningClientSocket);
        }
        return TRUE;
    }
    socklen_t AddrLen;
    if(Session->fActiveMode){//if active mode e.g. by PORT command
        //active mode
        AddrLen=sizeof(Session->ServerDataAddr);
        //accept server connection
        if((Session->hDataServerSocket=accept(Session->hListeningServerSocket,(struct sockaddr*)&(Session->ServerDataAddr),&AddrLen))!=-1){
            Session->hDataClientSocket=socket(PF_INET,SOCK_STREAM,0);
            if(Session->hDataClientSocket==-1){
   	        sendreply(Session,S425MSG);
                logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S425MSG);
                shutdown(Session->hListeningServerSocket,SHUT_RDWR);
                close(Session->hListeningServerSocket);
                return FALSE;
            }
            //connect to client data socket
            if(connect(Session->hDataClientSocket,(struct sockaddr *)&(Session->ClientDataAddr),sizeof(Session->ClientDataAddr))==0){
		sendreply(Session,S150MSG);
                logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S150MSG);
                iLen=-1;
                if(fStor){
                    //if STOR command e.g. send data to server then
                    hDstDataSocket=Session->hDataServerSocket;//set destination to server
                    hSrcDataSocket=Session->hDataClientSocket;//set source to client
                }
                else{
                    //else
                    hSrcDataSocket=Session->hDataServerSocket;//set destination to client
                    hDstDataSocket=Session->hDataClientSocket;//set source to server
                }
                iSize=0;
                time(&BegTime);//save begin time
                while(iLen!=0){
                    //check on ABORT command
                    if(isAbort(Session)==TRUE){
                        fAbort=TRUE;
                        iStat=1;
                        break;
                    }
                    //read data from source
                    iLen=recv(hSrcDataSocket,cBuf,BUF_SIZE,0);
		    if((iLen==-1)&&(errno==ENOTCONN)){
                        //if connection reffused then
			sendreply(Session,S452MSG);
                        logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S452MSG);
			shutdown(Session->hDataClientSocket,SHUT_RDWR);
			close(Session->hDataClientSocket);
                        shutdown(Session->hDataServerSocket,SHUT_RDWR);
                        close(Session->hDataServerSocket);
                        shutdown(Session->hListeningServerSocket,SHUT_RDWR);
                        close(Session->hListeningServerSocket);
                        time(&EndTime);
                        if(strlen(lpszParam)==0)
                            accesslog(Session,EndTime-BegTime,iSize,2,lpszFTPCmd);
                        else
                            accesslog(Session,EndTime-BegTime,iSize,2,lpszParam);
                        return TRUE;
                        
		    }
                    //send to destination
                    iLen=send(hDstDataSocket,cBuf,iLen,0);
		    if((iLen==-1)&&(errno==EPIPE)){
                        //if connection reffused then
			sendreply(Session,S452MSG);
                        logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S452MSG);
                        shutdown(Session->hDataClientSocket,SHUT_RDWR);
			close(Session->hDataClientSocket);
                        shutdown(Session->hDataServerSocket,SHUT_RDWR);
                        close(Session->hDataServerSocket);
                        shutdown(Session->hDataServerSocket,SHUT_RDWR);
                        close(Session->hListeningServerSocket);
                        time(&EndTime);
                        if(strlen(lpszParam)==0)
                            accesslog(Session,EndTime-BegTime,iSize,2,lpszFTPCmd);
                        else
                            accesslog(Session,EndTime-BegTime,iSize,2,lpszParam);
			return TRUE;
		    }
                    iSize+=iLen;
                }
                time(&EndTime);//get end time
                //save record to access log file
                if(strlen(lpszParam)==0)
                    accesslog(Session,EndTime-BegTime,iSize,iStat,lpszFTPCmd);
                else
                    accesslog(Session,EndTime-BegTime,iSize,iStat,lpszParam);
                //close connection
                shutdown(Session->hDataClientSocket,SHUT_RDWR);
                close(Session->hDataClientSocket);
                if(fAbort==FALSE){
		    sendreply(Session,S226MSG);
                    logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S226MSG);
                }
                else{
                    strcpy(cBuf,S426MSG);
                    strcat(cBuf,"\r\n");
                    strcat(cBuf,S226AMSG);
		    sendreply(Session,cBuf);
                    logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
                }
                shutdown(Session->hDataServerSocket,SHUT_RDWR);
                close(Session->hDataServerSocket);
                shutdown(Session->hListeningServerSocket,SHUT_RDWR);
                close(Session->hListeningServerSocket);
		logex(iClientNum,"iRetCode before check %d 1",iRetCode);
                
		while((iRetCode!=226)&&(iRetCode!=225)){
		    iRetCode=getreply(Session,cBuf);
		    logex(iClientNum,"cBuf %s ",cBuf); 
		    if(iRetCode==-1){
                        logex(iClientNum,"Error getreply 1.");
			return FALSE;
		    }
		}
            }
            else{
                 //can't connect to server
  		 sendreply(Session,S425MSG);
                 logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S425MSG);
                 shutdown(Session->hListeningServerSocket,SHUT_RDWR);
                 close(Session->hListeningServerSocket);
                 shutdown(Session->hDataClientSocket,SHUT_RDWR);
                 close(Session->hDataClientSocket);
            }
        }
        else{
            //can't accept server connection
	    sendreply(Session,S425MSG);
            logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
            shutdown(Session->hListeningServerSocket,SHUT_RDWR);
            close(Session->hListeningServerSocket);
        }
    }
    else{
        //passive mode
        AddrLen=sizeof(Session->ClientDataAddr);
        if((Session->hDataClientSocket=accept(Session->hListeningClientSocket,(struct sockaddr*)&(Session->ClientDataAddr),&AddrLen))==-1){
            //error
	    sendreply(Session,S425MSG);
            logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S425MSG);
            shutdown(Session->hListeningClientSocket,SHUT_RDWR);
            close(Session->hListeningClientSocket);
            shutdown(Session->hDataServerSocket,SHUT_RDWR);
            close(Session->hDataServerSocket);
            return TRUE;
            
        }
        //send reply to client
        sendreply(Session,S150MSG);
        logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S150MSG);
        iLen=-1;
        if(fStor){
            //if STOR command e.g. send data to server then
            hDstDataSocket=Session->hDataServerSocket;//set destination to server
            hSrcDataSocket=Session->hDataClientSocket;//set source to client
        }
        else{
            //else
            hSrcDataSocket=Session->hDataServerSocket;//set destination to client
            hDstDataSocket=Session->hDataClientSocket;//set source to server
        }

        iSize=0;
        time(&BegTime);
        while(iLen!=0){
            //check on ABORT command
            if(isAbort(Session)==TRUE){
                fAbort=TRUE;
                iStat=1;
                break;
            }
            //read data from source
            iLen=recv(hSrcDataSocket,cBuf,BUF_SIZE,0);
	    if((iLen==-1)&&(errno==ENOTCONN)){
	        sendreply(Session,S452MSG);
                logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S452MSG);
                shutdown(Session->hDataClientSocket,SHUT_RDWR);
		close(Session->hDataClientSocket);
                shutdown(Session->hDataServerSocket,SHUT_RDWR);
		close(Session->hDataServerSocket);
                shutdown(Session->hListeningClientSocket,SHUT_RDWR);
        	close(Session->hListeningClientSocket);
                time(&EndTime);
                if(strlen(lpszParam)==0)
                    accesslog(Session,EndTime-BegTime,iSize,2,lpszFTPCmd);
                else
                    accesslog(Session,EndTime-BegTime,iSize,2,lpszParam);
		return TRUE;
	    }
            //send data to destination
            iLen=send(hDstDataSocket,cBuf,iLen,0);
            if((iLen==-1)&&(errno==EPIPE)){
	        sendreply(Session,S452MSG);
                logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S452MSG);
		shutdown(Session->hDataClientSocket,SHUT_RDWR);
		close(Session->hDataClientSocket);
                shutdown(Session->hDataServerSocket,SHUT_RDWR);
                close(Session->hDataServerSocket);
                shutdown(Session->hListeningClientSocket,SHUT_RDWR);
                close(Session->hListeningClientSocket);
                time(&EndTime);
                if(strlen(lpszParam)==0)
                    accesslog(Session,EndTime-BegTime,iSize,2,lpszFTPCmd);
                else
                    accesslog(Session,EndTime-BegTime,iSize,2,lpszParam);
		return TRUE;
	    }
            iSize+=iLen;
        }
        time(&EndTime);
        //save record to access log file
        if(strlen(lpszParam)==0)
            accesslog(Session,EndTime-BegTime,iSize,iStat,lpszFTPCmd);
        else
            accesslog(Session,EndTime-BegTime,iSize,iStat,lpszParam);
        //close connection
        shutdown(Session->hDataClientSocket,SHUT_RDWR);
        close(Session->hDataClientSocket);
        if(fAbort==FALSE){
	    sendreply(Session,S226MSG);
            logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),S226MSG);
        }
        else{
            strcpy(cBuf,S426MSG);
            strcat(cBuf,"\r\n");
            strcat(cBuf,S226AMSG);
	    sendreply(Session,cBuf);
            logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
        }
        shutdown(Session->hDataServerSocket,SHUT_RDWR);
        close(Session->hDataServerSocket);
        shutdown(Session->hListeningClientSocket,SHUT_RDWR);
        close(Session->hListeningClientSocket);
	logex(iClientNum,"iRetCode before check %d 2",iRetCode);
        while((iRetCode!=226)&&(iRetCode!=225)){
            iRetCode=getreply(Session,cBuf);
	    if(iRetCode==-1){
                logex(iClientNum,"Error getreply 2.");
		return FALSE;
	    }
	}
    }
    return TRUE;
}

//process LIST commnad
int listcmdprocces(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam){
    return datatransfercmd(Session,lpszFTPCmd,lpszParam,FALSE);
}

//process RETR command
int retrcmdprocces(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam){
    char cBuf[BUF_SIZE];
    //get file size
    sprintf(cBuf,"SIZE %s",lpszParam);
    sendcmd(Session,cBuf);
    int iRetCode=getreply(Session,cBuf);
    if(iRetCode==-1){
        logex(iClientNum,"RETR Error getreply 1.");
        return FALSE;
    }
    if(iRetCode!=213){
        sendreply(Session,S425MSG);
	if(Session->fActiveMode){
	    shutdown(Session->hListeningServerSocket,SHUT_RDWR);
	    close(Session->hListeningServerSocket);
        }
	else{
	    shutdown(Session->hListeningClientSocket,SHUT_RDWR);
	    close(Session->hListeningClientSocket);
        }
        return TRUE;
    }
    int iSize=0;
    sscanf(cBuf,"%d %d",&iRetCode,&iSize);
    //read max file size from config file
    if(getparam("MAXFILESIZE",cBuf)==FALSE)
        iMaxFileSize=0;
    else
        iMaxFileSize=atoi(cBuf);
    if(iMaxFileSize==0)
        iMaxFileSize=MAXFILESIZE;

    //check file size
    if(iSize>iMaxFileSize){
        sendreply(Session,S425MSG);
	if(Session->fActiveMode){
	    shutdown(Session->hListeningServerSocket,SHUT_RDWR);
	    close(Session->hListeningServerSocket);
        }
	else{
	    shutdown(Session->hListeningClientSocket,SHUT_RDWR);
	    close(Session->hListeningClientSocket);
        }
        return TRUE;
    }
    else
        return datatransfercmd(Session,lpszFTPCmd,lpszParam,FALSE);
}

//process STOR command
int storcmdprocces(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam){
    return datatransfercmd(Session,lpszFTPCmd,lpszParam,TRUE);
}

//send ABOR command to server
int aborcmdprocces(struct ClientParam *Session,char *lpszFTPCmd,char* lpszParam){
    char cBuf[BUF_SIZE];
    cBuf[0]=255;//IAC
    cBuf[1]=244;//IP
    int iLen=send(Session->hCtrlServerSocket,cBuf,2,MSG_OOB);
    cBuf[0]=255;//IAC
    cBuf[1]=242;//DM
    iLen=send(Session->hCtrlServerSocket,cBuf,2,0);
    strcpy(cBuf,"ABOR");
    strcat(cBuf,"\r\n");
    iLen=send(Session->hCtrlServerSocket,cBuf,strlen(cBuf),0);
    fsync(Session->hCtrlServerSocket);
    int iRetCode=getreply(Session,cBuf);
    sendreply(Session,cBuf);
    logex(iClientNum,"Logged %s(%s) < %s",Session->szUserName,inet_ntoa(Session->ClientAddr.sin_addr),cBuf);
    return TRUE;
}


