home *** CD-ROM | disk | FTP | other *** search
/ Revista do CD-ROM 71 / CDROM71.ISO / internet / navoff / data1.cab / Sources / src / htsftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-01  |  29.1 KB  |  1,037 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche, Yann Philippot and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. This project has been developed by Xavier Roche and Yann Philippot,
  29. from the company Serianet at Caen, France (http://www.serianet.com)
  30. and other contributors (see the greetings file)
  31.  
  32. Please visit our Website: http://www.httrack.com
  33. */
  34.  
  35.  
  36. /* ------------------------------------------------------------ */
  37. /* File: basic FTP protocol manager                             */
  38. /* Author: Xavier Roche                                         */
  39. /* ------------------------------------------------------------ */
  40.  
  41. // Gestion protocole ftp
  42. // Version .05 (01/2000)
  43.  
  44. #include "htsftp.h"
  45.  
  46. #include "htsglobal.h"
  47. #include "htsbase.h"
  48. #include "htsnet.h"
  49. #include "htsthread.h"
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #if HTS_WIN
  54. #else
  55. //inet_ntoa
  56. #include <arpa/inet.h>
  57. #endif
  58.  
  59. #if HTS_WIN
  60. #ifndef __cplusplus
  61. // DOS
  62. #include <process.h>    /* _beginthread, _endthread */
  63. #endif
  64. #endif
  65.  
  66. // ftp mode passif
  67. #define FTP_PASV 1
  68.  
  69. #define FTP_DEBUG 0
  70. //#define FORK_DEBUG 0
  71.  
  72. #define FTP_STATUS_READY 1001
  73.  
  74. #if USE_BEGINTHREAD
  75. /*
  76. #ifdef __cplusplus
  77. // C++ -> Shell
  78. UINT back_launch_ftp( LPVOID pP ) {
  79.   lien_back* back=(lien_back*) pP;
  80.   if (back == NULL) {
  81.     //back->status=FTP_STATUS_READY;    // fini
  82.     //back->r.statuscode=-1;
  83.     return -1;
  84.   }
  85.   
  86.   // lancer ftp
  87.   run_launch_ftp(back);
  88.   // prΩt
  89.   back->status=0;
  90.  
  91.   return 0;    // thread completed successfully
  92. }
  93. #else
  94. */
  95. PTHREAD_TYPE back_launch_ftp( void* pP ) {
  96.   lien_back* back=(lien_back*) pP;
  97.   if (back == NULL) {
  98.     //back->status=FTP_STATUS_READY;    // fini
  99.     //back->r.statuscode=-1;
  100. #if FTP_DEBUG
  101.     printf("[ftp error: no args]\n");
  102. #endif
  103.     return PTHREAD_RETURN;
  104.   }
  105.   
  106.   // lancer ftp
  107. #if FTP_DEBUG
  108.   printf("[Launching main ftp routine]\n");
  109. #endif
  110.   run_launch_ftp(back);
  111.   // prΩt
  112.   back->status=0;
  113.   
  114.   return PTHREAD_RETURN;
  115. }
  116. /*#endif*/
  117. // lancer en back
  118. void launch_ftp(lien_back* back) {
  119. /*
  120. #ifdef __cplusplus
  121.   // C++ -> Shell
  122.   AfxBeginThread(back_launch_ftp,(LPVOID) back);
  123. #else
  124. */
  125.   // DOS
  126. #if FTP_DEBUG
  127.   printf("[Launching main ftp thread]\n");
  128. #endif
  129.   _beginthread(back_launch_ftp, 0, (void*) back);
  130. /*#endif*/
  131. }
  132.  
  133. #else
  134. // Unix sans pthread
  135. int back_launch_ftp(lien_back* back) {
  136.   // lancer ftp
  137.   run_launch_ftp(back);
  138.   // prΩt
  139.   back->status=0;
  140.   return 0;
  141. }
  142. void launch_ftp(lien_back* back,char* path,char* exec) {
  143.   FILE* fp = fopen(fconv(path),"wb");
  144.   if (fp) {
  145.     char _args[8][256];
  146.     char *args[8];
  147.     fclose(fp); fp=NULL;
  148.     
  149.     strcpy(_args[0],exec);
  150.     strcpy(_args[1],"-#R");
  151.     strcpy(_args[2],back->url_adr);
  152.     strcpy(_args[3],back->url_fil);
  153.     strcpy(_args[4],back->url_sav);
  154.     strcpy(_args[5],path);
  155.     //strcpy(_args[6],"");
  156.     args[0]=_args[0];
  157.     args[1]=_args[1];
  158.     args[2]=_args[2];
  159.     args[3]=_args[3];
  160.     args[4]=_args[4];
  161.     args[5]=_args[5];
  162.     args[6]=NULL;
  163.     switch (fork()) {    // note: vfork dΘconne un max'
  164.     case -1: printf("Can not vfork() process\n"); break;
  165.     case 0: 
  166.       if (execvp(args[0],args)==-1) {
  167.         fp=fopen(fconv(path),"wb");
  168.         if (fp) {
  169.           fprintf(fp,"-1 unable to launch %s",args[0]);
  170.           fclose(fp); fp=NULL;
  171.           rename(path,concat(path,".ok"));
  172.         } else remove(path);
  173.       }
  174.       _exit(0);    // exit 'propre'
  175.       break;
  176.     default:  // parent
  177.       // bah on fait rien..
  178.       break;         
  179.     }
  180.   }
  181. }
  182. #endif
  183.  
  184. // pour l'arrΩt du ftp
  185. #ifdef _WIN32
  186. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  187. #else
  188. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  189. #endif
  190. #define _HALT_FTP { \
  191.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  192.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  193.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  194. }
  195. #define _CHECK_HALT_FTP \
  196.   if (stop_ftp(back)) { \
  197.   _HALT_FTP \
  198.   return 0; \
  199.   }
  200.  
  201. // la vΘritable fonction une fois lancΘes les routines thread/fork
  202. int run_launch_ftp(lien_back* back) {
  203.   char user[256]="anonymous";
  204.   char pass[256]="user@";
  205.   char line_retr[2048];
  206.   int port=21;
  207.   int port_pasv=0;
  208.   char adr_ip[1024];
  209.   char *adr,*real_adr;
  210.   char* ftp_filename="";
  211.   int timeout = 300;    // timeout
  212.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  213.   int transfer_list=0;  // directory
  214.   int rest_understood=0;  // rest command understood
  215.   //
  216.   T_SOC soc_ctl=INVALID_SOCKET;
  217.   T_SOC soc_servdat=INVALID_SOCKET;
  218.   T_SOC soc_dat=INVALID_SOCKET;
  219.   //
  220.   line_retr[0]=adr_ip[0]='\0';
  221.   
  222.   timeout=300;
  223.   
  224.   // effacer
  225.   strcpy(back->r.msg,"");
  226.   back->r.statuscode=0;
  227.   back->r.size=0;
  228.   
  229.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  230.   real_adr = strchr(back->url_adr,':');
  231.   if (real_adr) real_adr++;
  232.   else real_adr=back->url_adr;
  233.   while(*real_adr=='/') real_adr++;    // sauter /
  234.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  235.     int i=-1;
  236.     pass[0]='\0';
  237.     do {
  238.       i++;
  239.       user[i]=real_adr[i];
  240.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  241.     user[i]='\0';
  242.     if (real_adr[i]==':') {    // pass
  243.       int j=-1;
  244.       i++;  // oui on saute aussi le :
  245.       do {
  246.         j++;
  247.         pass[j]=real_adr[i+j];
  248.       } while( ((int) (&real_adr[i+j+1]) < (int) adr) && (real_adr[i+j]) );
  249.       pass[j]='\0';
  250.     }
  251.   }
  252.   
  253.   // Calculer RETR <nom>
  254.   {
  255.     char* a;
  256.     a=back->url_fil + strlen(back->url_fil)-1;
  257.     while( ((int) a > (int) back->url_fil) && (*a!='/')) a--;
  258.     if (*a == '/') {    // ok repΘrΘ
  259.       a++;    // sauter /
  260.       ftp_filename=a;
  261.       if (strnotempty(a))
  262.         sprintf(line_retr,"RETR %s",a);
  263.       else {
  264.         transfer_list=1;
  265.         sprintf(line_retr,"LIST -A");
  266.       }
  267.     } else {
  268.       strcpy(back->r.msg,"Unexpected PORT error");
  269.       back->status=FTP_STATUS_READY;    // fini
  270.       back->r.statuscode=-1;
  271.     }
  272.   }
  273.   
  274. #if FTP_DEBUG
  275.   printf("Connecting to %s...\n",adr);
  276. #endif
  277.   
  278.   // connexion
  279.   {
  280.     struct sockaddr_in server;
  281.     t_hostent* hp;    
  282.     char * a;
  283.     char _adr[256];
  284.     _adr[0]='\0';
  285.     //T_SOC soc_ctl;
  286.     // effacer structure
  287.     bzero((char *)&server, sizeof(server));
  288.     
  289.     // port
  290.     a=strchr(adr,':');    // port
  291.     if (a) {
  292.       sscanf(a+1,"%d",&port);
  293.       strncat(_adr,adr,(int) a - (int) adr);
  294.     } else
  295.       strcpy(_adr,adr);
  296.     
  297.     // rΘcupΘrer adresse rΘsolue
  298.     strcpy(back->info,"host name");
  299.     hp = hts_gethostbyname(_adr);
  300.     if (hp == NULL) {
  301.       strcpy(back->r.msg,"Unable to get server's address");
  302.       back->status=FTP_STATUS_READY;    // fini
  303.       back->r.statuscode=-5;
  304.       _HALT_FTP
  305.         return 0;
  306.     }
  307.     _CHECK_HALT_FTP;
  308.     
  309.     // copie adresse
  310.     bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  311.     
  312.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  313.     soc_ctl=socket(AF_INET,SOCK_STREAM,0);
  314.     if (soc_ctl==INVALID_SOCKET) {
  315.       strcpy(back->r.msg,"Unable to create a socket");
  316.       back->status=FTP_STATUS_READY;    // fini
  317.       back->r.statuscode=-1;
  318.       _HALT_FTP
  319.         return 0;
  320.     }
  321.     server.sin_family = AF_INET;
  322.     server.sin_port = htons((unsigned short int) port);
  323.     
  324.     // connexion (bloquante, on est en thread)
  325.     strcpy(back->info,"connect");
  326.  
  327. #if HTS_WIN
  328.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, sizeof(server)) != 0) {
  329. #else
  330.       if (connect(soc_ctl, (struct sockaddr *)&server, sizeof(server)) == -1) {
  331. #endif
  332.         strcpy(back->r.msg,"Unable to connect to the server");
  333.         back->status=FTP_STATUS_READY;    // fini
  334.         back->r.statuscode=-1;
  335.         _HALT_FTP
  336.           return 0;
  337. #if HTS_WIN
  338.       }
  339. #else
  340.     }
  341. #endif
  342.     _CHECK_HALT_FTP;
  343.     
  344.     {
  345.       char line[1024];
  346.       // envoi du login
  347.       
  348.       // --USER--
  349.       get_line(soc_ctl,line,timeout);    // en tΩte
  350.       _CHECK_HALT_FTP;
  351.       
  352.       if (line[0]=='2') {        // ok, connectΘ
  353.         strcpy(back->info,"login: user");
  354.         sprintf(line,"USER %s",user);
  355.         send_line(soc_ctl,line);
  356.         get_line(soc_ctl,line,timeout);
  357.         _CHECK_HALT_FTP;      
  358.         if (line[0]=='3') {
  359.           // --PASS--
  360.           strcpy(back->info,"login: pass");
  361.           sprintf(line,"PASS %s",pass);
  362.           send_line(soc_ctl,line);
  363.           get_line(soc_ctl,line,timeout);
  364.           _CHECK_HALT_FTP;      
  365.           if (line[0]=='2') {  // ok
  366.             // --CWD--
  367.             char* a;
  368.             a=back->url_fil + strlen(back->url_fil)-1;
  369.             while( ((int) a > (int) back->url_fil) && (*a!='/')) a--;
  370.             if (*a == '/') {    // ok repΘrΘ
  371.               char target[1024];
  372.               target[0]='\0';
  373.               strncat(target,back->url_fil,(int) a - (int) back->url_fil);
  374.               if (strnotempty(target)==0)
  375.                 strcat(target,"/");
  376.               strcpy(back->info,"cwd");
  377.               sprintf(line,"CWD %s",target);
  378.               send_line(soc_ctl,line);
  379.               get_line(soc_ctl,line,timeout);
  380.               _CHECK_HALT_FTP;      
  381.               if (line[0]=='2') {
  382.                 send_line(soc_ctl,"TYPE I");
  383.                 get_line(soc_ctl,line,timeout);
  384.                 _CHECK_HALT_FTP;      
  385.                 if (line[0]=='2') {
  386.                   // ok..
  387.                 } else {
  388.                   strcpy(back->r.msg,"TYPE I error");
  389.                   back->status=FTP_STATUS_READY;    // fini
  390.                   back->r.statuscode=-1;
  391.                 }
  392.               } else {
  393.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  394.                 back->status=FTP_STATUS_READY;    // fini
  395.                 back->r.statuscode=-1;
  396.               }    // sinon on est prΩts
  397.             } else {
  398.               strcpy(back->r.msg,"Unexpected ftp error");
  399.               back->status=FTP_STATUS_READY;    // fini
  400.               back->r.statuscode=-1;
  401.             }
  402.             
  403.           } else {
  404.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  405.             back->status=FTP_STATUS_READY;    // fini
  406.             back->r.statuscode=-1;
  407.           }
  408.         } else {
  409.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  410.           back->status=FTP_STATUS_READY;    // fini
  411.           back->r.statuscode=-1;
  412.         }
  413.       } else {
  414.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  415.         back->status=FTP_STATUS_READY;    // fini
  416.         back->r.statuscode=-1;
  417.       }
  418.      
  419.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  420.       if (back->r.statuscode != -1) {
  421.  
  422.         
  423.         //
  424.         // PrΘ-REST
  425.         //
  426. #if FTP_PASV
  427.         strcpy(back->info,"pasv");
  428.         sprintf(line,"PASV");
  429.         send_line(soc_ctl,line);
  430.         get_line(soc_ctl,line,timeout);
  431.         _CHECK_HALT_FTP;      
  432.         if (line[0]=='2') {
  433.           char *a,*b,*c;
  434.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  435.           if (a) {
  436.            
  437.             // -- analyse de l'adresse IP et du port --
  438.             a++;
  439.             b=strchr(a,',');
  440.             if (b) b=strchr(b+1,',');
  441.             if (b) b=strchr(b+1,',');
  442.             if (b) b=strchr(b+1,',');
  443.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  444.             if (b) *b='\0';
  445.             //
  446.             strcpy(adr_ip,a);       // copier adresse ip
  447.             //
  448.             if (b) {
  449.               a=b+1;  // dΘbut du port
  450.               b=strchr(a,'.');
  451.               if (b) {
  452.                 int n1,n2;
  453.                 //
  454.                 *b='\0';
  455.                 b++;
  456.                 c=strchr(b,')');
  457.                 if (c) {
  458.                   *c='\0';
  459.                   //
  460.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  461.                     //
  462. #ifndef HTS_LITTLE_ENDIAN
  463.                     port_pasv=n2+(n1<<8);
  464. #else
  465.                     port_pasv=n1+(n2<<8);
  466. #endif
  467.                   }
  468.                 } else {
  469.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  470.                 }    // sinon on est prΩts
  471.               }
  472.             }
  473.             // -- fin analyse de l'adresse IP et du port --
  474.           } else {
  475.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  476.             back->status=FTP_STATUS_READY;    // fini
  477.             back->r.statuscode=-1;
  478.           }    // sinon on est prΩts
  479.         } else {
  480.           sprintf(back->r.msg,"PASV error: %s",linejmp(line));
  481.           back->status=FTP_STATUS_READY;    // fini
  482.           back->r.statuscode=-1;
  483.         }    // sinon on est prΩts
  484. #else
  485.         // rien α faire avant
  486. #endif
  487.  
  488. #if FTP_PASV
  489.         if (port_pasv) {
  490. #endif
  491.           // REST lui mΩme
  492.           if (back->r.statuscode != -1) {
  493.             if (!transfer_list) {
  494.               // SIZE?
  495.               strcpy(back->info,"size");
  496.               sprintf(line,"SIZE %s",ftp_filename);
  497.               send_line(soc_ctl,line);
  498.               get_line(soc_ctl,line,timeout);
  499.               _CHECK_HALT_FTP;      
  500.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  501.                 // REST?
  502.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  503.                   strcpy(back->info,"rest");
  504.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  505.                   send_line(soc_ctl,line);
  506.                   get_line(soc_ctl,line,timeout);
  507.                   _CHECK_HALT_FTP;      
  508.                   if (line[0]=='3') {  // ok
  509.                     rest_understood=1;
  510.                   } // sinon tant pis 
  511.                 } 
  512.               }  // sinon tant pis 
  513.             }
  514.           }
  515. #if FTP_PASV
  516.         }
  517. #endif
  518.  
  519.         //
  520.         // Post-REST
  521.         //
  522. #if FTP_PASV
  523.         // Ok, se connecter
  524.         if (port_pasv) {
  525.           struct sockaddr_in server;
  526.           t_hostent* hp;    
  527.           // effacer structure
  528.           bzero((char *)&server, sizeof(server));
  529.           
  530.           // infos
  531.           strcpy(back->info,"resolv");
  532.           
  533.           // rΘsoudre
  534.           hp = hts_gethostbyname(adr_ip);
  535.           
  536.           // infos
  537.           strcpy(back->info,"cnxdata");
  538. #if FTP_DEBUG
  539.           printf("Data: Connecting to %s:%d...\n",adr_ip,port_pasv);
  540. #endif
  541.           if (hp) {
  542.             // copie adresse
  543.             bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  544.             
  545.             // socket
  546.             soc_dat=socket(AF_INET,SOCK_STREAM,0);
  547.             if (soc_dat != INVALID_SOCKET) {
  548.               // structure: connexion au domaine internet, port 80 (ou autre)
  549.               server.sin_family = AF_INET;
  550.               server.sin_port = htons((unsigned short int) port_pasv);
  551. #if HTS_WIN
  552.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, sizeof(server)) == 0) {
  553. #else
  554.               if (connect(soc_dat, (struct sockaddr *)&server, sizeof(server)) != -1) {
  555. #endif
  556.                 strcpy(back->info,"retr");
  557.                 strcpy(line,line_retr);
  558.                 send_line(soc_ctl,line);
  559.                 get_line(soc_ctl,line,timeout);
  560.                 _CHECK_HALT_FTP;      
  561.                 if (line[0]=='1') {
  562.                   // OK
  563.                 } else {
  564.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  565.                   //
  566.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  567.                   back->status=FTP_STATUS_READY;    // fini
  568.                   back->r.statuscode=-1;
  569.                 }    // sinon on est prΩts
  570.               } else {
  571.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  572.                 //
  573.                 strcpy(back->r.msg,"Unable to connect");
  574.                 back->status=FTP_STATUS_READY;    // fini
  575.                 back->r.statuscode=-1;
  576.               }    // sinon on est prΩts
  577.             } else {
  578.               strcpy(back->r.msg,"Unable to create a socket");
  579.               back->status=FTP_STATUS_READY;    // fini
  580.               back->r.statuscode=-1;
  581.             }    // sinon on est prΩts
  582.           } else {
  583.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  584.             back->status=FTP_STATUS_READY;    // fini
  585.             back->r.statuscode=-1;
  586.           }    // sinon on est prΩts
  587.         } else {
  588.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  589.           back->status=FTP_STATUS_READY;    // fini
  590.           back->r.statuscode=-1;
  591.         }    // sinon on est prΩts
  592. #else
  593.         //T_SOC soc_servdat;
  594.         strcpy(back->info,"listening");
  595.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  596.           _CHECK_HALT_FTP;      
  597.           send_line(soc_ctl,line);          // envoi du RETR
  598.           get_line(soc_ctl,line,timeout);
  599.           _CHECK_HALT_FTP;      
  600.           if (line[0]=='2') {  // ok
  601.             strcpy(back->info,"retr");
  602.             strcpy(line,line_retr);
  603.             send_line(soc_ctl,line);
  604.             get_line(soc_ctl,line,timeout);
  605.             _CHECK_HALT_FTP;      
  606.             if (line[0]=='1') {
  607.               //T_SOC soc_dat;
  608.               struct sockaddr dummyaddr;
  609.               int dummylen = sizeof(struct sockaddr);
  610.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  611.                 strcpy(back->r.msg,"Unable to accept connection");
  612.                 back->status=FTP_STATUS_READY;    // fini
  613.                 back->r.statuscode=-1;
  614.               }
  615.             } else {
  616.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  617.               back->status=FTP_STATUS_READY;    // fini
  618.               back->r.statuscode=-1;
  619.             }
  620.           } else {
  621.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  622.             back->status=FTP_STATUS_READY;    // fini
  623.             back->r.statuscode=-1;
  624.           }
  625. #if HTS_WIN
  626.           closesocket(soc_servdat);
  627. #else
  628.           close(soc_servdat);
  629. #endif
  630.         } else {
  631.           strcpy(back->r.msg,"Unable to listen to a port");
  632.           back->status=FTP_STATUS_READY;    // fini
  633.           back->r.statuscode=-1;
  634.         }
  635. #endif
  636.         
  637.         //
  638.         // Ok, connexion initiΘe
  639.         //
  640.         if (soc_dat != INVALID_SOCKET) {
  641.           if (rest_understood) {         // REST envoyΘe et comprise
  642.             filenote(back->url_sav,NULL);
  643.             back->r.fp = fopen(fconv(back->url_sav),"ab");
  644.           } else
  645.             back->r.fp = filecreate(back->url_sav);
  646.           strcpy(back->info,"receiving");
  647.           if (back->r.fp != NULL) {
  648.             char buff[1024];
  649.             int len=1;
  650.             int read_len=1024;
  651.             HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  652.             
  653.             while( (len>0) && (!stop_ftp(back)) ) {
  654.               // attendre les donnΘes
  655.               len=1;    // pas d'erreur pour le moment
  656.               switch(wait_socket_receive(soc_dat,timeout)) {
  657.               case -1:
  658.                 strcpy(back->r.msg,"Read error");
  659.                 back->status=FTP_STATUS_READY;    // fini
  660.                 back->r.statuscode=-1;
  661.                 len=0;    // fin
  662.                 break;
  663.               case 0:
  664.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  665.                 back->status=FTP_STATUS_READY;    // fini
  666.                 back->r.statuscode=-1;
  667.                 len=0;    // fin
  668.                 break;
  669.               }
  670.               
  671.               // rΘception
  672.               if (len) {
  673.                 len=recv(soc_dat,buff,read_len,0);
  674.                 if (len>0) {
  675.                   back->r.size+=len;
  676.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  677.                   if (back->r.fp) {
  678.                     if ((int) fwrite(buff,1,len,back->r.fp) != len) {
  679.                       strcpy(back->r.msg,"Write error");
  680.                       back->status=FTP_STATUS_READY;    // fini
  681.                       back->r.statuscode=-1;
  682.                       len=0;  // error
  683.                     }
  684.                   } else {
  685.                     strcpy(back->r.msg,"Unexpected write error");
  686.                     back->status=FTP_STATUS_READY;    // fini
  687.                     back->r.statuscode=-1;
  688.                   }
  689.                 } else {        // Erreur ou terminΘ
  690.                   //strcpy(back->r.msg,"Read error");
  691.                   back->status=FTP_STATUS_READY;    // fini
  692.                   back->r.statuscode=0;
  693.                 }
  694.                 read_len=1024; HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  695.               }
  696.             }
  697.             if (back->r.fp) { 
  698.               fclose(back->r.fp); 
  699.               back->r.fp=NULL;
  700.             }
  701.           } else {
  702.             strcpy(back->r.msg,"Unable to write file");
  703.             back->status=FTP_STATUS_READY;    // fini
  704.             back->r.statuscode=-1;
  705.           }
  706. #if HTS_WIN
  707.           closesocket(soc_dat);
  708. #else
  709.           close(soc_dat);
  710. #endif
  711.           
  712.           // 226 Transfer complete?
  713.           if (back->r.statuscode != -1) {
  714.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  715.               // rΘcupΘrer 226 transfer complete
  716.               get_line(soc_ctl,line,timeout);
  717.               if (line[0]=='2') {       // OK
  718.                 strcpy(back->r.msg,"OK");
  719.                 back->status=FTP_STATUS_READY;    // fini
  720.                 back->r.statuscode=200;
  721.               } else {
  722.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  723.                 back->status=FTP_STATUS_READY;    // fini
  724.                 back->r.statuscode=-1;
  725.               }
  726.             } else {
  727.               strcpy(back->r.msg,"Read error");
  728.               back->status=FTP_STATUS_READY;    // fini
  729.               back->r.statuscode=-1;
  730.             }
  731.           }
  732.           
  733.         }
  734.         
  735.         
  736.         
  737.       }
  738.       
  739.       
  740.     }
  741.     
  742.     _CHECK_HALT_FTP;
  743.     strcpy(back->info,"quit");
  744.     send_line(soc_ctl,"QUIT");    // bye bye
  745.     get_line(soc_ctl,NULL,timeout);
  746. #if HTS_WIN
  747.     closesocket(soc_ctl);
  748. #else
  749.     close(soc_ctl);
  750. #endif
  751.   }
  752.   
  753.   if (back->r.statuscode!=-1) {
  754.     back->r.statuscode=200;
  755.     strcpy(back->r.msg,"OK");
  756.   }
  757.   back->status=FTP_STATUS_READY;    // fini
  758.   return 0;
  759. }
  760.  
  761.  
  762.  
  763. // ouverture d'un port
  764. T_SOC get_datasocket(char* to_send) {
  765.   T_SOC soc = INVALID_SOCKET;
  766.   char h_loc[256+2];
  767.   
  768.   to_send[0]='\0';
  769.   if (gethostname(h_loc,256)==0) {    // host name
  770.     t_hostent* hp_loc;    
  771.     if ( (hp_loc=gethostbyname(h_loc)) ) {  // notre host      
  772.       if ( (soc=socket(AF_INET,SOCK_STREAM,0)) != INVALID_SOCKET) {
  773.         struct sockaddr_in server;
  774.         // effacer structure
  775.         bzero((char *)&server, sizeof(server));
  776.         server.sin_family = AF_INET;
  777.         server.sin_port = htons((unsigned short int) 0);    // demander port qque
  778.         // copie adresse locale
  779.         bcopy(hp_loc->h_addr, (char *)&server.sin_addr, hp_loc->h_length);
  780.         // // NAAN server.sin_addr.s_addr=htonl(INADDR_ANY);
  781.         if ( bind(soc,(struct sockaddr*) &server,sizeof(struct sockaddr)) == 0 ) {
  782.           struct sockaddr_in server2;
  783.           int len;
  784.           len=sizeof(server2);
  785.           // effacer structure
  786.           bzero((char *)&server2, sizeof(server2));
  787.           if (getsockname(soc,(struct sockaddr*) &server2,&len) == 0) {
  788.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  789.             if (listen(soc,10)>=0) {    // au pif le 10
  790.               unsigned short int a,n1,n2;
  791.               // calculer port
  792.               a  = server2.sin_port;
  793. #ifndef HTS_LITTLE_ENDIAN
  794.               n1 = (a & 0xff);
  795.               n2 = ((a>>8) & 0xff);
  796. #else
  797.               n2 = (a & 0xff);
  798.               n1 = ((a>>8) & 0xff);
  799. #endif
  800.               // calculer adresse
  801.               // pour commande port
  802.               {
  803.                 char dots[256];
  804.                 char* a;
  805.                 char* dot = (char*) inet_ntoa(server2.sin_addr);
  806.                 dots[0]='\0';
  807.                 //
  808.                 strncat(dots,dot,32);
  809.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  810.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  811.               }
  812.               
  813.             } else {
  814. #if HTS_WIN
  815.               closesocket(soc);
  816. #else
  817.               close(soc);
  818. #endif
  819.               soc=INVALID_SOCKET;
  820.             }
  821.             
  822.             
  823.           } else {
  824. #if HTS_WIN
  825.             closesocket(soc);
  826. #else
  827.             close(soc);
  828. #endif
  829.             soc=INVALID_SOCKET;
  830.           }
  831.           
  832.           
  833.         } else {
  834. #if HTS_WIN
  835.           closesocket(soc);
  836. #else
  837.           close(soc);
  838. #endif
  839.           soc=INVALID_SOCKET;
  840.         }
  841.       }
  842.     }
  843.   }
  844.   
  845.   
  846.   return soc;
  847. }
  848.  
  849. #if FTP_DEBUG
  850. FILE* dd=NULL;
  851. #endif
  852.  
  853. // routines de rΘception/Θmission
  854. // 0 = ERROR
  855. int send_line(T_SOC soc,char* data) {
  856.   char line[1024];
  857.   if (_DEBUG_HEAD) {
  858.     if (ioinfo) {
  859.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  860.       fflush(ioinfo);
  861.     }
  862.   }
  863. #if FTP_DEBUG
  864.   if (dd == NULL) dd = fopen("toto.txt","w");
  865.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  866.   printf("---> %s",data); fflush(stdout);
  867. #endif
  868.   sprintf(line,"%s\x0d\x0a",data);
  869.   if (check_socket_connect(soc) != 1) {
  870. #if FTP_DEBUG
  871.     printf("!SOC WRITE ERROR\n");
  872. #endif
  873.     return 0;    // erreur, plus connectΘ!
  874.   }
  875. #if FTP_DEBUG
  876.   {
  877.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  878.     printf("%s\x0d\x0a",data); fflush(stdout);
  879.     return r;
  880.   }
  881. #else
  882.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  883. #endif
  884. }
  885.  
  886. int get_line(T_SOC soc,char* line,int timeout) {
  887.   char data[1024];
  888.   int i,ok;
  889. #if FTP_DEBUG
  890.   if (dd == NULL) dd = fopen("toto.txt","w");
  891. #endif
  892.   
  893.   data[0]='\0';
  894.   i=0; ok=0; data[3]='\0';
  895.   do {
  896.     char b;                        
  897.     int dummy=1;    // =1 : dummy (pour CHECK)
  898.     
  899.     // vΘrifier donnΘes
  900.     switch(wait_socket_receive(soc,timeout)) {
  901.     case -1:   // erreur de lecture
  902.       if (line) strcpy(line,"500 *read error");
  903.       return 0;
  904.       break;
  905.     case 0:
  906.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  907.       return 0;
  908.       break;
  909.     }
  910.     
  911.     HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  912.     switch(recv(soc,&b,1,0)) {
  913.       //case 0: break;    // pas encore --> erreur (on attend)!
  914.     case 1:
  915.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  916.       if ((b!=10) && (b!=13))
  917.         data[i++]=b;
  918.       break;
  919.     default:
  920.       if (line) strcpy(line,"500 *read error");
  921.       return 0; // error
  922.       break;
  923.     }
  924.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  925.       if (data[3]!='-')          // y'en a encore!!
  926.         ok=1;    // sortir
  927.       else {  // suivante
  928.         data[3]='\0';
  929.         i=0;
  930.       }
  931.     }
  932.   } while(!ok);
  933.   data[i++]='\0';
  934.   
  935.   if (_DEBUG_HEAD) {
  936.     if (ioinfo) {
  937.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  938.       fflush(ioinfo);
  939.     }
  940.   }
  941. #if FTP_DEBUG
  942.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  943.   printf("<--- %s\n",data);
  944. #endif
  945.   if (line) strcpy(line,data);
  946.   return (strnotempty(data));
  947. }
  948.  
  949. // sauter NNN
  950. char* linejmp(char* line) {
  951.   if (strlen(line)>4)
  952.     return line+4;
  953.   else
  954.     return line;
  955. }
  956.  
  957. // test socket:
  958. // 0 : no data
  959. // 1 : data detected
  960. // -1: error
  961. int check_socket(T_SOC soc) {
  962.   fd_set fds,fds_e;           // poll structures
  963.   struct timeval tv;          // structure for select
  964.   FD_ZERO(&fds);
  965.   FD_ZERO(&fds_e); 
  966.   // socket read 
  967.   FD_SET(soc,&fds);           
  968.   // socket error
  969.   FD_SET(soc,&fds_e);
  970.   tv.tv_sec=0;
  971.   tv.tv_usec=0;
  972.   // poll!     
  973.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  974.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  975.     return -1;
  976.   } else if (FD_ISSET(soc,&fds)) {
  977.     return 1;
  978.   }
  979.   return 0;
  980. }
  981. // check if connected
  982. int check_socket_connect(T_SOC soc) {
  983.   fd_set fds,fds_e;           // poll structures
  984.   struct timeval tv;          // structure for select
  985.   FD_ZERO(&fds);
  986.   FD_ZERO(&fds_e); 
  987.   // socket write 
  988.   FD_SET(soc,&fds);           
  989.   // socket error
  990.   FD_SET(soc,&fds_e);
  991.   tv.tv_sec=0;
  992.   tv.tv_usec=0;
  993.   // poll!     
  994.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  995.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  996.     return -1;
  997.   } else if (FD_ISSET(soc,&fds)) {
  998.     return 1;
  999.   }
  1000.   return 0;
  1001. }
  1002. // attendre des donnΘes
  1003. int wait_socket_receive(T_SOC soc,int timeout) {
  1004.   // attendre les donnΘes
  1005.   double ltime=time_local();
  1006.   int r;
  1007. #if FTP_DEBUG
  1008.   printf("\x0dWaiting for data "); fflush(stdout);
  1009. #endif
  1010.   while( (!(r = check_socket(soc))) && ( ((int) ((double) (time_local()-ltime))) < timeout )) {
  1011.     Sleep(100);
  1012. #if FTP_DEBUG
  1013.     printf("."); fflush(stdout);
  1014. #endif
  1015.   }
  1016. #if FTP_DEBUG
  1017.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1018. #endif
  1019.   return r;
  1020. }
  1021.  
  1022.  
  1023. // cancel reτu?
  1024. int stop_ftp(lien_back* back) {
  1025.   if (back->stop_ftp) {
  1026.     strcpy(back->r.msg,"Cancelled by User");
  1027.     back->status=FTP_STATUS_READY;    // fini
  1028.     back->r.statuscode=-1;
  1029.     return 1;
  1030.   }
  1031.   return 0;
  1032. }
  1033.  
  1034.  
  1035.  
  1036.  
  1037.