/*

    File: ftpp/socktool.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"
#include "unitools.h"

//connect to server
int servconnect(struct ClientParam *Session){
    char cBuf[BUF_SIZE];
    if(Session->hCtrlServerSocket==-1){
        Session->hCtrlServerSocket=socket(PF_INET,SOCK_STREAM,0);
        //connect
        int iRes=connect(Session->hCtrlServerSocket,(struct sockaddr *)&(Session->ServerAddr),sizeof(Session->ServerAddr));
        if(iRes==-1){
             strcpy(cBuf,S501MSG);
             strcat(cBuf,"\r\n");
             send(Session->hCtrlClientSocket,cBuf,strlen(cBuf),0);
             return FALSE;
        }
        else{
             //get server promt
             if(waitserver(Session)==FALSE){
                 close(Session->hCtrlServerSocket);
                 return FALSE;
             }
             int iRetCode=getreply(Session,cBuf);
             while(iRetCode==0){
                 iRetCode=getreply(Session,cBuf);
             }
             if(iRetCode==421)
             {
                 close(Session->hCtrlServerSocket);
                 return FALSE;
             }
             return TRUE;
         }
    }
    else
        return TRUE;
}

//wait while socket is ready for read
int waitread(int hHandle,struct timeval TimeOut){
    fd_set rfds;
    int iRetval=1;
    FD_ZERO(&rfds);
    FD_SET(hHandle,&rfds);
    iRetval = select(hHandle+1, &rfds, NULL, NULL, &TimeOut);
    return iRetval;
}

//wait while socket is ready for write
int waitwrite(int hHandle,struct timeval TimeOut){
    fd_set wfds;
    int iRetval=1;
    FD_ZERO(&wfds);
    FD_SET(hHandle,&wfds);
    iRetval = select(hHandle+1, NULL, &wfds, NULL, &TimeOut);
    return iRetval;
}

//wait while server not ready
int waitserver(struct ClientParam *Session){
    struct timeval tv;
    int iRetval=1;
    while (1) {
         tv.tv_sec = 0;
         tv.tv_usec = 500;
         iRetval=waitread(Session->hCtrlServerSocket,tv);
         if(iRetval)
              break;
    }
    return TRUE;
}

//wait while clientnot ready
int waitclient(struct ClientParam *Session){
    char cBuf[BUF_SIZE];
    fd_set rfds;
    struct timeval tv;
    struct itimerval stimeout,sotimeout;
    int iRetval=1,iTime=0;
    stimeout.it_value.tv_sec=30;
    stimeout.it_value.tv_usec=0;

   if(Session->fServerConnected==TRUE)
         setitimer(ITIMER_REAL,&stimeout,&sotimeout);
    while (1) {
         tv.tv_sec = 0;
         tv.tv_usec = 500;
         iRetval=waitread(Session->hCtrlClientSocket,tv);         
         if(iRetval)
              break;
         if(iTime*30==300){
             sendreply(Session,S421MSG);
             fClientDisconnected=TRUE;
             return FALSE;
         }
         getitimer(ITIMER_REAL,&stimeout);
         if((Session->fServerConnected==TRUE) & (stimeout.it_value.tv_sec==0)){
             iTime++;
             sendcmd(Session,NOOPCMD);
             logex(iClientNum,"30 sec timeout > %s",NOOPCMD);
             if(waitserver(Session)==FALSE){
                 return FALSE;
             }
             int iLen=recv(Session->hCtrlServerSocket,cBuf,BUF_SIZE,0);
             if(strlen(cBuf)>2)
                 cBuf[iLen-2]='\0';
             else
                 cBuf[iLen]='\0';
             stimeout.it_value.tv_sec=30;
             stimeout.it_value.tv_usec=0;
             setitimer(ITIMER_REAL,&stimeout,&sotimeout);
         }
    }
    return TRUE;
}

//send command to server
int sendcmd(struct ClientParam *Session,const char *lpszCmd){
    char cBuf[BUF_SIZE];
    strcpy(cBuf,lpszCmd);
    if((cBuf[strlen(cBuf)-2]!='\r') & (cBuf[strlen(cBuf)-2]!='\r'))
      	strcat(cBuf,"\r\n");
    int iRes=send(Session->hCtrlServerSocket,cBuf,strlen(cBuf),0);
    if((iRes=-1)&&(errno==EPIPE)){
	fClientDisconnected=TRUE;
	return -1;
    }
    else
        return iRes;
}

//send reply to client
int sendreply(struct ClientParam *Session,const char *lpszReply){
    char cBuf[BUF_SIZE];
    strcpy(cBuf,lpszReply);
    if((cBuf[strlen(cBuf)-2]!='\r') & (cBuf[strlen(cBuf)-2]!='\r'))
      	strcat(cBuf,"\r\n");
    int iRes = send(Session->hCtrlClientSocket,cBuf,strlen(cBuf),0);
    if((iRes=-1)&&(errno==EPIPE)){
	fClientDisconnected=TRUE;
	return -1;
    }
    else
        return iRes;
}

//read server reply
int getreply(struct ClientParam *Session,char *lpszReply){
    char cBuf[BUF_SIZE];
    struct timeval tv;
    tv.tv_sec = REPLY_TIMEOUT;
    tv.tv_usec = 0;

    if(waitread(Session->hCtrlServerSocket,tv)==FALSE)
      	return -1;
    int iLen=recv(Session->hCtrlServerSocket,cBuf,BUF_SIZE,0);
    if((iLen==-1)&&(errno==ENOTCONN))
        return -1;
    cBuf[iLen]='\0';
    strcpy(lpszReply,cBuf);
    char szLastStr[BUF_SIZE];
    char *lpszPtr=cBuf,*lpszPtrEx;
    strcpy(szLastStr,cBuf);
    int iPrevRes=0;
    while(lpszPtr!=NULL){
        if(szLastStr[3]==' '){
            szLastStr[3]='\0';
	    if((isdigit(szLastStr[0])!=0)&&(isdigit(szLastStr[1])!=0)&&(isdigit(szLastStr[2])!=0))
       	        iPrevRes=atoi(szLastStr);
	    else
		iPrevRes=iPrevRes;
	}
        lpszPtrEx=strstr(lpszPtr,"\r\n");
        if(lpszPtrEx!=NULL){
            int iLen=lpszPtrEx-lpszPtr;
            strncpy(szLastStr,lpszPtr,iLen);
            szLastStr[lpszPtrEx-lpszPtr]='\0';
            lpszPtr=lpszPtrEx+2;
            if(strlen(lpszPtr)==0)
                lpszPtr=NULL;
        }
        else{
            strcpy(szLastStr,lpszPtr);
            lpszPtr=NULL;
        }
    }
    if(szLastStr[3]==' '){
        if((isdigit(szLastStr[0])!=0)&&(isdigit(szLastStr[1])!=0)&&(isdigit(szLastStr[2])!=0)){
            szLastStr[3]='\0';
            return atoi(szLastStr);
        }
        else
	    return iPrevRes;
    }
    else
        return iPrevRes;
}

//convert host name to ip addres
int getipbyhost(char *lpszHostName){
    struct sockaddr_in addr;
    struct hostent *hp;
    if((hp = gethostbyname(lpszHostName)) == NULL) {
//        sendreply(Session,S501MSG);
        return FALSE;
    }
    memcpy(&(addr.sin_addr), hp->h_addr, hp->h_length);
    sprintf(lpszHostName,"%s",inet_ntoa(addr.sin_addr));
    return TRUE;
}

