summaryrefslogtreecommitdiff
path: root/src/htsftp.c
diff options
context:
space:
mode:
authorXavier Roche <xroche@users.noreply.github.com>2012-03-19 12:36:11 +0000
committerXavier Roche <xroche@users.noreply.github.com>2012-03-19 12:36:11 +0000
commitad5b7acc19290ff91e0f42a0de448a26760fcf99 (patch)
tree2d1867758835fd0c4e443ff3cc7e5c774af85874 /src/htsftp.c
Imported httrack 3.20.2
Diffstat (limited to 'src/htsftp.c')
-rw-r--r--src/htsftp.c1135
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;
+}
+
+
+
+