home *** CD-ROM | disk | FTP | other *** search
/ PC Open 48 / pcopen48.iso / Internet / HtTrack / DATA1.CAB / Sources / src / htsftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-21  |  29.0 KB  |  1,036 lines

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