diff options
author | Xavier Roche <xroche@users.noreply.github.com> | 2012-03-19 12:36:11 +0000 |
---|---|---|
committer | Xavier Roche <xroche@users.noreply.github.com> | 2012-03-19 12:36:11 +0000 |
commit | ad5b7acc19290ff91e0f42a0de448a26760fcf99 (patch) | |
tree | 2d1867758835fd0c4e443ff3cc7e5c774af85874 /src/htsftp.c |
Imported httrack 3.20.2
Diffstat (limited to 'src/htsftp.c')
-rw-r--r-- | src/htsftp.c | 1135 |
1 files changed, 1135 insertions, 0 deletions
diff --git a/src/htsftp.c b/src/htsftp.c new file mode 100644 index 0000000..5fbe895 --- /dev/null +++ b/src/htsftp.c @@ -0,0 +1,1135 @@ +/* ------------------------------------------------------------ */ +/* +HTTrack Website Copier, Offline Browser for Windows and Unix +Copyright (C) Xavier Roche and other contributors + +This program 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 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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + +Important notes: + +- We hereby ask people using this source NOT to use it in purpose of grabbing +emails addresses, or collecting any other private information on persons. +This would disgrace our work, and spoil the many hours we spent on it. + + +Please visit our Website: http://www.httrack.com +*/ + + +/* ------------------------------------------------------------ */ +/* File: basic FTP protocol manager */ +/* Author: Xavier Roche */ +/* ------------------------------------------------------------ */ + +// Gestion protocole ftp +// Version .05 (01/2000) + +#include "htsftp.h" + +#include "htsglobal.h" +#include "htsbase.h" +#include "htsnet.h" +#include "htsthread.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if HTS_WIN +#else +//inet_ntoa +#include <arpa/inet.h> +#endif + +#if HTS_WIN +#ifndef __cplusplus +// DOS +#include <process.h> /* _beginthread, _endthread */ +#endif +#endif + +// ftp mode passif +// #if HTS_INET6==0 +#define FTP_PASV 1 +// #else +// no passive mode for v6 +// #define FTP_PASV 0 +// #endif + +#define FTP_DEBUG 0 +//#define FORK_DEBUG 0 + +#define FTP_STATUS_READY 1001 + +#if USE_BEGINTHREAD +/* +#ifdef __cplusplus +// C++ -> Shell +UINT back_launch_ftp( LPVOID pP ) { + lien_back* back=(lien_back*) pP; + if (back == NULL) { + //back->status=FTP_STATUS_READY; // fini + //back->r.statuscode=-1; + return -1; + } + + // lancer ftp + run_launch_ftp(back); + // prêt + back->status=0; + + return 0; // thread completed successfully +} +#else +*/ +PTHREAD_TYPE back_launch_ftp( void* pP ) { + lien_back* back=(lien_back*) pP; + if (back == NULL) { + //back->status=FTP_STATUS_READY; // fini + //back->r.statuscode=-1; +#if FTP_DEBUG + printf("[ftp error: no args]\n"); +#endif + return PTHREAD_RETURN; + } + + /* Initialize */ + hts_init(); + + // lancer ftp +#if FTP_DEBUG + printf("[Launching main ftp routine]\n"); +#endif + run_launch_ftp(back); + // prêt + back->status=0; + + /* Uninitialize */ + hts_uninit(); + return PTHREAD_RETURN; +} +/*#endif*/ +// lancer en back +void launch_ftp(lien_back* back) { +/* +#ifdef __cplusplus + // C++ -> Shell + AfxBeginThread(back_launch_ftp,(LPVOID) back); +#else +*/ + // DOS +#if FTP_DEBUG + printf("[Launching main ftp thread]\n"); +#endif + _beginthread(back_launch_ftp, 0, (void*) back); +/*#endif*/ +} + +#else +// Unix sans pthread +int back_launch_ftp(lien_back* back) { + // lancer ftp + run_launch_ftp(back); + // prêt + back->status=0; + return 0; +} +void launch_ftp(lien_back* back,char* path,char* exec) { + FILE* fp = fopen(fconv(path),"wb"); + if (fp) { + char _args[8][256]; + char *args[8]; + fclose(fp); fp=NULL; + + strcpy(_args[0],exec); + strcpy(_args[1],"-#R"); + strcpy(_args[2],back->url_adr); + strcpy(_args[3],back->url_fil); + strcpy(_args[4],back->url_sav); + strcpy(_args[5],path); + //strcpy(_args[6],""); + args[0]=_args[0]; + args[1]=_args[1]; + args[2]=_args[2]; + args[3]=_args[3]; + args[4]=_args[4]; + args[5]=_args[5]; + args[6]=NULL; + switch (fork()) { // note: vfork déconne un max' + case -1: printf("Can not vfork() process\n"); break; + case 0: + if (execvp(args[0],args)==-1) { + fp=fopen(fconv(path),"wb"); + if (fp) { + fprintf(fp,"-1 unable to launch %s",args[0]); + fclose(fp); fp=NULL; + rename(path,concat(path,".ok")); + } else remove(path); + } + _exit(0); // exit 'propre' + break; + default: // parent + // bah on fait rien.. + break; + } + } +} +#endif + +// pour l'arrêt du ftp +#ifdef _WIN32 +#define _T_SOC_close(soc) closesocket(soc); soc=INVALID_SOCKET; +#else +#define _T_SOC_close(soc) close(soc); soc=INVALID_SOCKET; +#endif +#define _HALT_FTP { \ + if ( soc_ctl != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \ + if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \ + if ( soc_dat != INVALID_SOCKET ) _T_SOC_close(soc_dat); \ +} +#define _CHECK_HALT_FTP \ + if (stop_ftp(back)) { \ + _HALT_FTP \ + return 0; \ + } + +// la véritable fonction une fois lancées les routines thread/fork +int run_launch_ftp(lien_back* back) { + char user[256]="anonymous"; + char pass[256]="user@"; + char line_retr[2048]; + int port=21; +#if FTP_PASV + int port_pasv=0; +#endif + char adr_ip[1024]; + char *adr,*real_adr; + char* ftp_filename=""; + int timeout = 300; // timeout + int timeout_onfly=8; // attente réponse supplémentaire + int transfer_list=0; // directory + int rest_understood=0; // rest command understood + t_fullhostent fullhostent_buffer; // buffer pour resolver + // + T_SOC soc_ctl=INVALID_SOCKET; + T_SOC soc_servdat=INVALID_SOCKET; + T_SOC soc_dat=INVALID_SOCKET; + // + SOCaddr server_data; + int server_data_size=sizeof(server_data); + // + line_retr[0]=adr_ip[0]='\0'; + + timeout=300; + + // effacer + strcpy(back->r.msg,""); + back->r.statuscode=0; + back->r.size=0; + + // récupérer user et pass si présents, et sauter user:id@ dans adr + real_adr = strchr(back->url_adr,':'); + if (real_adr) real_adr++; + else real_adr=back->url_adr; + while(*real_adr=='/') real_adr++; // sauter / + if ( (adr = jump_identification(real_adr)) != real_adr) { // user + int i=-1; + pass[0]='\0'; + do { + i++; + user[i]=real_adr[i]; + } while( (real_adr[i]!=':') && (real_adr[i]) ); + user[i]='\0'; + if (real_adr[i]==':') { // pass + int j=-1; + i++; // oui on saute aussi le : + do { + j++; + pass[j]=real_adr[i+j]; + } while( ((&real_adr[i+j+1]) < adr) && (real_adr[i+j]) ); + pass[j]='\0'; + } + } + + // Calculer RETR <nom> + { + char* a; + a=back->url_fil + strlen(back->url_fil)-1; + while( (a > back->url_fil) && (*a!='/')) a--; + if (*a == '/') { // ok repéré + a++; // sauter / + ftp_filename=a; + if (strnotempty(a)) { + char* ua=unescape_http(a); + if ( + (strchr(ua, ' ')) + || + (strchr(ua, '\"')) + || + (strchr(ua, '\'')) + ) { + sprintf(line_retr,"RETR \"%s\"",ua); + } else { /* Regular one */ + sprintf(line_retr,"RETR %s",ua); + } + } else { + transfer_list=1; + sprintf(line_retr,"LIST -A"); + } + } else { + strcpy(back->r.msg,"Unexpected PORT error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } + +#if FTP_DEBUG + printf("Connecting to %s...\n",adr); +#endif + + // connexion + { + SOCaddr server; + int server_size=sizeof(server); + t_hostent* hp; + char * a; + char _adr[256]; + _adr[0]='\0'; + //T_SOC soc_ctl; + // effacer structure + memset(&server, 0, sizeof(server)); + + // port + a=strchr(adr,':'); // port + if (a) { + sscanf(a+1,"%d",&port); + strncat(_adr,adr,(int) (a - adr)); + } else + strcpy(_adr,adr); + + // récupérer adresse résolue + strcpy(back->info,"host name"); + hp = hts_gethostbyname(_adr, &fullhostent_buffer); + if (hp == NULL) { + strcpy(back->r.msg,"Unable to get server's address"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-5; + _HALT_FTP + return 0; + } + _CHECK_HALT_FTP; + + // copie adresse + SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length); + // copie adresse pour cnx data + SOCaddr_copyaddr(server_data, server_data_size, hp->h_addr_list[0], hp->h_length); + // memcpy(&server.sin_addr, hp->h_addr, hp->h_length); + + // créer ("attachement") une socket (point d'accès) internet,en flot + soc_ctl=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0); + if (soc_ctl==INVALID_SOCKET) { + strcpy(back->r.msg,"Unable to create a socket"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + _HALT_FTP + return 0; + } + + SOCaddr_initport(server, port); + // server.sin_port = htons((unsigned short int) port); + + // connexion (bloquante, on est en thread) + strcpy(back->info,"connect"); + +#if HTS_WIN + if (connect(soc_ctl, (const struct sockaddr FAR *)&server, server_size) != 0) { +#else + if (connect(soc_ctl, (struct sockaddr *)&server, server_size) == -1) { +#endif + strcpy(back->r.msg,"Unable to connect to the server"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + _HALT_FTP + return 0; +#if HTS_WIN + } +#else + } +#endif + _CHECK_HALT_FTP; + + { + char line[1024]; + // envoi du login + + // --USER-- + get_ftp_line(soc_ctl,line,timeout); // en tête + _CHECK_HALT_FTP; + + if (line[0]=='2') { // ok, connecté + strcpy(back->info,"login: user"); + sprintf(line,"USER %s",user); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if ((line[0]=='3') || (line[0]=='2')) { + // --PASS-- + strcpy(back->info,"login: pass"); + sprintf(line,"PASS %s",pass); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='2') { // ok + // --CWD-- + char* a; + a=back->url_fil + strlen(back->url_fil)-1; + while( (a > back->url_fil) && (*a!='/')) a--; + if (*a == '/') { // ok repéré + char target[1024]; + target[0]='\0'; + strncat(target,back->url_fil,(int) (a - back->url_fil)); + if (strnotempty(target)==0) + strcat(target,"/"); + strcpy(back->info,"cwd"); + sprintf(line,"CWD %s",target); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='2') { + send_line(soc_ctl,"TYPE I"); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='2') { + // ok.. + } else { + strcpy(back->r.msg,"TYPE I error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + sprintf(back->r.msg,"CWD error: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } else { + strcpy(back->r.msg,"Unexpected ftp error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + + } else { + sprintf(back->r.msg,"Bad password: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + sprintf(back->r.msg,"Bad user name: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + sprintf(back->r.msg,"Connection refused: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + + // ok, si on est prêts on écoute sur un port et on demande la sauce + if (back->r.statuscode != -1) { + + + // + // Pré-REST + // +#if FTP_PASV + if (SOCaddr_getproto(server, server_size) == '1') { + strcpy(back->info,"pasv"); + sprintf(line,"PASV"); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + } else { /* ipv6 */ + line[0]='\0'; + } + _CHECK_HALT_FTP; + if (line[0]=='2') { + char *a,*b,*c; + a=strchr(line,'('); // exemple: 227 Entering Passive Mode (123,45,67,89,177,27) + if (a) { + + // -- analyse de l'adresse IP et du port -- + a++; + b=strchr(a,','); + if (b) b=strchr(b+1,','); + if (b) b=strchr(b+1,','); + if (b) b=strchr(b+1,','); + c=a; while( (c=strchr(c,',')) ) *c='.'; // remplacer , par . + if (b) *b='\0'; + // + strcpy(adr_ip,a); // copier adresse ip + // + if (b) { + a=b+1; // début du port + b=strchr(a,'.'); + if (b) { + int n1,n2; + // + *b='\0'; + b++; + c=strchr(b,')'); + if (c) { + *c='\0'; + if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) { + port_pasv=n2+(n1<<8); + } + } else { + deletesoc(soc_dat); soc_dat=INVALID_SOCKET; + } // sinon on est prêts + } + } + // -- fin analyse de l'adresse IP et du port -- + } else { + sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } else { + /* + * try epsv (ipv6) * + */ + strcpy(back->info,"pasv"); + sprintf(line,"EPSV"); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='2') { /* got it */ + char *a; + a=strchr(line,'('); // exemple: 229 Entering Extended Passive Mode (|||6446|) + if ( + (a != NULL) + && + (*a == '(') + && (*(a+1)) + && (*(a+1) == *(a+2)) && (*(a+1) == *(a+3)) + && (isdigit(*(a+4))) + && (*(a+5)) + ) { + unsigned int n1 = 0; + if (sscanf(a+4,"%d",&n1)==1) { + if ((n1 < 65535) && (n1 > 0)) { + port_pasv=n1; + } + } + } else { + sprintf(back->r.msg,"EPSV incorrect: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + sprintf(back->r.msg,"PASV/EPSV error: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } +#else + // rien à faire avant +#endif + +#if FTP_PASV + if (port_pasv) { +#endif + // SIZE + if (back->r.statuscode != -1) { + if (!transfer_list) { + char* ua=unescape_http(ftp_filename); + if ( + (strchr(ua, ' ')) + || + (strchr(ua, '\"')) + || + (strchr(ua, '\'')) + ) { + sprintf(line,"SIZE \"%s\"", ua); + } else { + sprintf(line,"SIZE %s", ua); + } + + // SIZE? + strcpy(back->info,"size"); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='2') { // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee) + // REST? + if (fexist(back->url_sav) && (transfer_list==0)) { + strcpy(back->info,"rest"); + sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav)); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if ((line[0]=='3') || (line[0]=='2')) { // ok + rest_understood=1; + } // sinon tant pis + } + } // sinon tant pis + } + } +#if FTP_PASV + } +#endif + + // + // Post-REST + // +#if FTP_PASV + // Ok, se connecter + if (port_pasv) { + SOCaddr server; + int server_size=sizeof(server); + t_hostent* hp; + // effacer structure + memset(&server, 0, sizeof(server)); + + // infos + strcpy(back->info,"resolv"); + + // résoudre + if (adr_ip[0]) { + hp = hts_gethostbyname(adr_ip, &fullhostent_buffer); + if (hp) { + SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length); + } else { + server_size=0; + } + } else { + memcpy(&server, &server_data, sizeof(server_data)); + server_size=server_data_size; + } + + // infos + strcpy(back->info,"cnxdata"); +#if FTP_DEBUG + printf("Data: Connecting to %s:%d...\n", adr_ip, port_pasv); +#endif + if (server_size > 0) { + // socket + soc_dat=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0); + if (soc_dat != INVALID_SOCKET) { + // structure: connexion au domaine internet, port 80 (ou autre) + SOCaddr_initport(server, port_pasv); + // server.sin_port = htons((unsigned short int) port_pasv); +#if HTS_WIN + if (connect(soc_dat, (const struct sockaddr FAR *)&server, server_size) == 0) { +#else + if (connect(soc_dat, (struct sockaddr *)&server, server_size) != -1) { +#endif + strcpy(back->info,"retr"); + strcpy(line,line_retr); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='1') { + // OK + } else { + deletesoc(soc_dat); soc_dat=INVALID_SOCKET; + // + sprintf(back->r.msg,"RETR command errror: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } else { +#if FTP_DEBUG + printf("Data: unable to connect\n"); +#endif + deletesoc(soc_dat); soc_dat=INVALID_SOCKET; + // + strcpy(back->r.msg,"Unable to connect"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } else { + strcpy(back->r.msg,"Unable to create a socket"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } else { + sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts + } else { + sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } // sinon on est prêts +#else + //T_SOC soc_servdat; + strcpy(back->info,"listening"); + if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) { + _CHECK_HALT_FTP; + send_line(soc_ctl,line); // envoi du RETR + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='2') { // ok + strcpy(back->info,"retr"); + strcpy(line,line_retr); + send_line(soc_ctl,line); + get_ftp_line(soc_ctl,line,timeout); + _CHECK_HALT_FTP; + if (line[0]=='1') { + //T_SOC soc_dat; + struct sockaddr dummyaddr; + int dummylen = sizeof(struct sockaddr); + if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) { + strcpy(back->r.msg,"Unable to accept connection"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + sprintf(back->r.msg,"RETR command errror: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + sprintf(back->r.msg,"PORT command error: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } +#if HTS_WIN + closesocket(soc_servdat); +#else + close(soc_servdat); +#endif + } else { + strcpy(back->r.msg,"Unable to listen to a port"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } +#endif + + // + // Ok, connexion initiée + // + if (soc_dat != INVALID_SOCKET) { + if (rest_understood) { // REST envoyée et comprise + filenote(back->url_sav,NULL); + back->r.fp = fopen(fconv(back->url_sav),"ab"); + } else + back->r.fp = filecreate(back->url_sav); + strcpy(back->info,"receiving"); + if (back->r.fp != NULL) { + char buff[1024]; + int len=1; + int read_len=1024; + //HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues + + while( (len>0) && (!stop_ftp(back)) ) { + // attendre les données + len=1; // pas d'erreur pour le moment + switch(wait_socket_receive(soc_dat,timeout)) { + case -1: + strcpy(back->r.msg,"Read error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + len=0; // fin + break; + case 0: + sprintf(back->r.msg,"Time out (%d)",timeout); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + len=0; // fin + break; + } + + // réception + if (len) { + len=recv(soc_dat,buff,read_len,0); + if (len>0) { + back->r.size+=len; + HTS_STAT.HTS_TOTAL_RECV+=len; + if (back->r.fp) { + if ((int) fwrite(buff,1,len,back->r.fp) != len) { + strcpy(back->r.msg,"Write error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + len=0; // error + } + } else { + strcpy(back->r.msg,"Unexpected write error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { // Erreur ou terminé + //strcpy(back->r.msg,"Read error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=0; + } + read_len=1024; + //HTS_TOTAL_RECV_CHECK(read_len); // Diminuer au besoin si trop de données reçues + } + } + if (back->r.fp) { + fclose(back->r.fp); + back->r.fp=NULL; + } + } else { + strcpy(back->r.msg,"Unable to write file"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } +#if HTS_WIN + closesocket(soc_dat); +#else + close(soc_dat); +#endif + + // 226 Transfer complete? + if (back->r.statuscode != -1) { + if (wait_socket_receive(soc_ctl,timeout_onfly)>0) { + // récupérer 226 transfer complete + get_ftp_line(soc_ctl,line,timeout); + if (line[0]=='2') { // OK + strcpy(back->r.msg,"OK"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=200; + } else { + sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line)); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } else { + strcpy(back->r.msg,"Read error"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + } + } + + } + + + + } + + + } + + _CHECK_HALT_FTP; + strcpy(back->info,"quit"); + send_line(soc_ctl,"QUIT"); // bye bye + get_ftp_line(soc_ctl,NULL,timeout); +#if HTS_WIN + closesocket(soc_ctl); +#else + close(soc_ctl); +#endif + } + + if (back->r.statuscode!=-1) { + back->r.statuscode=200; + strcpy(back->r.msg,"OK"); + } + back->status=FTP_STATUS_READY; // fini + return 0; +} + + + +// ouverture d'un port +T_SOC get_datasocket(char* to_send) { + T_SOC soc = INVALID_SOCKET; + char h_loc[256+2]; + + to_send[0]='\0'; + if (gethostname(h_loc,256)==0) { // host name + SOCaddr server; + int server_size=sizeof(server); + t_hostent* hp_loc; + t_fullhostent buffer; + + // effacer structure + memset(&server, 0, sizeof(server)); + + if ( (hp_loc=vxgethostbyname(h_loc, &buffer)) ) { // notre host + + // copie adresse + SOCaddr_copyaddr(server, server_size, hp_loc->h_addr_list[0], hp_loc->h_length); + + if ( (soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0)) != INVALID_SOCKET) { + + if ( bind(soc,(struct sockaddr*) &server, server_size) == 0 ) { + SOCaddr server2; + int len; + len=sizeof(server2); + // effacer structure + memset(&server2, 0, sizeof(server2)); + if (getsockname(soc,(struct sockaddr*) &server2, &len) == 0) { + // *port=ntohs(server.sin_port); // récupérer port + if (listen(soc,10)>=0) { // au pif le 10 +#if HTS_INET6==0 + unsigned short int a,n1,n2; + // calculer port + a = SOCaddr_sinport(server2); + n1 = (a & 0xff); + n2 = ((a>>8) & 0xff); + { + char dots[256+2]; + char dot[256+2]; + char* a; + SOCaddr_inetntoa(dot, 256, server2, sizeof(server2)); + // + dots[0]='\0'; + strncat(dots, dot, 128); + while( (a=strchr(dots,'.')) ) *a=','; // virgules! + while( (a=strchr(dots,':')) ) *a=','; // virgules! + sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2); + } +#else + /* + EPRT |1|132.235.1.2|6275| + EPRT |2|1080::8:800:200C:417A|5282| + */ + { + char dot[256+2]; + SOCaddr_inetntoa(dot, 256, server2, len); + sprintf(to_send,"EPRT |%c|%s|%d|", SOCaddr_getproto(server2, len), dot, SOCaddr_sinport(server2)); + } +#endif + + } else { +#if HTS_WIN + closesocket(soc); +#else + close(soc); +#endif + soc=INVALID_SOCKET; + } + + + } else { +#if HTS_WIN + closesocket(soc); +#else + close(soc); +#endif + soc=INVALID_SOCKET; + } + + + } else { +#if HTS_WIN + closesocket(soc); +#else + close(soc); +#endif + soc=INVALID_SOCKET; + } + } + } + } + + + return soc; +} + +#if FTP_DEBUG +FILE* dd=NULL; +#endif + +// routines de réception/émission +// 0 = ERROR +int send_line(T_SOC soc,char* data) { + char line[1024]; + if (_DEBUG_HEAD) { + if (ioinfo) { + fprintf(ioinfo,"---> %s\x0d\x0a",data); + fflush(ioinfo); + } + } +#if FTP_DEBUG + if (dd == NULL) dd = fopen("toto.txt","w"); + fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd); + printf("---> %s",data); fflush(stdout); +#endif + sprintf(line,"%s\x0d\x0a",data); + if (check_socket_connect(soc) != 1) { +#if FTP_DEBUG + printf("!SOC WRITE ERROR\n"); +#endif + return 0; // erreur, plus connecté! + } +#if FTP_DEBUG + { + int r = (send(soc,line,strlen(line),0) == (int) strlen(line)); + printf("%s\x0d\x0a",data); fflush(stdout); + return r; + } +#else + return (send(soc,line,strlen(line),0) == (int) strlen(line)); +#endif +} + +int get_ftp_line(T_SOC soc,char* line,int timeout) { + char data[1024]; + int i,ok,multiline; +#if FTP_DEBUG + if (dd == NULL) dd = fopen("toto.txt","w"); +#endif + + data[0]='\0'; + i=ok=multiline=0; data[3]='\0'; + do { + char b; + + // vérifier données + switch(wait_socket_receive(soc,timeout)) { + case -1: // erreur de lecture + if (line) strcpy(line,"500 *read error"); + return 0; + break; + case 0: + if (line) sprintf(line,"500 *read timeout (%d)",timeout); + return 0; + break; + } + + //HTS_TOTAL_RECV_CHECK(dummy); // Diminuer au besoin si trop de données reçues + switch(recv(soc,&b,1,0)) { + //case 0: break; // pas encore --> erreur (on attend)! + case 1: + HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant + if ((b!=10) && (b!=13)) + data[i++]=b; + break; + default: + if (line) strcpy(line,"500 *read error"); + return 0; // error + break; + } + if ( ((b==13) || (b==10)) && (i>0) ){ // CR/LF + if ( + (data[3] == '-') + || + ((multiline) && (!isdigit((unsigned char)data[0]))) + ) + { + data[3]='\0'; + i=0; + multiline=1; + } + else + ok=1; // sortir + } + } while(!ok); + data[i++]='\0'; + + if (_DEBUG_HEAD) { + if (ioinfo) { + fprintf(ioinfo,"<--- %s\x0d\x0a",data); + fflush(ioinfo); + } + } +#if FTP_DEBUG + fprintf(dd,"<--- %s\n",data); fflush(dd); + printf("<--- %s\n",data); +#endif + if (line) strcpy(line,data); + return (strnotempty(data)); +} + +// sauter NNN +char* linejmp(char* line) { + if (strlen(line)>4) + return line+4; + else + return line; +} + +// test socket: +// 0 : no data +// 1 : data detected +// -1: error +int check_socket(T_SOC soc) { + fd_set fds,fds_e; // poll structures + struct timeval tv; // structure for select + FD_ZERO(&fds); + FD_ZERO(&fds_e); + // socket read + FD_SET(soc,&fds); + // socket error + FD_SET(soc,&fds_e); + tv.tv_sec=0; + tv.tv_usec=0; + // poll! + select(soc + 1,&fds,NULL,&fds_e,&tv); + if (FD_ISSET(soc,&fds_e)) { // error detected + return -1; + } else if (FD_ISSET(soc,&fds)) { + return 1; + } + return 0; +} +// check if connected +int check_socket_connect(T_SOC soc) { + fd_set fds,fds_e; // poll structures + struct timeval tv; // structure for select + FD_ZERO(&fds); + FD_ZERO(&fds_e); + // socket write + FD_SET(soc,&fds); + // socket error + FD_SET(soc,&fds_e); + tv.tv_sec=0; + tv.tv_usec=0; + // poll! + select(soc + 1,NULL,&fds,&fds_e,&tv); + if (FD_ISSET(soc,&fds_e)) { // error detected + return -1; + } else if (FD_ISSET(soc,&fds)) { + return 1; + } + return 0; +} +// attendre des données +int wait_socket_receive(T_SOC soc,int timeout) { + // attendre les données + TStamp ltime=time_local(); + int r; +#if FTP_DEBUG + printf("\x0dWaiting for data "); fflush(stdout); +#endif + while( (!(r = check_socket(soc))) && ( ((int) ((TStamp) (time_local()-ltime))) < timeout )) { + Sleep(100); +#if FTP_DEBUG + printf("."); fflush(stdout); +#endif + } +#if FTP_DEBUG + printf("\x0dreturn: %d\x0d",r); fflush(stdout); +#endif + return r; +} + + +// cancel reçu? +int stop_ftp(lien_back* back) { + if (back->stop_ftp) { + strcpy(back->r.msg,"Cancelled by User"); + back->status=FTP_STATUS_READY; // fini + back->r.statuscode=-1; + return 1; + } + return 0; +} + + + + |