/* john pfeiffer june 2007 my own ftp client in c */
#include <winsock.h> /*important to load object files C:\devcpp\Lib\libwsock32.a*/
#include <stdio.h>
#include <stdlib.h> /* for atoi() - char to int function */
#define BUFFERMAX 1024
#define CMDPORT 21
#define DATAPORT 20
#define SITENAME "localhost"
/*#define IPADDRESS "127.0.0.1" */
#define IPADDRESS "209.85.5.187" /* beyondcalifornia.com */
void exit_all( SOCKET s )
{ shutdown(s,1); /*better than close() */
closesocket(s);
WSACleanup();
}/*end func exit_all() Cleans up the WSA & closes the socket */
int get_digits( int* buffer_index, char buffer[BUFFERMAX], char digits[16], int* digits_index )
{ int exit_loop = 0;
do
{ if( buffer[ *buffer_index ] == ',' || buffer[ *buffer_index ] == ')')
{ exit_loop = 1; }
digits[ *digits_index ] = buffer[ *buffer_index ];
*digits_index = *digits_index + 1;
*buffer_index = *buffer_index + 1;
}while( exit_loop != 1 ) ;
digits[ *digits_index - 1 ] = '.'; /*digits now contains up to 3 digits and '.'*/
}/*end func get_digits() Copies chars from buffer to digits until ',' or ')' */
void pasv_parse( int d, char buffer[BUFFERMAX], char PASVaddress[16], int* PASVport)
{ int exit_loop = 0;
int buffer_index=0;
int address_index=0;
char cPort[8];
int nPort[2];
int i;
do /*find first parenthesis */
{ if( (buffer[buffer_index] == '(') || (buffer_index == strlen(buffer)) )
{ exit_loop=1; } /*there should be 5 groups of */
buffer_index = buffer_index + 1; /*up to 3 digits, ',' delimited */
}while( exit_loop != 1 ); /*Starting and finishing with '( )' */
if( buffer_index < strlen(buffer)) /* to make sure everything's OK */
{
for( i=0; i<4; i++) /* get the 4 digits IP address*/
{ get_digits( &buffer_index, buffer, PASVaddress, &address_index ); }
PASVaddress[ address_index-1 ] = '\0';
address_index = 0;
get_digits( &buffer_index, buffer, cPort, &address_index );
cPort[ address_index-1 ] = '\0';
nPort[0] = atoi(cPort); /*get the first paramater about the port */
address_index = 0;
get_digits( &buffer_index, buffer, cPort, &address_index );
cPort[ address_index-1 ] = '\0';
nPort[1] = atoi(cPort); /*get the second paramater about the port*/
*PASVport = (256*(nPort[0])) + (nPort[1]); /* 8 highbits + 8 bits */
}
}/*end func pasv_parse() Formats the server response to PASV command */
/* SPECIAL CASE FROM RFC 959
123-First line //one received buffer
Second line //next received buffer
234 A line beginning with numbers //next received buffer
123 The last line //finally end of message */
int process_buffer( int nReceived, char buffer[BUFFERMAX], char server_response_code[4],
int msg_finished )
{ char display[512];
int display_counter=0;
int i=0;
int end_line = 0;
/* printf("%d bytes received from SERVER\n",nReceived); /*DBEUGGING ONLY*/
do
{ do
{ if( buffer[i]==13 && buffer[i+1]==10 )
{ end_line = 1; }
else
{ display[display_counter] = buffer[i];
i = i + 1;
}
display_counter = display_counter + 1;
}while( end_line == 0 );
display[display_counter-1] = '\0';
puts(display);
if( msg_finished == 0 ) /*if multi line message */
{ if( (server_response_code[0] == display[0]) && /* our original resp code */
(server_response_code[1] == display[1]) &&
(server_response_code[2] == display[2]) &&
(display[3] == ' ') ) /*blank means end multi-line msg */
{ msg_finished = -1; } /*end the recv loop in main */
}
display_counter = 0; /* reset our variables */
end_line = 0; /* reset so we can get another whole line */
i=i+2; /* skip the '/r' and '/n' */
}while( i < nReceived );
return( msg_finished );
}/* end func process_buffer() puts on screen buffer's contents */
int begin_server_reply( int nReceived, char buffer[BUFFERMAX], char server_response_code[4])
{ int msg_finished = -1; /* if -1 then full msg received */
server_response_code[0] = buffer[0];
server_response_code[1] = buffer[1];
server_response_code[2] = buffer[2];
server_response_code[3] = buffer[3]; /* if is a '-', then multi line msg */
if( server_response_code[3] == '-' )
{ msg_finished = 0;
printf("multi line message\n");
}
msg_finished = process_buffer( nReceived, buffer, server_response_code, msg_finished );
return( msg_finished );
}/*end func server_reply(); Formats and displays the server's reply on screen*/
int cmd( char* usercommand, char buffer[BUFFERMAX] )
{ strcpy(buffer,usercommand);
puts(buffer);
strcat(buffer,"\r\n\r\n");
if( strlen(buffer) < 512)
{ return( 512 ); }
else
{ return( strlen(buffer) ); }
}/*end func cmd() Formats string const, puts it in the buffer & on the screen */
/*must pass by reference for Structs!!!!*/
void setup_socket_connect_data( SOCKADDR_IN* ptraData, char ip[16], int port )
{ (*ptraData).sin_family = AF_INET; /*internet protocol addressing */
(*ptraData).sin_port = htons(port); /*connect to port - change to big endian */
(*ptraData).sin_addr.s_addr = inet_addr(ip); /*needs a null terminated string*/
memset(&((*ptraData).sin_zero), '\0', 8); /* zero the rest of the struct*/
printf("Connecting to %s at port %d...\n",ip,port);
}/*end func setup_socket_connect_data() */
/*////MAIN////////////////////////////////////////////////////////////////////*/
int main(void)
{ char buffer[BUFFERMAX];
char server_response_code[4]; /*250- */
char ipaddress[16]; /*255.255.255.255'\0' */
int port=0;
WSADATA ws; /*defined in winsock - before socket usage!*/
int nReceived = WSAStartup(0x0202,&ws); /*starts winsock 2 (windows only)*/
printf("WSASTARTUP = %d ",nReceived); /*shows the result (error?)*/
SOCKADDR_IN SockAddrInData; /*easy struct for socket addressing internals*/
SOCKET sCMD = socket(AF_INET,SOCK_STREAM,0); /*get the handle to socket (should be > 0) */
SOCKET sDATA = socket(AF_INET,SOCK_STREAM,0);
SOCKET sPASV = socket(AF_INET,SOCK_STREAM,0); /*to connect to a server with PASV*/
/*Make Connection/////////////////////////////////////////////////////////////*/
strcpy(ipaddress,IPADDRESS); /*must pass by ref for structs*/
setup_socket_connect_data( &SockAddrInData, ipaddress, CMDPORT );
/*must cast */
nReceived = connect( sCMD, (SOCKADDR*) &SockAddrInData, sizeof(SockAddrInData) );
printf(" SOCKET = %d, Connected? %d (should be: 0)\n",sCMD,nReceived);
if( nReceived < 0 ){ printf("\nERROR GETTING SOCKET\n"); exit(1); }
memset(&buffer, '\0', BUFFERMAX); /* clear the buffer */
nReceived = recv(sCMD,buffer,sizeof(buffer),0);
/* if multi line response from server this will get it all */
if( begin_server_reply(nReceived,buffer,server_response_code) == 0 )
{ do
{ nReceived = recv(sCMD,buffer,sizeof(buffer),0);
nReceived = process_buffer(nReceived,buffer,server_response_code,0);
}while( nReceived != -1 ); /* process_buffer returns -1 when done */
}
/*Logging In//////////////////////////////////////////////////////////////////*/
send(sCMD,buffer, cmd("USER myusername",buffer) ,0);
nReceived = recv(sCMD,buffer,sizeof(buffer),0);
if( begin_server_reply(nReceived,buffer,server_response_code) == 0 )
{ do
{ nReceived = recv(sCMD,buffer,sizeof(buffer),0);
nReceived = process_buffer(nReceived,buffer,server_response_code,0);
}while( nReceived != -1 ); /* process_buffer returns -1 when done */
}
memset(&buffer, '\0', BUFFERMAX); /* clear the buffer */
send(sCMD,"PASS mypassword\r\n\r\n",512,0);
nReceived = recv(sCMD,buffer,sizeof(buffer),0);
// printf("\nhello\n");
// puts(buffer);
if( begin_server_reply(nReceived,buffer,server_response_code) == 0 )
{ do
{ nReceived = recv(sCMD,buffer,sizeof(buffer),0);
nReceived = process_buffer(nReceived,buffer,server_response_code,0);
}while( nReceived != -1 ); /* process_buffer returns -1 when done */
}
/*Passive Setup///////////////////////////////////////////////////////////////*/
/* send(sCMD,buffer, cmd("PASV",buffer) ,0);
nReceived = recv(sCMD,buffer,sizeof(buffer),0);
begin_server_reply(nReceived,buffer,server_response_code);
pasv_parse(nReceived, buffer, ipaddress, &port);
setup_socket_connect_data( &SockAddrInData, ipaddress, port );
nReceived = connect( sPASV, (SOCKADDR*) &SockAddrInData, sizeof(SockAddrInData) );
printf(" SOCKET = %d, Connected? %d (should be: 0)\n",sPASV,nReceived);
if( nReceived < 0 ){ printf("\nERROR GETTING SOCKET\n"); exit(1); }
/*Changing Directory//////////////////////////////////////////////////////////*/
// send(sCMD,buffer, cmd("PWD",buffer) ,0); /*PWD too*/
// send(sCMD,buffer, cmd("CWD html/temp",buffer) ,0); /*PWD too*/
// nReceived = recv(sCMD,buffer,sizeof(buffer),0);
// begin_server_reply(nReceived,buffer,server_response_code);
/*Listing File Names//////////////////////////////////////////////////////////*/
/* send(sCMD,buffer, cmd("LIST",buffer) ,0);
nReceived = recv(sCMD,buffer,sizeof(buffer),0);
begin_server_reply(nReceived,buffer,server_response_code);
nReceived = recv(sPASV,buffer,sizeof(buffer),0);
printf("%d bytes received from SERVER\n",nReceived);
begin_server_reply(nReceived,buffer,server_response_code);
/*////QUIT////////////////////////////////////////////////////////////////////*/
send(sCMD,buffer, cmd("QUIT",buffer) ,0);
nReceived = recv(sCMD,buffer,sizeof(buffer),0);
begin_server_reply(nReceived,buffer,server_response_code);
exit_all(sPASV);
exit_all(sCMD); /*clean up socket, ws, etc. */
return 0; /*rumor is, ALWAYS RETURN */
}/*end main */
/*////END OF PROGRAM//////////////////////////////////////////////////////////*/
/*socket,receive buffer,cmd,0 - i don't know why 0*/
// printf("%d\n",strlen("USER foupfeiffer_fun\r\n\r\n"));
// send(s,"USER foupfeiffer_fun\r\n\r\n",24,0);
// send(s,buffer, cmd(strcpy(buffer,"USER foupfeiffer_fun"), buffer),0);
// strcpy(buffer,"USER foupfeiffer_fun\r\n\r\n");
/*
do{
gets(buffer);
if( buffer[0] != 'q' )
{ send(s,buffer,cmd(buffer, buffer),0);
nReceived = recv(s,buffer,sizeof(buffer),0);
server_reply(s,nReceived,buffer);
}else{ printf("Thank you, now closing socket and quitting."); }
}while( buffer[0]!='q' );
/*
Default Data? port 20?
setup_socket_connect_data( &SockAddrInData, ipaddress, DATAPORT );
nReceived = connect( sDATA, (SOCKADDR*) &SockAddrInData, sizeof(SockAddrInData) );
printf(" SOCKET = %d, Connected? %d (should be: 0)\n",sDATA,nReceived);
if( nReceived < 0 ){ printf("\nERROR GETTING SOCKET\n"); exit(1); }
ACTIVE PORT COMMAND
send(s,buffer, cmd(strcpy(buffer,"PORT 127,0,0,1,0,88"), buffer),0);
COMMANDS TO IMITATE
rename RNFR/RNTO
mkdir MKD
rmdir RMD
delete DELE
send STOR
recv RETR
ascii
binary
help site
help
status STAT used only during transfer
*/