Files
libraries/SDD/sdd_ftpx.c
Philip Smart af833c09ee Initial upload
2019-11-18 00:29:48 +00:00

2179 lines
70 KiB
C
Executable File

/******************************************************************************
* Product: ##### ###### ###### # ### ######
* # # # # # # # # # #
* # # # # # # # # #
* ##### # # # # # # ######
* # # # # # # # # #
* # # # # # # # # # #
* ##### ###### ###### ####### ####### ### ######
*
* File: sdd_ftpx.c
* Description: Server Data-source Driver library driver to handle direct
* FTP transfers to an FTP server.
*
* Version: %I%
* Dated: %D%
* Copyright: P.D. Smart, 1996-2019.
*
* History: 1.0 - Initial Release.
*
******************************************************************************
* This source file 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 3 of the License, or
* (at your option) any later version.
*
* This source file 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* Bring in system header files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
#include <sys/wait.h>
#include <unistd.h>
#endif
/* Indicate that we are a C module for any header specifics.
*/
#define SDD_FTPX_C
/* Bring in local specific header files.
*/
#include "sdd.h"
#include "sdd_ftpx.h"
/******************************************************************************
* Function: _FTPX_GetStrArg
* Description: Function to scan an input buffer and extract a string based
* argument.
*
* Returns: SDD_FAIL- Couldnt obtain argument.
* SDD_OK - Argument obtained.
******************************************************************************/
int _FTPX_GetStrArg( UCHAR *snzDataBuf, /* I: Input buffer */
int nDataLen, /* I: Len of data */
UCHAR *szArg, /* I: Arg to look for */
UCHAR **pszPath ) /* O: Pointer to argument */
{
/* Local variables.
*/
int nCmpLen;
int nPos;
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_FTPX_GetStrArg";
/* Go through the input buffer looking for 'szArg' within the
* input buffer. If it exists, then note the position just after it
* as this contains the string argument.
*/
for(nPos=0, nCmpLen=strlen(szArg); nPos < nDataLen; nPos++)
{
/* If a match occurs, then setup the pointer to correct location.
*/
if(strncmp(&snzDataBuf[nPos], szArg, nCmpLen) == 0)
{
/* Make sure that the match is not a sub-match as some of the
* variables we are scanning for are similar.
*/
if( (nPos == 0) ||
(nPos > 0 && snzDataBuf[nPos-1] == '\0') ||
(nPos > 0 && isspace(snzDataBuf[nPos-1])) )
{
nPos += nCmpLen;
break;
}
}
}
/* If the pointer did not reach the end of the buffer then we have
* located a valid name.
*/
if(nPos < nDataLen)
{
/* Setup the callers pointer to point to the correct location
* in the buffer.
*/
*pszPath = &snzDataBuf[nPos];
nReturn=SDD_OK;
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_GetMode
* Description: Function to scan an input buffer and determine the mode
* of FTP operation that the caller requires (Binary or Ascii). If
* no mode is provided then default to binary.
*
* Returns: Mode Flag - 1 = Binary mode selected.
* - 0 = Ascii mode selected.
******************************************************************************/
int _FTPX_GetMode( UCHAR *snzDataBuf, /* I: Input buffer */
int nDataLen ) /* I: Len of data */
{
/* Local variables.
*/
int nCmpLen;
int nPos;
int nReturn = FTP_BINARY_MODE;
UCHAR *szFunc = "_FTPX_GetMode";
/* Go through the input buffer looking for the MODE directive. If it
* exists then note the position just after it as this is the flag
* value indicating BINARY or ASCII.
*/
for(nPos=0, nCmpLen=strlen(FTP_MODE); nPos < nDataLen; nPos++)
{
/* If a match occurs, then setup the pointer to correct location.
*/
if(strncmp(&snzDataBuf[nPos], FTP_MODE, nCmpLen) == 0)
{
/* Make sure that the match is not a sub-match as some of the
* variables we are scanning for are similar.
*/
if( (nPos == 0) ||
(nPos > 0 && snzDataBuf[nPos-1] == '\0') ||
(nPos > 0 && isspace(snzDataBuf[nPos-1])) )
{
nPos += nCmpLen;
break;
}
}
}
/* If the pointer did not reach the end of the buffer then we have
* located the beginning of the argument list.
*/
if(nPos < nDataLen)
{
/* Does the user require Ascii mode? If he doesnt, then assume binary
* as its pointless error trapping here.
*/
if(strcasecmp(&snzDataBuf[nPos], FTP_ASCII) == 0)
{
nReturn = FTP_ASCII_MODE;
}
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_GetWriteData
* Description: Function to scan an input buffer, verify that it has data in it,
* extract the data and store in the opened file stream and
* set the start flag if the block is the final block.
*
* Returns: SDD_FAIL- Bad block of data or error writing to file.
* SDD_OK - Block obtained and stored.
******************************************************************************/
int _FTPX_GetWriteData( UCHAR *snzDataBuf, /* I: Input buffer */
int nDataLen, /* I: Len of data */
FILE *fpFile, /* IO: Opened file stream */
int *nLast, /* O: Last block flag */
UCHAR *szErrMsg ) /* O: Any resultant error msg */
{
/* Local variables.
*/
int nBlockSize;
int nCmpDataLen;
int nCmpEndLen;
int nPos;
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_FTPX_GetWriteData";
/* Initialise any required variables.
*/
*nLast = FALSE;
nCmpDataLen=strlen(FTP_DATA);
nCmpEndLen=strlen(FTP_END);
/* Go through the input buffer looking for FTP_DATA or FTP_END within the
* input buffer. If either exist then note position just after it
* as this contains the size of the data block as an ascii number. If
* FTP_END is detected then set the nLast flag to indicate last block.
*/
for(nPos=0; nPos < nDataLen; nPos++)
{
/* If a match occurs, then setup the pointer to correct location.
*/
if(strncmp(&snzDataBuf[nPos], FTP_DATA, nCmpDataLen) == 0 ||
strncmp(&snzDataBuf[nPos], FTP_END, nCmpEndLen) == 0)
{
/* Make sure that the match is not a sub-match as some of the
* variables we are scanning for are similar.
*/
if( (nPos == 0) ||
(nPos > 0 && snzDataBuf[nPos-1] == '\0') ||
(nPos > 0 && isspace(snzDataBuf[nPos-1])) )
{
if(strncmp(&snzDataBuf[nPos], FTP_DATA, nCmpDataLen) == 0)
{
nPos += nCmpDataLen;
} else
{
/* Setup the nLast flag as this is the last data block.
*/
*nLast = TRUE;
nPos += nCmpEndLen;
}
break;
}
}
}
/* If the pointer did not reach the end of the buffer then we have
* located a valid data block.
*/
if(nPos < nDataLen)
{
/* The following location upto a NULL byte should contain the
* size of the data block in ASCII representation so use scanf
* to extract the data accordingly.
*/
if(sscanf(&snzDataBuf[nPos], "%d", &nBlockSize) != 1)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg, "%s: Invalid Block Size provided",
SDD_EMSG_BADBLOCKSZ);
nReturn = SDD_FAIL;
goto _FTPX_GetWriteData_EXIT;
}
/* Update our index variable.
*/
nPos += (strlen(&snzDataBuf[nPos]) + 1);
/* Quick test before we go any further, ensure that the data
* provided is sufficient.
*/
if((nPos+nBlockSize) != nDataLen)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Data block size does not match data provided",
SDD_EMSG_BADBLOCKSZ);
nReturn = SDD_FAIL;
goto _FTPX_GetWriteData_EXIT;
}
/* Read data byte at a time and write to the opened file stream.
*/
while(nPos < nDataLen)
{
if(fputc(snzDataBuf[nPos], fpFile) == EOF)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Couldnt write to temporary file to store data",
SDD_EMSG_FILEERROR);
nReturn = SDD_FAIL;
break;
}
/* Time for pointer update... Could write the same data forever
* I suppose....
*/
nPos += 1;
}
}
/* I suppose we are successful.... this time!
*/
nReturn=SDD_OK;
_FTPX_GetWriteData_EXIT:
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_PutReadData
* Description: Function to read an open stream and transmit the data
* contents to the caller via the callback mechanism.
*
* Returns: SDD_FAIL- Couldnt obtain PATH.
* SDD_OK - PATH obtained.
******************************************************************************/
int _FTPX_PutReadData( FILE *fpFile, /* I: Stream to read from */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: CB to send data to */
UCHAR *szErrMsg ) /* O: Error text */
{
/* Local variables.
*/
int nChar;
int nEnd = FALSE;
int nNdx;
int nReturn;
UCHAR szRetBuf[MAX_RETURN_BUF];
UCHAR *szFunc = "_FTPX_PutReadData";
/* Loop, extracting data from the input stream and sending it to the
* users callback in MAX_RETURN_BUF (ID + MAX_RETURN_BUF-1 bytes data)
* byte blocks until we reach the end.
*/
while(nEnd == FALSE)
{
/* Initialise any loop variables.
*/
nNdx=1;
/* Loop until the return buffer becomes full or we run out of data.
*/
while(nNdx < (MAX_RETURN_BUF-1) && (nChar=fgetc(fpFile)) != EOF)
{
szRetBuf[nNdx] = (UCHAR)nChar;
nNdx++;
}
/* Is this the end of the input stream?
*/
if(nChar == EOF)
{
/* Set flag as we've got to end of the file, time to get out.
*/
nEnd = TRUE;
/* Set the first location in the input buffer to indicate last
* block.
*/
szRetBuf[0] = SDD_ENDBLOCK;
} else
{
/* Set the first location in the input buffer to indicate that
* this is one of many data blocks.
*/
szRetBuf[0] = SDD_DATABLOCK;
}
/* Call function to transmit row to original caller.
*/
if(fSendDataCB(szRetBuf, nNdx) == SDD_FAIL)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Failed to send row back to client", SDD_EMSG_SENDROW);
nReturn = SDD_FAIL;
nEnd = TRUE;
}
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_PIDataCB
* Description: Function to handle any control information passed back from
* the FTP server.
*
* Returns: No returns.
******************************************************************************/
void _FTPX_PIDataCB( UINT nChanId, /* I: Channel data arrived on */
UCHAR *szData, /* I: Actual data */
UINT nDataLen ) /* I: Length of data */
{
/* Local variables.
*/
UINT nA1, nA2, nA3, nA4;
UINT nNdx;
UINT nP1, nP2;
UCHAR *spNewBuf = NULL;
UCHAR *spTmp = NULL;
UCHAR *spTmp2 = NULL;
UCHAR *szFunc = "_FTPX_PIDataCB";
/* If needed, create initial FTP buffer.
*/
if(FTPX.snzPIDataBuf == NULL)
{
if((FTPX.snzPIDataBuf=(UCHAR *)malloc(DEF_FTP_BUF_SIZE)) == NULL)
{
Lgr(LOG_DEBUG, szFunc,
"Couldnt malloc initial FTP buffer, wasting data");
return;
}
/* Setup initial size.
*/
FTPX.nPIDataBufLen = DEF_FTP_BUF_SIZE;
FTPX.nPIDataBufPos = 0;
}
/* If the data will overfill our buffer, then grow it to accomodate.
*/
if( (FTPX.nPIDataBufPos+nDataLen) > FTPX.nPIDataBufLen)
{
/* For safety's sake, an upper limit on the size of the
* receive buffer has to be implemented. If this ceiling
* is hit, then assume something is going wrong, so keep
* the current buffer, but dump the contents.
*/
if( FTPX.nPIDataBufLen >= MAX_FTP_BUF_SIZE )
{
Lgr(LOG_DEBUG, szFunc,
"Exceeded maximum size of recv buffer, dumping");
FTPX.nPIDataBufPos = 0;
return;
}
/* OK, lets grow the buffer by a fixed size. If no memory
* is available, then keep the current buffer, just stop
* reading. Later functionality will prune the data.
*/
if((spNewBuf=(UCHAR *)malloc(FTPX.nPIDataBufLen+DEF_FTP_BUF_INCSIZE))
== NULL)
{
Lgr(LOG_DEBUG, szFunc, "Couldnt malloc (%d) bytes",
DEF_FTP_BUF_INCSIZE);
return;
}
/* Copy the old buffer onto the new, so we can release it
* back to the sys pool.
*/
for(spTmp=FTPX.snzPIDataBuf, spTmp2=spNewBuf, nNdx=FTPX.nPIDataBufLen;
nNdx != 0; nNdx--, *spTmp2 = *spTmp, spTmp++, spTmp2++);
/* Get rid of old buffer, and update pointers to accomodate the new
* buffer and new size values.
*/
free(FTPX.snzPIDataBuf);
FTPX.snzPIDataBuf = spNewBuf;
FTPX.nPIDataBufLen += DEF_FTP_BUF_INCSIZE;
/* Log a message indicating that the buffer has grown in size.
*/
Lgr(LOG_DEBUG, szFunc,
"Allocated new receive buffer of %d bytes", FTPX.nPIDataBufLen);
}
/* Copy data from passed buffer into our buffer.
*/
for(nNdx=FTPX.nPIDataBufPos; nNdx < (FTPX.nPIDataBufPos+nDataLen); nNdx++)
{
FTPX.snzPIDataBuf[nNdx] = szData[nNdx-FTPX.nPIDataBufPos];
}
FTPX.nPIDataBufPos += nNdx;
/* Scan through the buffer looking for the start of a number as
* this will represent the FTP Server response code.
*/
for(nNdx=0; nNdx < FTPX.nPIDataBufPos; nNdx++)
{
if(isdigit(FTPX.snzPIDataBuf[nNdx]))
break;
}
/* Digit detected? If not, fall through and wait for more data to
* arrive.
*/
if(nNdx < FTPX.nPIDataBufPos)
{
/* Get number.
*/
sscanf(&FTPX.snzPIDataBuf[nNdx], "%d", &FTPX.nPIResponseCode);
/* Special case handling if weve entered passive mode.
*/
if(FTPX.nPIResponseCode == FTP_RESPONSE_PASSIVE)
{
/* Extract the IP address and port number from the response.
*/
if(sscanf(&FTPX.snzPIDataBuf[nNdx+27], "%d,%d,%d,%d,%d,%d",
&nA1, &nA2, &nA3, &nA4, &nP1, &nP2) == 6)
{
/* Build up address and port number in useable form.
*/
FTPX.lDTPIPaddr = ((ULNG)nA1*16777216L) + ((ULNG)nA2*65536L) +
((ULNG)nA3*256L) + (ULNG)nA4;
FTPX.nDTPPortNo = (nP1*256) + nP2;
} else
{
FTPX.nPIResponseCode == FTP_RESPONSE_NONE;
}
}
/* Clear buffer, data no longer needed.
*/
FTPX.nPIDataBufPos = 0;
}
/* Return to caller.
*/
return;
}
/******************************************************************************
* Function: _FTPX_PICtrlCB
* Description: Function to handle any control callbacks during connectivity
* with the FTP server.
*
* Returns: No returns.
******************************************************************************/
void _FTPX_PICtrlCB( int nType, /* I: Type of callback */
... ) /* I: Var args */
{
/* Local variables.
*/
UINT nChanId;
UINT nPortNo;
ULNG lIPaddr;
va_list pArgs;
UCHAR *szFunc = "_FTPX_PICtrlCB";
/* Start var-arg list by making pArgs point to first arg in list.
*/
va_start(pArgs, nType);
/* What type of callback is it....?
*/
switch(nType)
{
/* A new connection has arrived.
*/
case SLC_NEWSERVICE:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link going down event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"New Service with client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
break;
/* A connection has been made
*/
case SLC_CONNECT:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
Lgr(LOG_DEBUG, szFunc,
"Connected to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
SL_RawMode(nChanId, TRUE);
break;
/* Given connection has become temporarily unavailable.
*/
case SLC_LINKDOWN:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link going down event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"Link down to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
/* Get rid of connection, no longer needed.
*/
SL_DelClient(FTPX.nPIChanId);
FTPX.nPIChanId = 0;
break;
/* Given connection has died.
*/
case SLC_LINKFAIL:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link failure event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"Link closed to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
break;
default:
/* Log a message as this condition shouldnt occur.
*/
Lgr(LOG_DEBUG, szFunc, "Unrecognised message type (%d)", nType);
break;
}
/* Return to caller.
*/
return;
}
/******************************************************************************
* Function: _FTPX_DTPDataCB
* Description: Function to handle any data passed back from the FTP server on
* the data transfer connection..
*
* Returns: No returns.
******************************************************************************/
void _FTPX_DTPDataCB( UINT nChanId, /* I: Channel data arrived on */
UCHAR *szData, /* I: Actual data */
UINT nDataLen ) /* I: Length of data */
{
/* Local variables.
*/
UINT nNdx;
UCHAR *szFunc = "_FTPX_DTPDataCB";
/* Simply store the data into our opened file buffer.
*/
if(FTPX.fDataFile == NULL)
{
return;
}
/* Copy data byte at a time into the storage file.
*/
for(nNdx=0; nNdx < nDataLen; nNdx++)
{
fputc(szData[nNdx], FTPX.fDataFile);
}
/* Return to caller.
*/
return;
}
/******************************************************************************
* Function: _FTPX_DTPCtrlCB
* Description: Function to handle any control callbacks on the Data Transfer
* connection with the FTP server.
*
* Returns: No returns.
******************************************************************************/
void _FTPX_DTPCtrlCB( int nType, /* I: Type of callback */
... ) /* I: Var args */
{
/* Local variables.
*/
UINT nChanId;
UINT nPortNo;
ULNG lIPaddr;
va_list pArgs;
UCHAR *szFunc = "_FTPX_DTPCtrlCB";
/* Start var-arg list by making pArgs point to first arg in list.
*/
va_start(pArgs, nType);
/* What type of callback is it....?
*/
switch(nType)
{
/* A new connection has arrived.
*/
case SLC_NEWSERVICE:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link going down event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"New Service with client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
/* Set channel into raw mode.
*/
SL_RawMode(nChanId, TRUE);
/* Store the channel id, because a server connection only
* liberates the channel id at this point.
*/
FTPX.nDTPChanId=nChanId;
FTPX.nDTPConnected=TRUE;
break;
/* A connection has been made
*/
case SLC_CONNECT:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
Lgr(LOG_DEBUG, szFunc,
"Connected to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
SL_RawMode(nChanId, TRUE);
FTPX.nDTPConnected = TRUE;
break;
/* Given connection has become temporarily unavailable.
*/
case SLC_LINKDOWN:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link going down event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"Link down to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
/* Mark channel as closed.
*/
FTPX.nDTPConnected = FALSE;
/* On a link down, remove the connection entry as its no longer
* needed.
*/
SL_DelClient(FTPX.nDTPChanId);
FTPX.nDTPChanId = 0;
break;
/* Given connection has died.
*/
case SLC_LINKFAIL:
nChanId = va_arg(pArgs, UINT);
nPortNo = va_arg(pArgs, UINT);
lIPaddr = va_arg(pArgs, ULNG);
/* Log link failure event for bug catching.
*/
Lgr(LOG_DEBUG, szFunc,
"Link closed to client: nChanId=%d, nPortNo=%d, IP=%s",
nChanId, nPortNo, SL_HostIPtoString(lIPaddr));
/* Mark channel as closed.
*/
FTPX.nDTPConnected = FALSE;
break;
default:
/* Log a message as this condition shouldnt occur.
*/
Lgr(LOG_DEBUG, szFunc, "Unrecognised message type (%d)", nType);
break;
}
/* Return to caller.
*/
return;
}
/******************************************************************************
* Function: _FTPX_PIGetResponse
* Description: Function to get a response code from the FTP server.
*
* Returns: Response Code.
******************************************************************************/
int _FTPX_PIGetResponse( void )
{
/* Local variables.
*/
UINT nTotalTime;
UCHAR *szFunc = "_FTPX_PIGetResponse";
/* Setup what type of data we are looking for from FTP server.
*/
FTPX.nPIResponseCode = FTP_RESPONSE_NONE;
/* OK, lets go into a loop state until we get a required response.
*/
nTotalTime = 0;
while(FTP_CONNECT_TIME > nTotalTime &&
FTPX.nPIResponseCode==FTP_RESPONSE_NONE)
{
SL_Poll((ULNG)1);
nTotalTime += 1;
}
/* Return to caller.
*/
return(FTPX.nPIResponseCode);
}
/******************************************************************************
* Function: _FTPX_PISendCmd
* Description: Function to send a command to an FTP server.
*
* Returns: SDD_FAIL - FTP Server failed to respond, see szErrMsg.
* SDD_OK - Command sent successfully.
******************************************************************************/
int _FTPX_PISendCmd( UCHAR *szCmd, /* I: Command to send */
UINT *panReqResponses, /* I: Array of req resp */
UCHAR *szErrMsg ) /* O: Error message */
{
/* Local variables.
*/
UINT nNdx;
UINT nResponse;
UINT nReturn = SDD_FAIL;
UCHAR *szFunc = "_FTPX_PISendCmd";
/* Send command to FTP server.
*/
if(SL_BlockSendData(FTPX.nPIChanId, (UCHAR *)szCmd, strlen(szCmd)) != R_OK)
{
sprintf(szErrMsg, "Couldnt send command '%s' to FTP server", szCmd);
return(SDD_FAIL);
}
/* If caller requires a certain set of response to the issued command, then
* obtain a response and match it.
*/
if(panReqResponses == NULL || panReqResponses[0] != FTP_RESPONSE_NONE)
{
/* Get the response from the executed command.
*/
nResponse=_FTPX_PIGetResponse();
/* See if the response exists in the array that the caller has
* passed.
*/
for(nNdx=0; nResponse != FTP_RESPONSE_NONE &&
panReqResponses[nNdx] != FTP_RESPONSE_NONE; nNdx++)
{
if(panReqResponses[nNdx] == nResponse)
break;
}
/* If there was no response or rthe response did not match any of
* the callers then indicate error.
*/
if(nResponse == FTP_RESPONSE_NONE ||
panReqResponses[nNdx] == FTP_RESPONSE_NONE)
{
sprintf(szErrMsg, "Illegal response '%d' obtained for command '%s'",
nResponse, szCmd);
} else
{
nReturn = SDD_OK;
}
} else
{
nReturn = SDD_OK;
}
/* Return to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_PIGetDTPResponse
* Description: Function to get a response code during a DTP transfer.
*
* Returns: Response Code.
******************************************************************************/
int _FTPX_PIGetDTPResponse( void )
{
/* Local variables.
*/
UINT nTotalTime;
UCHAR *szFunc = "_FTPX_PIGetResponse";
/* Setup what type of data we are looking for from FTP server.
*/
FTPX.nPIResponseCode = FTP_RESPONSE_NONE;
/* OK, lets go into a loop state until we get a required response.
*/
nTotalTime = 0;
while( FTP_CONNECT_TIME > nTotalTime )
{
SL_Poll((ULNG) 1);
nTotalTime += 1;
if(FTPX.nPIResponseCode!=FTP_RESPONSE_NONE && FTPX.nDTPConnected==FALSE)
break;
}
/* Return to caller.
*/
return(FTPX.nPIResponseCode);
}
/******************************************************************************
* Function: _FTPX_PISendDTPCmd
* Description: Function to send a command to an FTP server which will invoke
* a DTP channel for data transfer.
*
* Returns: SDD_FAIL - FTP Server failed to respond, see szErrMsg.
* SDD_OK - Command sent successfully.
******************************************************************************/
int _FTPX_PISendDTPCmd( UCHAR *szCmd, /* I: Command to send */
UINT *panReqResponses, /* I: Allowed responses */
UCHAR *szErrMsg ) /* O: Error message */
{
/* Local variables.
*/
UINT anResponses[3];
UINT nPortNo;
UINT nReturn = SDD_OK;
UINT nTotalTime;
ULNG lIPAddr;
UCHAR szTmp[MAX_TMP_BUF_SIZE];
UCHAR *szFunc = "_FTPX_PISendDTPCmd";
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_PASSIVE;
anResponses[1] = FTP_RESPONSE_NONE;
/* Tel FTP server to enter into passive mode.
*/
if(_FTPX_PISendCmd("PASV\r\n", anResponses, szErrMsg) == SDD_OK)
{
/* OK, FTP server has entered passive mode, so lets build a Data
* Transfer link to it.
*/
if((FTPX.nDTPChanId = SL_AddClient(FTPX.nDTPPortNo, FTPX.lDTPIPaddr,
"DTP Channel", _FTPX_DTPDataCB,
_FTPX_DTPCtrlCB)) < 0)
{
sprintf(szErrMsg, "Couldnt build DTP connection");
return(SDD_FAIL);
}
/* Reset flag so that when connection is built we can detect it.
*/
FTPX.nDTPConnected = FALSE;
/* OK, lets go into a loop state until we get a required response.
*/
nTotalTime = 0;
while(FTP_CONNECT_TIME > nTotalTime && FTPX.nDTPConnected == FALSE)
{
SL_Poll((ULNG) 1);
nTotalTime += 1;
}
/* Was the connection made?
*/
if(FTPX.nDTPConnected == FALSE)
{
sprintf(szErrMsg, "Couldnt build DTP connection");
return(SDD_FAIL);
}
} else
{
/* Look for a port we can hang on to.
*/
for(nPortNo=DEF_SRV_START_PORT; nPortNo < DEF_SRV_END_PORT; nPortNo++)
{
/* Try and add a service on this port, if ok, then exit and run
* with it.
*/
if(SL_AddServer(nPortNo, FALSE, _FTPX_DTPDataCB,
_FTPX_DTPCtrlCB) == SDD_OK)
break;
}
/* Have we reached the limit? If we have, give up, saturated server
* or what!!
*/
if(nPortNo == DEF_SRV_END_PORT)
{
sprintf(szErrMsg, "Couldnt add a service port for DTP channel");
return(SDD_FAIL);
}
/* OK, lets tell the FTP server that we are listening for a
* connection. Firstly, work out who we are.
*/
gethostname(szTmp, MAX_TMP_BUF_SIZE);
if(SL_GetIPaddr(szTmp, &lIPAddr) != R_OK)
{
sprintf(szErrMsg, "Couldnt get our IP address");
return(SDD_FAIL);
}
/* Convert the IP address and Port number into easy blocks for
* inserting into our command.
*/
PutCharFromLong(szTmp, lIPAddr);
PutCharFromInt(&szTmp[4], nPortNo);
/* Build up the command to instruct the FTP server.
*/
sprintf(&szTmp[6], "PORT %d,%d,%d,%d,%d,%d\r\n",
(UINT)szTmp[0], (UINT)szTmp[1], (UINT)szTmp[2],
(UINT)szTmp[3], (UINT)szTmp[4], (UINT)szTmp[5]);
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_CWDOK;
anResponses[1] = FTP_RESPONSE_CMDOK;
anResponses[2] = FTP_RESPONSE_NONE;
/* Fire the command at the server and stand back.....Ce'st la vie.
*/
if(_FTPX_PISendCmd(&szTmp[6], anResponses, szErrMsg) == SDD_FAIL)
{
sprintf(szErrMsg, "Couldnt instruct FTP server to use port %d",
nPortNo);
return(SDD_FAIL);
}
}
/* Send command to FTP server
*/
if(_FTPX_PISendCmd(szCmd, panReqResponses, szErrMsg) != SDD_OK)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": Failed to obtain valid response from FTP server");
return(SDD_FAIL);
}
/* Return to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_SetMode
* Description: Function to setup the transfer mode between the FTP server and
* the driver.
*
* Returns: SDD_FAIL - Failed to set transfer mode, critical error.
* SDD_OK - Mode set.
******************************************************************************/
int _FTPX_SetMode( UINT nBinaryMode, /* I: Select binary mode = TRUE */
UCHAR *szErrMsg ) /* O: Generated error messages */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT anResponses[3];
UCHAR *szFunc = "_FTPX_SetMode";
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_CMDOK;
anResponses[1] = FTP_RESPONSE_CWDOK;
anResponses[2] = FTP_RESPONSE_NONE;
/* Enable binary mode or ascii?
*/
if( nBinaryMode == TRUE)
{
nReturn=_FTPX_PISendCmd("TYPE I\r\n", anResponses, szErrMsg);
} else
{
nReturn=_FTPX_PISendCmd("TYPE A\r\n", anResponses, szErrMsg);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_SetCwd
* Description: Function to set the FTP servers current working directory.
*
* Returns: SDD_FAIL - Failed to set directory to that specified.
* SDD_OK - Current Working Directory set.
******************************************************************************/
int _FTPX_SetCwd( UCHAR *szPath, /* I: Path to set CWD */
UCHAR *szErrMsg ) /* O: Generated error messages */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT anResponses[3];
UCHAR *pszCmd;
UCHAR *szFunc = "_FTPX_SetCwd";
/* Allocate required memory for the command buffer.
*/
if((pszCmd=(UCHAR *)malloc(strlen(szPath)+7)) == NULL)
{
sprintf(szErrMsg, "Couldnt allocate memory for CWD command");
return(SDD_FAIL);
}
/* Setup command to change the remote directory to that required.
*/
sprintf(pszCmd, "CWD %s\r\n", szPath);
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_CMDOK;
anResponses[1] = FTP_RESPONSE_CWDOK;
anResponses[2] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
nReturn=_FTPX_PISendCmd(pszCmd, anResponses, szErrMsg);
/* Free up resources, no longer needed.
*/
free(pszCmd);
/* If a failure occurred, tag on our reason code as well.
*/
if(nReturn == SDD_FAIL)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": Couldnt change CWD to '%' on remote", szPath);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_FTPInit
* Description: Function to initialise a connection with an FTP server. The
* caller provides the name/IP address of the server and the
* user name/password to complete the connection.
*
* Returns: SDD_FAIL - Couldnt make connection with given details.
* SDD_OK - FTP connection made.
******************************************************************************/
int _FTPX_FTPInit( UCHAR *szFTPServer, /* I: Name of FTP server */
UCHAR *szUserName, /* I: User name to login with */
UCHAR *szPassword, /* I: Password for login */
UCHAR *szErrMsg ) /* O: Error message if failed */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT anResponses[2];
UINT nFTPPortNo;
ULNG lIPAddr;
UCHAR *pszCmd;
UCHAR *szFunc = "_FTPX_FTPInit";
/* Setup any module variables to an initial state.
*/
FTPX.nPIResponseCode = FTP_RESPONSE_NONE;
FTPX.nPIChanId = 0;
FTPX.nDTPChanId = 0;
FTPX.nPIDataBufLen = 0;
FTPX.nPIDataBufPos = 0;
FTPX.snzPIDataBuf = NULL;
FTPX.lDTPIPaddr = 0;
FTPX.nDTPPortNo = 0;
FTPX.nDTPConnected = FALSE;
FTPX.fDataFile = NULL;
/* Get the IP address of the host we are connecting with.
*/
if(SL_GetIPaddr(szFTPServer, &lIPAddr) != R_OK)
{
sprintf(szErrMsg, "Server %s does not appear in hosts file",
szFTPServer);
return(SDD_FAIL);
}
/* Lookup port number for FTP service.
*/
if(SL_GetService(DEF_FTP_SERVICE_NAME, &nFTPPortNo) != R_OK)
{
sprintf(szErrMsg, "FTP service '%s' does not appear in services file",
DEF_FTP_SERVICE_NAME);
return(SDD_FAIL);
}
/* OK, got IP address and port number, so lets build a connection to
* it.
*/
if((FTPX.nPIChanId = SL_AddClient(nFTPPortNo, lIPAddr, szFTPServer,
_FTPX_PIDataCB, _FTPX_PICtrlCB)) < 0)
{
sprintf(szErrMsg, "Couldnt build IP connection to %s", szFTPServer);
return(SDD_FAIL);
}
/* Have we connected?
*/
if(_FTPX_PIGetResponse() != FTP_RESPONSE_CONNECTED)
{
sprintf(szErrMsg, "Couldnt build IP connection to %s", szFTPServer);
return(SDD_FAIL);
}
/* Allocate required memory for the command buffer.
*/
if((pszCmd=(UCHAR *)malloc(strlen(szUserName)+strlen(szPassword)+8))==NULL)
{
sprintf(szErrMsg, "Couldnt allocate memory during FTP initialisation");
return(SDD_FAIL);
}
/* OK, send the FTP server the User name.
*/
sprintf(pszCmd, "USER %s\r\n", szUserName);
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_USEROK;
anResponses[1] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
if(_FTPX_PISendCmd(pszCmd, anResponses, szErrMsg) != SDD_OK)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": Couldnt login to FTP server with user '%s'", szUserName);
free(pszCmd);
return(SDD_FAIL);
}
/* OK, send the FTP server the Password for above user name.
*/
sprintf(pszCmd, "PASS %s\r\n", szPassword);
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_PWDOK;
anResponses[1] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
nReturn=_FTPX_PISendCmd(pszCmd, anResponses, szErrMsg);
/* Free up memory buffer, no longer needed.
*/
free(pszCmd);
/* If a failure occurred on last command, tag on our reason code.
*/
if(nReturn == SDD_FAIL)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": Couldnt login to FTP server with password '%s'", szPassword);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_FTPClose
* Description: Function to close a connected FTP connection and tidy up
* in preparation for next task.
*
* Returns: SDD_FAIL - Failed to close properly, library wont work again.
* SDD_OK - Closed.
******************************************************************************/
int _FTPX_FTPClose( UCHAR *szErrMsg ) /* O: Generated error messages */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT anResponses[2];
UCHAR *szFunc = "_FTPX_FTPClose";
/* If the PI channel is open, close it by issuing the QUIT command to
* the FTP server then deleting the connection.
*/
if(FTPX.nPIChanId != 0)
{
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_GOODBYE;
anResponses[1] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
_FTPX_PISendCmd("QUIT\r\n", anResponses, szErrMsg);
/* Delete the physical connection.
*/
SL_DelClient(FTPX.nPIChanId);
FTPX.nPIChanId = 0;
}
/* If the DTP channel is open (shouldnt be!!!), delete the connection.
*/
if(FTPX.nDTPChanId != 0)
{
/* Delete the physical connection.
*/
SL_DelClient(FTPX.nDTPChanId);
FTPX.nDTPChanId = 0;
}
/* Free the PI data buffer if still allocated.
*/
if(FTPX.snzPIDataBuf != NULL)
{
free(FTPX.snzPIDataBuf);
}
/* If the data file is still open, close it and reset.
*/
if(FTPX.fDataFile != NULL)
{
fclose(FTPX.fDataFile);
FTPX.fDataFile = NULL;
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_FTPRenFile
* Description: Function to rename a file on a remote FTP server.
*
* Returns: SDD_FAIL - Failed to rename the required file.
* SDD_OK - File renamed successfully.
******************************************************************************/
int _FTPX_FTPRenFile( UCHAR *szPath, /* I: Path to remote file */
UCHAR *szSrcFile, /* I: Original remote file name */
UCHAR *szDstFile, /* I: New remote file name */
UCHAR *szErrMsg ) /* O: Generated error messages */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT anResponses[3];
UCHAR *pszCmd;
UCHAR *szFunc = "_FTPX_FTPRenFile";
/* Change to correct directory on remote.
*/
if(_FTPX_SetCwd(szPath, szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Allocate required memory for the command buffer.
*/
if((pszCmd=(UCHAR *)malloc(strlen(szSrcFile)+strlen(szDstFile)+10))==NULL)
{
sprintf(szErrMsg, "Couldnt allocate memory for command buffer");
return(SDD_FAIL);
}
/* Setup command to issue the FROM portion of the rename command.
*/
sprintf(pszCmd, "RNFR %s\r\n", szSrcFile);
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_RENFROK;
anResponses[1] = FTP_RESPONSE_NONE;
/* Issue part 1 of the rename sequence.
*/
if(_FTPX_PISendCmd(pszCmd, anResponses, szErrMsg) == SDD_FAIL)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": FTP server couldnt locate file '%s'", szSrcFile);
free(pszCmd);
return(SDD_FAIL);
}
/* Setup command to issue the TO portion of the rename command.
*/
sprintf(pszCmd, "RNTO %s\r\n", szDstFile);
/* Setup allowed responses.
*/
anResponses[0] = FTP_RESPONSE_CWDOK;
anResponses[1] = FTP_RESPONSE_CMDOK;
anResponses[2] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
nReturn=_FTPX_PISendCmd(pszCmd, anResponses, szErrMsg);
/* Free up command buffer, no longer needed.
*/
free(pszCmd);
/* If the above command failed, tag on our reason code and exit.
*/
if(nReturn == SDD_FAIL)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": FTP server couldnt rename to file '%s'", szDstFile);
return(SDD_FAIL);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_FTPRcvFile
* Description: Function to initiate a file transfer from the FTP server
* to the current machine file system.
*
* Returns: SDD_FAIL - Failed to complete file transfer.
* SDD_OK - File received successfully.
******************************************************************************/
int _FTPX_FTPRcvFile( UCHAR *szRcvFile, /* I: Name of file to store in */
UCHAR *szPath, /* I: Path to remote file */
UCHAR *szFile, /* I: Remote file */
UINT nBinaryMode, /* I: Select binary transfer mode */
UCHAR *szErrMsg ) /* O: Generated error messages */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT anResponses[2];
UCHAR *pszCmd;
UCHAR *szFunc = "_FTPX_FTPRcvFile";
/* Setup transfer mode.
*/
if(_FTPX_SetMode(nBinaryMode, szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Change to correct directory on remote.
*/
if(_FTPX_SetCwd(szPath, szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Open file to store data into.
*/
if((FTPX.fDataFile=fopen(szRcvFile, "w")) == NULL)
{
sprintf(szErrMsg, "Could not open '%s' for writing", szRcvFile);
return(SDD_FAIL);
}
/* Allocate required memory for the command buffer.
*/
if((pszCmd=(UCHAR *)malloc(strlen(szFile)+8))==NULL)
{
sprintf(szErrMsg, "Couldnt allocate memory for command buffer");
return(SDD_FAIL);
}
/* Setup command to retrieve the required file.
*/
sprintf(pszCmd, "RETR %s\r\n", szFile);
/* Setup required responses.
*/
anResponses[0] = FTP_RESPONSE_DATASTART;
anResponses[1] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
nReturn=_FTPX_PISendDTPCmd(pszCmd, anResponses, szErrMsg);
/* Free up command buffer, no longer needed.
*/
free(pszCmd);
/* If the above command failed, tag on our reason code and exit.
*/
if(nReturn == SDD_FAIL)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": Failed to receive data file '%s'", szFile);
return(SDD_FAIL);
}
/* Have we connected?
*/
if(_FTPX_PIGetDTPResponse() != FTP_RESPONSE_DATAEND)
{
sprintf(szErrMsg, "Failure to receive data file '%s'", szFile);
return(SDD_FAIL);
}
/* OK, all done, so close the file and prepare to exit.
*/
fclose(FTPX.fDataFile);
FTPX.fDataFile=NULL;
/* Ensure that the link between us and FTP server is severed.
*/
SL_DelClient(FTPX.nDTPChanId);
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _FTPX_FTPXmitFile
* Description: Function to initiate a file transfer from the current machine
* file system to the FTP server.
*
* Returns: SDD_FAIL - Failed to complete file transfer.
* SDD_OK - File transmitted successfully.
******************************************************************************/
int _FTPX_FTPXmitFile( UCHAR *szXmitFile, /* I: Name of file to transmit */
UCHAR *szPath, /* I: Path to remote destination */
UCHAR *szFile, /* I: Remote file */
UINT nBinaryMode, /* I: Select binary transfer Mode */
UCHAR *szErrMsg ) /* O: Generated error messages */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UINT nChar;
UINT nNdx;
UINT anResponses[2];
UINT nSending;
UCHAR *pszCmd;
UCHAR *pszDataBuf;
UCHAR *szFunc = "_FTPX_FTPXmitFile";
/* Setup transfer mode.
*/
if(_FTPX_SetMode(nBinaryMode, szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Change to correct directory on remote.
*/
if(_FTPX_SetCwd(szPath, szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Open the file for transmission.
*/
if((FTPX.fDataFile=fopen(szXmitFile, "r")) == NULL)
{
sprintf(szErrMsg, "Could not open '%s' for reading", szXmitFile);
return(SDD_FAIL);
}
/* Allocate required memory for the command buffer.
*/
if((pszCmd=(UCHAR *)malloc(strlen(szFile)+8))==NULL)
{
sprintf(szErrMsg, "Couldnt allocate memory for command buffer");
return(SDD_FAIL);
}
/* Setup command to store the required file.
*/
sprintf(pszCmd, "STOR %s\r\n", szFile);
/* Setup required responses.
*/
anResponses[0] = FTP_RESPONSE_DATASTART;
anResponses[1] = FTP_RESPONSE_NONE;
/* Send command to FTP server.
*/
nReturn=_FTPX_PISendDTPCmd(pszCmd, anResponses, szErrMsg);
/* Free up command buffer, no longer needed.
*/
free(pszCmd);
/* If last command failed, tag on our reason code and exit.
*/
if(nReturn == SDD_FAIL)
{
sprintf(&szErrMsg[strlen(szErrMsg)],
": Failed to transmit data file '%s'", szFile);
return(SDD_FAIL);
}
/* Allocate required memory for the transmit data buffer.
*/
if((pszDataBuf=(UCHAR *)malloc(DEF_FTP_XMIT_SIZE+1))==NULL)
{
sprintf(szErrMsg, "Couldnt allocate memory for xmit data buffer");
return(SDD_FAIL);
}
/* Transmit the contents of the file by going in a tight loop and sending
* packets of a predetermined size to the FTP server.
*/
for(nSending=TRUE, nNdx=0; nSending == TRUE; nNdx=0)
{
/* Fill our buffer with data from the file, cutting short if the
* file end is reached.
*/
while(nNdx < DEF_FTP_XMIT_SIZE && (nChar=fgetc(FTPX.fDataFile)) != EOF)
{
pszDataBuf[nNdx] = (UCHAR)nChar;
nNdx++;
}
/* If we have reached the end of the file then set the flag such
* that we fall out of this loop.
*/
if(nChar == EOF)
{
nSending=FALSE;
}
/* If there is any data in the buffer, then send it, regardless of
* wether we are at the end of the file.
*/
if(nNdx > 0)
{
if(SL_BlockSendData(FTPX.nDTPChanId,(UCHAR *)pszDataBuf,nNdx)!=R_OK)
{
sprintf(szErrMsg, "Couldnt send data to FTP server");
free(pszDataBuf);
return(SDD_FAIL);
}
}
}
/* Free up memory, no longer needed.
*/
free(pszDataBuf);
/* Close the DTP channel, which in turn indicates to the FTP server that
* data transmission is complete.
*/
SL_DelClient(FTPX.nDTPChanId);
FTPX.nDTPChanId = 0;
FTPX.nDTPConnected=FALSE;
/* Wait for the end of data transmission response from the server. If it
* doesnt arrive or another response arrives in its place then something
* went wrong.
*/
if(_FTPX_PIGetDTPResponse() != FTP_RESPONSE_DATAEND)
{
sprintf(szErrMsg, "Failed to send data file '%s'", szFile);
return(SDD_FAIL);
}
/* OK, all done, so close the file and prepare to exit.
*/
fclose(FTPX.fDataFile);
FTPX.fDataFile=NULL;
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: ftpx_InitService
* Description: Entry point which initialises the driver into a defined state.
* It is mandatory that this function is called before any other
* in order for the driver to function correctly. The caller
* provides it with two types of data, 1) A structure containing
* data for it to use in initialising itself, 2) a pointer to a
* buffer which the driver uses to place an error message should
* it not be able to complete initialisation.
*
* Returns: SDD_FAIL- An error occurred in initialising the driver and an
* error message is stored in szErrStr.
* SDD_OK - Driver initialised successfully.
******************************************************************************/
int ftpx_InitService( SERVICEDETAILS *sServiceDet, /* I: Init data */
UCHAR *szErrStr ) /* O: Error message */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *szFunc = "ftpx_InitService";
/* Prepare error string.
*/
sprintf(szErrStr, "%s: ", SDD_EMSG_SRCINIT);
/* Initialise a connection with the FTP server using the data provided
* in the service details record.
*/
if(_FTPX_FTPInit(sServiceDet->uServiceInfo.sFTPInfo.szServer,
sServiceDet->uServiceInfo.sFTPInfo.szUser,
sServiceDet->uServiceInfo.sFTPInfo.szPassword,
&szErrStr[strlen(szErrStr)]) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Log if debugging switched on.
*/
Lgr(LOG_MESSAGE, szFunc, "FTPX Driver: Initialised:");
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: ftpx_CloseService
* Description: Entry point which performs a drive closedown. The closedown
* procedure ensure that the driver returns to a virgin state
* (ie.like at power up) so that InitService can be called again.
*
* Returns: SDD_FAIL- An error occurred in closing the driver and an
* error message is stored in szErrStr.
* SDD_OK - Driver successfully closed.
******************************************************************************/
int ftpx_CloseService( UCHAR *szErrMsg ) /* O: Error message if failed */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *szFunc = "ftpx_CloseService";
/* Prepare error string.
*/
sprintf(szErrMsg, "%s: ", SDD_EMSG_BADEXIT);
/* Close connection with FTP server and tidy up.
*/
if(_FTPX_FTPClose( &szErrMsg[strlen(szErrMsg)] ) == SDD_FAIL)
{
return(SDD_FAIL);
}
/* Log if debugging switched on.
*/
Lgr(LOG_MESSAGE, szFunc, "FTPX Driver: Closed.");
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: ftpx_ProcessRequest
* Description: Entry point into driver to initiate the driver into
* processing a request. A data block is passed as a parameter
* to the driver which represents a request with relevant
* parameters. The data within the structure is only relevant
* to the original client and this driver code.
*
* Returns: SDD_FAIL- An error occurred within the driver whilst trying to
* process the request, see error text.
* SDD_OK - Request processed successfully.
******************************************************************************/
int ftpx_ProcessRequest( UCHAR *snzDataBuf, /* I: Input data */
int nDataLen, /* I: Len of data */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: CB to send reply*/
UCHAR *szErrMsg ) /* O: Error text */
{
/* Static variables.
*/
static int nXmitMode = FTP_BINARY_MODE;
static UCHAR *pszRemoteFile = NULL;
static UCHAR *pszRemotePath = NULL;
static UCHAR szXmitFile[MAX_FTP_FILENAME] = "";
static FILE *fXmitFile = NULL;
/* Local variables.
*/
int nLastBlock;
int nRcvMode;
int nReturn = SDD_OK;
UCHAR *szSrcFile;
UCHAR *szDstFile;
UCHAR *szPath;
UCHAR szRcvFile[MAX_FTP_FILENAME] = "";
UCHAR *szFunc = "ftpx_ProcessRequest";
FILE *fpRcvFile;
/* If the request block doesnt contain any data, something went wrong
* somewhere?
*/
if(nDataLen <= 1)
{
sprintf(szErrMsg,
"%s: Illegal request, has size of %dBytes",
SDD_EMSG_BADREQ, nDataLen);
return(SDD_FAIL);
}
/* First byte of the request data block indicates actions required, so
* decipher it.
*/
switch(snzDataBuf[0])
{
case SDD_FTPX_XMIT:
/* If this is the first time, then create a temporary file and
* process any options.
*/
if(fXmitFile == NULL)
{
/* Create a filename using a constant with the current pid.
*/
sprintf(szXmitFile, "/tmp/XmitFile.%d", getpid());
/* Try to open the file.
*/
if((fXmitFile=fopen(szXmitFile, "w")) == NULL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Failed to create a temporary storage file",
SDD_EMSG_FILEERROR);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Get the path of the file to on the remote.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_SRCPATH,
&szPath) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no Path given in command",
SDD_EMSG_BADPATH);
/* Close file, no longer needed.
*/
fclose(fXmitFile);
fXmitFile = NULL;
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Get the name of the file to be created on the remote.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_SRCFILE,
&szSrcFile) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no Filename given in command",
SDD_EMSG_BADFILE);
/* Close file, no longer needed.
*/
fclose(fXmitFile);
fXmitFile = NULL;
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Allocate memory to store the Path and File until they
* are needed.
*/
if((pszRemotePath=(UCHAR *)malloc(strlen(szPath)+1)) == NULL ||
(pszRemoteFile=(UCHAR *)malloc(strlen(szSrcFile)+1)) == NULL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: No more memory whilst allocating storage",
SDD_EMSG_MEMORY);
/* Close file, no longer needed.
*/
fclose(fXmitFile);
fXmitFile = NULL;
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Copy temporary contents into the permanent memory we've
* just allocated.
*/
strcpy(pszRemotePath, szPath);
strcpy(pszRemoteFile, szSrcFile);
/* Get the mode of transfer, if specified, else default to
* binary.
*/
nXmitMode = _FTPX_GetMode(&snzDataBuf[1], (nDataLen-1));
}
/* Extract the data which has been passed in the block and store
* in the temporary file opened earlier.
*/
if(_FTPX_GetWriteData(&snzDataBuf[1], (nDataLen-1), fXmitFile,
&nLastBlock, szErrMsg) == SDD_FAIL)
{
/* Tidy up as we are not coming back!!!
*/
fclose(fXmitFile);
fXmitFile = NULL;
free(pszRemotePath);
free(pszRemoteFile);
pszRemotePath = NULL;
pszRemoteFile = NULL;
/* Delete temporary file as we dont want thousands of these
* populating the temporary directory.
*/
unlink(szXmitFile);
/* Exit directly as we have nothing left to tidy up.
*/
return(SDD_FAIL);
}
/* If we wrote the last block successfully, then prepare for FTP
* takeoff.
*/
if(nLastBlock == TRUE)
{
/* Firstly, close the opened file and reset the pointer for
* next time.
*/
fclose(fXmitFile);
fXmitFile = NULL;
/* Fire the data into hyper space... we assume the FTP link
* is still open, it will fail otherwise.
*/
nReturn=_FTPX_FTPXmitFile(szXmitFile, pszRemotePath,
pszRemoteFile, nXmitMode, szErrMsg);
/* Free the permanent path and file store, no longer needed.
*/
free(pszRemotePath);
free(pszRemoteFile);
pszRemotePath = NULL;
pszRemoteFile = NULL;
/* Delete temporary file as we dont want thousands of these
* populating the temporary directory.
*/
unlink(szXmitFile);
}
break;
case SDD_FTPX_RCV:
/* Get the path of the file to be received.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_SRCPATH,
&szPath) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no Path given in command",
SDD_EMSG_BADPATH);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Get the name of the file to be received.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_SRCFILE,
&szSrcFile) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no Filename given in command",
SDD_EMSG_BADFILE);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Get the mode of transfer, if specified, else default to
* binary.
*/
nRcvMode = _FTPX_GetMode(&snzDataBuf[1], (nDataLen-1));
/* Create the name of the temporary file for holding FTP'd data.
*/
sprintf(szRcvFile, "/tmp/RcvFile.%d", getpid());
/* Get file from remote site.. lets hope it hasnt closed down,
* maybe the client is the ?A.dasd?.
*/
if(_FTPX_FTPRcvFile(szRcvFile, szPath, szSrcFile, nRcvMode,
szErrMsg) == SDD_FAIL)
{
/* Delete temporary file as we dont want thousands of these
* populating the temporary directory.
*/
unlink(szRcvFile);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Open the file just populated from the FTP receive ready for
* transmission back to the host.
*/
if((fpRcvFile=fopen(szRcvFile, "r")) == NULL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no Filename given in command",
SDD_EMSG_BADFILE);
/* Delete temporary file as we dont want thousands of these
* populating the temporary directory.
*/
unlink(szRcvFile);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Transmit data back to caller......
*/
nReturn=_FTPX_PutReadData(fpRcvFile, fSendDataCB, szErrMsg);
/* Close file and remove it...
*/
fclose(fpRcvFile);
unlink(szRcvFile);
break;
case SDD_FTPX_REN:
/* Get the path where the file to be renamed exists.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_SRCPATH,
&szPath) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg, "%s: Illegal or no Path given in command",
SDD_EMSG_BADPATH);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Get the source file name.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_SRCFILE,
&szSrcFile) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no source file given in command",
SDD_EMSG_BADPATH);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Get the destination file name.
*/
if(_FTPX_GetStrArg(&snzDataBuf[1], (nDataLen-1), FTP_DSTFILE,
&szDstFile) == SDD_FAIL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal or no source file given in command",
SDD_EMSG_BADPATH);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Call the FTP function to perform the rename.
*/
if(_FTPX_FTPRenFile(szPath,szSrcFile,szDstFile,szErrMsg)==SDD_FAIL)
{
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
break;
default:
sprintf(szErrMsg,
"%s: Illegal command in request buffer (%x)",
SDD_EMSG_BADREQ, snzDataBuf[0]);
return(SDD_FAIL);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: ftpx_ProcessOOB
* Description: Entry point into driver to process an out of band command
* that may or may not be relevant to current state of
* operation. The task of this function is to decipher the
* command and act on it immediately, ie. a cancel command
* would abort any ProcessRequest that is in process and
* clean up.
*
* Returns: No returns.
******************************************************************************/
void ftpx_ProcessOOB( UCHAR nCommand ) /* I: OOB Command */
{
/* Local variables.
*/
/* Decipher command and perform actions accordingly.
*/
switch(nCommand)
{
/* Request to abort current ProcessRequest command and return daemon
* to a waiting-for-request state.
*/
case SDD_ABORT:
break;
/* Request to close down and exit.
*/
case SDD_EXIT:
break;
default:
break;
}
/* Return to caller.
*/
return;
}