home *** CD-ROM | disk | FTP | other *** search
/ PC Open 48 / pcopen48.iso / Internet / HtTrack / DATA1.CAB / Sources / src / htsback.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-21  |  68.7 KB  |  1,826 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: httrack.c subroutines:                                 */
  37. /*       backing system (multiple socket download)              */
  38. /* Author: Xavier Roche                                         */
  39. /* ------------------------------------------------------------ */
  40.  
  41. #include "htsback.h"
  42.  
  43. /* specific definitions */
  44. #include "htsbase.h"
  45. #include "htsnet.h"
  46. #include "htsthread.h"
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. /* END specific definitions */
  51.  
  52. //#if HTS_WIN
  53. #include "htsftp.h"
  54. //#endif
  55.  
  56. #if HTS_WIN
  57. #ifndef __cplusplus
  58. // DOS
  59. #include <process.h>    /* _beginthread, _endthread */
  60. #endif
  61. #else
  62. #endif
  63.  
  64. #undef test_flush
  65. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  66.  
  67. // ---
  68. // routines de backing
  69. // retourne l'index d'un lien dans un tableau de backing
  70. int back_index(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  71.   register int i=0;
  72.   register int index=-1;
  73.   while( i<back_max ) {
  74.     if (back[i].status>=0)    // rΘception OU prΩt
  75.       if (strfield2(back[i].url_adr,adr)) {
  76.         if (strcmp(back[i].url_fil,fil)==0) {
  77.           if (index==-1)    /* first time we meet, store it */
  78.             index=i;
  79.           else if (strcmp(back[i].url_sav,sav)==0) {  /* oops, check sav too */
  80.             index=i;
  81.             return index;
  82.           }
  83.         }
  84.       }
  85.     i++;
  86.   }
  87.   return index;
  88. }
  89.  
  90. // nombre d'entrΘes libres dans le backing
  91. int back_available(lien_back* back,int back_max) {
  92.   int i;
  93.   int nb=0;
  94.   for(i=0;i<back_max;i++)
  95.     if (back[i].status==-1)     /* libre */
  96.       nb++;
  97.   return nb;
  98. }
  99.  
  100. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  101. LLint back_incache(lien_back* back,int back_max) {
  102.   int i;
  103.   LLint sum=0;
  104.   for(i=0;i<back_max;i++)
  105.     if (back[i].status!=-1)
  106.       if (back[i].r.adr)       // ne comptabilier que les blocs en mΘmoire
  107.         sum+=max(back[i].r.size,back[i].r.totalsize);
  108.   return sum;
  109. }
  110.  
  111. // le lien a-t-il ΘtΘ mis en backing?
  112. HTS_INLINE int back_exist(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  113.   return (back_index(back,back_max,adr,fil,sav)>=0);
  114. }
  115.  
  116. // nombre de sockets en tΓche de fond
  117. int back_nsoc(lien_back* back,int back_max) {
  118.   int n=0;
  119.   int i;
  120.   for(i=0;i<back_max;i++)
  121.     if (back[i].status>0)    // rΘception uniquement
  122.       n++;
  123.  
  124.   return n;
  125. }
  126.  
  127. // effacer entrΘe
  128. int back_delete(lien_back* back,int p) {
  129.   if (p>=0) {    // on sait jamais..
  130.     // VΘrificateur d'intΘgritΘ
  131.     #if DEBUG_CHECKINT
  132.     _CHECKINT(&back[p],"Appel back_delete")
  133.     #endif
  134. #if HTS_DEBUG_CLOSESOCK
  135.     char info[256];
  136.     sprintf(info,"back_delete: #%d\n",p);
  137.     DEBUG_W2(info);
  138. #endif
  139.  
  140.     // LibΘrer tous les sockets, handles, buffers..
  141.     if (back[p].r.soc!=INVALID_SOCKET) {
  142. #if HTS_DEBUG_CLOSESOCK
  143.       DEBUG_W("back_delete: deletehttp\n");
  144. #endif
  145.       deletehttp(&back[p].r);
  146.       back[p].r.soc=INVALID_SOCKET;
  147.     }
  148.     if (back[p].r.adr!=NULL) {  // reste un bloc α dΘsallouer
  149.       freet(back[p].r.adr);
  150.       back[p].r.adr=NULL;
  151.     }
  152.     if (back[p].chunk_adr!=NULL) {  // reste un bloc α dΘsallouer
  153.       freet(back[p].chunk_adr);
  154.       back[p].chunk_adr=NULL;
  155.       back[p].chunk_size=0;
  156.       back[p].is_chunk=0;
  157.     }
  158.     if (back[p].r.is_file) {  // fermer fichier entrΘe
  159.       if (back[p].r.fp!=NULL) {
  160.         fclose(back[p].r.fp);
  161.         back[p].r.fp=NULL;
  162.       }
  163.     }
  164.     if (back[p].r.is_write) {     // ecriture directe
  165.       if (back[p].r.out!=NULL) {  // fermer fichier sortie
  166.         fclose(back[p].r.out);
  167.         back[p].r.out=NULL;
  168.       }
  169.       
  170.       /* Θcrire date "remote" */
  171.       if (strnotempty(back[p].url_sav))          // normalement existe si on a un fichier de sortie
  172.       if (strnotempty(back[p].r.lastmodified))   // last-modified existe
  173.       if (fexist(back[p].url_sav))          // ainsi que le fichier
  174.         set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
  175.  
  176.       /* executer commande utilisateur aprΦs chargement du fichier */
  177.       usercommand(0,NULL,back[p].url_sav);
  178.       back[p].r.is_write=0;
  179.     }
  180.     
  181.     // Tout nettoyer
  182.     bzero((char *)(&back[p]),sizeof(lien_back));  
  183.     back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  184.     
  185.     // Le plus important: libΘrer le champ
  186.     back[p].status=-1;
  187.   }
  188.   return 0;
  189. }
  190.  
  191. // ajouter un lien en backing
  192. int back_add(lien_back* back,int back_max,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test) {
  193.   int p=0;
  194.  
  195.   // vΘrifier cohΘrence de adr et fil (non vide!)
  196.   if (strnotempty(adr)==0) {
  197.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  198.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: adr is empty for back_add"LF);
  199.     }
  200.     return -1;    // erreur!
  201.   }
  202.   if (strnotempty(fil)==0) {
  203.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  204.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: fil is empty for back_add"LF);
  205.     }
  206.     return -1;    // erreur!
  207.   }
  208.   // FIN vΘrifier cohΘrence de adr et fil (non vide!)
  209.  
  210.   // rechercher emplacement
  211.   while((p<back_max) && back[p].status!=-1) p++;
  212.   if (back[p].status==-1) {    // ok on a de la place
  213.     back[p].send_too[0]='\0';  // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
  214.  
  215.     // ne sert α rien normalement
  216.     if (back[p].r.soc!=INVALID_SOCKET) {
  217. #if HTS_DEBUG_CLOSESOCK
  218.       DEBUG_W("back_add: deletehttp\n");
  219. #endif
  220.       deletehttp(&back[p].r);
  221.     }
  222.  
  223.     // effacer r
  224.     bzero((char*) &(back[p].r), sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  225.  
  226.     // crΘer entrΘe
  227.     strcpy(back[p].url_adr,adr);
  228.     strcpy(back[p].url_fil,fil);
  229.     strcpy(back[p].url_sav,save);
  230.     // copier referer si besoin
  231.     strcpy(back[p].referer_adr,"");
  232.     strcpy(back[p].referer_fil,"");
  233.     if ((referer_adr) && (referer_fil)) {       // existe
  234.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  235.         if (referer_adr[0]!='!') {    // non dΘtruit
  236.           if (strcmp(referer_adr,"file://")) {      // PAS file://
  237.             if (strcmp(referer_adr,"primary")) {      // pas referer 1er lien
  238.               strcpy(back[p].referer_adr,referer_adr);
  239.               strcpy(back[p].referer_fil,referer_fil);
  240.             }
  241.           }
  242.         }
  243.       }
  244.     }
  245.     // sav ne sert α rien pour le moment
  246.     back[p].r.size=0;                   // rien n'a encore ΘtΘ chargΘ
  247.     back[p].r.soc=INVALID_SOCKET;       // pas de socket
  248.     back[p].r.adr=NULL;                 // pas de bloc de mΘmoire
  249.     back[p].r.is_write=0;               // α priori stockage en mΘmoire
  250.     back[p].maxfile_html=opt->maxfile_html;
  251.     back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
  252.     back[p].testmode=test;              // mode test?
  253.     if (!opt->http10)                 // option "forcer 1.0" dΘsactivΘe
  254.       back[p].http11=1;               // autoriser http/1.1
  255.     back[p].head_request=0;
  256.     if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0)    // HEAD
  257.       back[p].head_request=1;
  258.     else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0)    // test en GET
  259.       back[p].head_request=2;       // test en get
  260.  
  261.     // tester cache
  262.     if ((strcmp(adr,"file://"))           /* pas fichier */
  263.       && ( (!test) || (cache->type==1) )   /* cache prioritaire, laisser passer en test! */
  264.       && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) {  // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
  265.       //if ((!test) && (strcmp(adr,"file://")) 
  266.       //if ((!test) && (strncmp(adr,"ftp://",6)) && (strcmp(adr,"file://")) 
  267. #if HTS_FAST_CACHE
  268.       int hash_pos;
  269.       int hash_pos_return=0;
  270. #else
  271.       char* a=NULL;
  272. #endif
  273. #if HTS_FAST_CACHE
  274.       if (cache->hash) { 
  275. #else
  276.       if (cache->use) { 
  277. #endif
  278.         char buff[HTS_URLMAXSIZE*4];
  279. #if HTS_FAST_CACHE
  280.         strcpy(buff,adr); strcat(buff,fil);
  281.         hash_pos_return=inthash_read((hash_chain**)cache->hash,cache->hash_size,buff,(long int*)&hash_pos);
  282. #else
  283.         buff[0]='\0'; strcat(buff,"\n"); strcat(buff,adr); strcat(buff,"\n"); strcat(buff,fil); strcat(buff,"\n");
  284.         a=strstr(cache->use,buff);
  285. #endif
  286.         
  287.         // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
  288. #if HTS_FAST_CACHE
  289.         if (hash_pos_return) {
  290. #else
  291.         if (a) {
  292. #endif
  293.           if (!test) {      // non mode test
  294. #if HTS_FAST_CACHE
  295.             int pos=hash_pos;
  296. #else
  297.             int pos=-1;
  298.             a+=strlen(buff);
  299.             sscanf(a,"%d",&pos);    // lire position
  300. #endif
  301.             if (pos<0) {    // pas de mise en cache data, vΘrifier existence
  302.               if (fsize(antislash(save)) <= 0) {  // fichier existe pas ou est vide!
  303. #if HTS_FAST_CACHE
  304.                 hash_pos_return=0;
  305. #else
  306.                 a=NULL;    
  307. #endif
  308.                 // dΘvalider car non prΘsent sur disque dans structure originale!!!
  309.                 // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
  310.                 // en Ωtre s√r
  311.                 if (opt->norecatch) {              // tester norecatch
  312.                   if (!fexist(antislash(save))) {  // fichier existe pas mais dΘclarΘ: on l'a effacΘ
  313.                     FILE* fp=fopen(antislash(save),"wb");
  314.                     if (fp) fclose(fp);
  315.                     if (opt->log!=NULL) {
  316.                       fspc(opt->log,"warning"); fprintf(opt->log,"File must have been erased by user, ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  317.                     }
  318.                   }
  319.                 }
  320.               }
  321.             }
  322.           }
  323.         }
  324.         //
  325.       } else
  326. #if HTS_FAST_CACHE
  327.         hash_pos_return=0;
  328. #else
  329.         a=NULL;
  330. #endif
  331.  
  332.       // Existe pas en cache, ou bien pas de cache prΘsent
  333. #if HTS_FAST_CACHE
  334.       if (hash_pos_return) {  // OK existe en cache (et donnΘes aussi)!
  335. #else
  336.       if (a!=NULL) {  // OK existe en cache (et donnΘes aussi)!
  337. #endif
  338.         if (cache->type==1) {   // cache prioritaire (pas de test if-modified..)
  339.                                // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302... 
  340.           // lire dans le cache
  341.           if (!test)
  342.             back[p].r=cache_read(opt,cache,adr,fil,save);
  343.           else
  344.             back[p].r=cache_read(opt,cache,adr,fil,NULL);       // charger en tΩte uniquement du cache
  345.           if (!back[p].r.location) 
  346.             back[p].r.location=back[p].location_buffer;
  347.           else {    /* recopier */
  348.             strcpy(back[p].location_buffer,back[p].r.location);
  349.             back[p].r.location=back[p].location_buffer;
  350.           }
  351.  
  352.           /* Interdiction taille par le wizard? --> dΘtruire */
  353.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  354.             if (!back_checksize(opt,&back[p],0)) {
  355.               back[p].status=0;  // FINI
  356.               back[p].r.statuscode=-1;
  357.               if (!back[p].testmode)
  358.                 strcpy(back[p].r.msg,"Cached file skipped (too big)");
  359.               else
  360.                 strcpy(back[p].r.msg,"Test: Cached file skipped  (too big)");
  361.               return 0;
  362.             }
  363.           }
  364.  
  365.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  366.             if ((opt->debug>0) && (opt->log!=NULL)) {
  367.               if (!test) {
  368.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  369.               } else {
  370.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  371.               }
  372.             }
  373.             back[p].r.notmodified=1;    // fichier non modifiΘ
  374.             back[p].status=0;  // OK prΩt
  375.             //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  376.             return 0;
  377.           } else {  // erreur
  378.             // effacer r
  379.             bzero((char*) &(back[p].r), sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  380.             // et continuer (chercher le fichier)
  381.           }
  382.           
  383.         } else if (cache->type==2) {    // si en cache, demander de tester If-Modified-Since
  384.           htsblk* r=cache_header(opt,cache,adr,fil);
  385.  
  386.           /* Interdiction taille par le wizard? */
  387.           {
  388.             LLint save_totalsize=back[p].r.totalsize;
  389.             back[p].r.totalsize=r->totalsize;
  390.             if (!back_checksize(opt,&back[p],1)) {
  391.               r=NULL;
  392.               //
  393.               back[p].status=0;  // FINI
  394.               deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
  395.               if (!back[p].testmode)
  396.                 strcpy(back[p].r.msg,"File too big");
  397.               else
  398.                 strcpy(back[p].r.msg,"Test: File too big");
  399.               return 0;
  400.             }
  401.             back[p].r.totalsize=save_totalsize;
  402.           }
  403.           
  404.           if (r) {
  405.             if (r->statuscode==200) {     // uniquement des 200 (OK)
  406.               if (strnotempty(r->etag)) {  // ETag (RFC2616)
  407.                 if (strnotempty(r->lastmodified))
  408.                   sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r->etag,r->lastmodified);
  409.                 else
  410.                   sprintf(back[p].send_too,"If-None-Match: %s\r\n",r->etag);
  411.               }
  412.               else if (strnotempty(r->lastmodified))
  413.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r->lastmodified);
  414.               else if (strnotempty(cache->lastmodified))
  415.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  416.             } else if (strnotempty(cache->lastmodified))
  417.               sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  418.           }
  419. #if DEBUGCA
  420.           printf("..is modified test %s\n",back[p].send_too);
  421. #endif
  422.         } 
  423.         // Okay, pas trouvΘ dans le cache
  424.         // Et si le fichier existe sur disque?
  425.         // Pas dans le cache: fichier n'a pas ΘtΘ transfΘrΘ du tout, donc pas sur disque?
  426.       } else {
  427.         if (fexist(save)) {    // fichier existe? aghl!
  428.           LLint sz=fsize(save);
  429.           // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
  430.           // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
  431.           // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
  432.           // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
  433.           if ((ishtml(save) != 1) && (ishtml(back[p].url_fil)!=1)) {   // NON HTML (liens changΘs!!)
  434.             if (sz>0) {    // Fichier non vide? (question bΩte, sinon on transfert tout!)
  435.               if (strnotempty(cache->lastmodified)) {     /* pas de If-.. possible */
  436.                 /*if ( (!opt->http10) && (strnotempty(cache->lastmodified)) ) { */    /* ne pas forcer 1.0 */
  437. #if DEBUGCA
  438.                 printf("..if unmodified since %s size "LLintP"\n",cache->lastmodified,(LLint)sz);
  439. #endif
  440.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  441.                   fspc(opt->log,"debug"); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  442.                 }
  443.                 
  444.                 /* impossible - don't have etag or date
  445.                 if (strnotempty(back[p].r.etag)) {  // ETag (RFC2616)
  446.                 sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
  447.                 back[p].http11=1;    // En tΩte 1.1
  448.                 } else if (strnotempty(back[p].r.lastmodified)) {
  449.                 sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
  450.                 back[p].http11=1;    // En tΩte 1.1
  451.                 } else 
  452.                 */
  453.                 if (strlen(cache->lastmodified)) {
  454.                   sprintf(back[p].send_too,
  455.                     "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
  456.                     ,cache->lastmodified,(LLint)sz);
  457.                   back[p].http11=1;    // En tΩte 1.1
  458.                   back[p].range_req_size=sz;
  459.                 } else {
  460.                   if ((opt->debug>0) && (opt->errlog!=NULL)) {
  461.                     fspc(opt->log,"warning"); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  462.                   }
  463.                 }
  464.                 
  465.               } else { 
  466.                 if ((opt->debug>0) && (opt->errlog!=NULL)) {
  467.                   fspc(opt->errlog,"warning");
  468.                   /*
  469.                   if (opt->http10)
  470.                   fprintf(opt->errlog,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
  471.                   else
  472.                   */
  473.                   fprintf(opt->errlog,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  474.                   test_flush;
  475.                 }
  476.                 /* Sinon requΩte normale... */
  477.                 back[p].http11=0;
  478.               }
  479.             } else if (opt->norecatch) {              // tester norecatch
  480.               filenote(save,NULL);       // ne pas purger tout de mΩme
  481.               back[p].status=0;  // OK prΩt
  482.               back[p].r.statuscode=-1;  // erreur
  483.               strcpy(back[p].r.msg,"Null-size file not recaught");
  484.               return 0;
  485.             }
  486.           } else {
  487.             if ((opt->debug>0) && (opt->errlog!=NULL)) {
  488.               fspc(opt->errlog,"warning");
  489.               fprintf(opt->errlog,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  490.               test_flush;
  491.             }
  492.             /* Sinon requΩte normale... */
  493.             back[p].http11=0;
  494.           }
  495.         }
  496.       }
  497.     }
  498.  
  499.  
  500.     {
  501.       ///htsblk r;   non directement dans la structure-rΘponse!
  502.       T_SOC soc;
  503.       
  504.       // ouvrir liaison, envoyer requΦte
  505.       // ne pas traiter ou recevoir l'en tΩte immΘdiatement
  506.       bzero((char*) &(back[p].r), sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  507.       // recopier proxy
  508.       bcopy((char*) &opt->proxy,(char*) &(back[p].r.req.proxy), sizeof(opt->proxy));
  509.       // et user-agent
  510.       strcpy(back[p].r.req.user_agent,opt->user_agent);
  511.       back[p].r.req.user_agent_send=opt->user_agent_send;
  512.       // et http11
  513.       back[p].r.req.http11=back[p].http11;
  514.  
  515.       // mode ftp, court-circuit!
  516.       if (strncmp(back[p].url_adr,"ftp://",6)==0) {
  517.         if (back[p].testmode) {
  518.           if ((opt->debug>1) && (opt->errlog!=NULL)) {
  519.             fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: forbidden test with ftp link for back_add"LF);
  520.           }
  521.           return -1;    // erreur pas de test permis
  522.         }
  523.         if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
  524.           back[p].status=1000;   // connexion ftp
  525. #if USE_BEGINTHREAD
  526.           launch_ftp(&(back[p]));
  527. #else
  528.           {
  529.             char nid[32];
  530.             sprintf(nid,"htsftp%d-in_progress.lock",p);
  531.             strcpy(back[p].location_buffer,fconcat(opt->path_log,nid));
  532.           }
  533.           launch_ftp(&(back[p]),back[p].location_buffer,opt->exec);
  534. #endif
  535.           return 0;
  536.         }
  537.       }
  538.       
  539. #if HTS_XGETHOST
  540. #if HDEBUG
  541.       printf("back_solve..\n");
  542. #endif
  543.       back[p].status=101;    // tentative de rΘsolution du nom de host
  544.       soc=INVALID_SOCKET;    // pas encore ouverte
  545.       back_solve(&back[p]);  // prΘparer
  546.       if (host_wait(&back[p])) {  // prΩt, par ex fichier ou dispo dans dns
  547. #if HDEBUG
  548.       printf("ok, dns cache ready..\n");
  549. #endif
  550.         soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  551.         if (soc==INVALID_SOCKET) {
  552.           back[p].status=0;  // fini, erreur
  553.         }
  554.       }
  555. //
  556. #else
  557. //
  558. #if CNXDEBUG
  559.       printf("XFopen..\n");
  560. #endif
  561.  
  562.       if (strnotempty(back[p].send_too))    // envoyer un if-modified-since
  563. #if HTS_XCONN
  564.       soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  565. #else
  566.       soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
  567. #endif
  568.       else
  569. #if HTS_XCONN
  570.         soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
  571. #else
  572.       soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
  573. #endif
  574. #endif
  575.       if (opt->timeout>0) {    // gestion du opt->timeout
  576.         back[p].timeout=opt->timeout;
  577.         back[p].timeout_refresh=time_local();
  578.       } else {
  579.         back[p].timeout=-1;    // pas de gestion (default)
  580.       }
  581.       
  582.       if (opt->rateout>0) {    // gestion d'un taux minimum de transfert tolΘrΘ
  583.         back[p].rateout=opt->rateout;
  584.         back[p].rateout_time=time_local();
  585.       } else {
  586.         back[p].rateout=-1;    // pas de gestion (default)
  587.       }
  588.  
  589.       // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
  590.       // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
  591.       //if ((back[p].statuscode!=200) || (soc<0)) { // ERREUR HTTP/autre
  592.  
  593. #if CNXDEBUG
  594. printf("Xfopen ok, poll..\n");
  595. #endif
  596.  
  597. #if HTS_XGETHOST
  598.     if (soc!=INVALID_SOCKET)
  599.       if (back[p].status==101) {  // pas d'erreur
  600.         if (!back[p].r.is_file)
  601.           back[p].status=100;   // connexion en cours
  602.         else
  603.           back[p].status=1;     // fichier
  604.       }
  605.  
  606. #else
  607.       if (soc==INVALID_SOCKET) { // erreur socket
  608.         back[p].status=0;    // FINI
  609.         //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
  610.         back[p].r.soc=INVALID_SOCKET;
  611.       } else {
  612.         if (!back[p].r.is_file)
  613. #if HTS_XCONN
  614.           back[p].status=100;   // connexion en cours
  615. #else
  616.           back[p].status=99;    // chargement en tΩte en cours
  617. #endif
  618.         else
  619.           back[p].status=1;     // chargement fichier
  620. #if BDEBUG==1
  621.         printf("..loading header\n");
  622. #endif
  623.       }
  624. #endif
  625.       
  626.     }
  627.  
  628.  
  629.     // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
  630.     // le lien est considΘrΘ comme traitΘ
  631.     //if (back[p].soc<0)  // erreur
  632.     //  return -1;
  633.  
  634.     return 0;
  635.   } else {
  636.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  637.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: no space left in stack for back_add"LF);
  638.     }
  639.     return -1;    // plus de place
  640.   }
  641. }
  642.  
  643.  
  644.  
  645. #if HTS_XGETHOST
  646. #if USE_BEGINTHREAD
  647. // lancement multithread du robot
  648. PTHREAD_TYPE Hostlookup(void* iadr_p) {
  649.   char iadr[256];
  650.   t_dnscache* cache=_hts_cache();  // adresse du cache
  651.   t_hostent* hp;
  652.   int error_found=0;
  653.  
  654.   // recopier (aprΦs id:pass)
  655. #if DEBUGDNS 
  656.   printf("resolv in background: %s\n",jump_identification(iadr_p));
  657. #endif
  658.   strcpy(iadr,jump_identification(iadr_p));
  659.   // couper Θventuel :
  660.   {
  661.     char *a;
  662.     if ( (a=strchr(iadr,':')) )
  663.       *a='\0';
  664.   }
  665.   freet(iadr_p);
  666.  
  667.   // attendre que le cache dns soit prΩt
  668.   while(_hts_lockdns(-1));  // attendre libΘration
  669.   _hts_lockdns(1);          // locker
  670.   while(cache->n) {
  671.     if (strcmp(cache->iadr,iadr)==0) {
  672.       error_found=1;
  673.     }
  674.     cache=cache->n;    // calculer queue
  675.   }
  676.   if (strcmp(cache->iadr,iadr)==0) {
  677.     error_found=1;
  678.   }
  679.  
  680.   if (!error_found) {
  681.     // en gros copie de hts_gethostbyname sans le return
  682.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  683.     if (cache->n!=NULL) {
  684.       strcpy(cache->n->iadr,iadr);
  685.       cache->n->host_length=0;        /* pour le moment rien */
  686.       cache->n->n=NULL;
  687.       _hts_lockdns(0);          // dΘlocker
  688.       
  689.       /* resolve */
  690. #if DEBUGDNS 
  691.       printf("gethostbyname() in progress for %s\n",iadr);
  692. #endif
  693.       hp=gethostbyname(iadr);  // rΘsolution IP
  694.       
  695.       /* okay, result */
  696.       if (hp!=NULL) {
  697.         bcopy(hp->h_addr,cache->n->host_addr,hp->h_length);       // write first
  698.         cache->n->host_length=hp->h_length;                       // then write this
  699.       } else {
  700.         cache->n->host_addr[0]='\0';
  701.         cache->n->host_length=-1;             // dΘclarer erreur dans le dns
  702.       }
  703.     } else 
  704.     _hts_lockdns(0);          // dΘlocker
  705.   } else {
  706. #if DEBUGDNS 
  707.     printf("aborting resolv for %s (found)\n",iadr);
  708. #endif
  709.     _hts_lockdns(0);          // dΘlocker
  710.   }
  711.   // fin de copie de hts_gethostbyname
  712.  
  713. #if DEBUGDNS 
  714.   printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
  715. #endif
  716.  
  717.   return PTHREAD_RETURN;     /* _endthread implied  */
  718. }
  719. #endif
  720.  
  721. // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
  722. // si c'est un fichier, la rΘsolution est immΘdiate
  723. // idem pour ftp://
  724. void back_solve(lien_back* back) {
  725.   if ((strcmp(back->url_adr,"file://")) && (strncmp(back->url_adr,"ftp://",6))) {
  726.   //## if (back->url_adr[0]!=lOCAL_CHAR) {  // qq chose α prΘparer
  727.     char* a;
  728.     if (!(back->r.req.proxy.active))
  729.       a=back->url_adr;
  730.     else
  731.       a=back->r.req.proxy.name;
  732.     if (!hts_dnstest(a)) {   // non encore testΘ!..
  733.       // inscire en thread
  734. #if HTS_WIN
  735.       // Windows
  736. #if USE_BEGINTHREAD
  737.       {
  738.         char* p = calloct(strlen(a)+2,1);
  739.         if (p) {
  740.           strcpy(p,a);
  741.           _beginthread( Hostlookup , 0, p );
  742.         }
  743.       }
  744. #else
  745.       /*t_hostent* h=*/
  746.       /*hts_gethostbyname(a);*/  // calcul
  747. #endif
  748. #else
  749. #if USE_BEGINTHREAD
  750.         char* p = calloct(strlen(a)+2,1);
  751.         if (p) {
  752.           strcpy(p,a);
  753.           _beginthread( Hostlookup , 0, p );
  754.         }
  755. #else
  756.       // Sous Unix, le gethostbyname() est bloquant..
  757.       /*t_hostent* h=*/
  758.       /*hts_gethostbyname(a);*/  // calcul
  759. #endif
  760. #endif
  761.     }
  762.   }
  763. }
  764.  
  765. // dΘtermine si le host a pu Ωtre rΘsolu
  766. int host_wait(lien_back* back) {
  767.   if ((strcmp(back->url_adr,"file://")) && (strncmp(back->url_adr,"ftp://",6))) {
  768.   //## if (back->url_adr[0]!=lOCAL_CHAR) {
  769.     if (!(back->r.req.proxy.active)) {
  770.       return (hts_dnstest(back->url_adr));
  771.     } else {
  772.       return (hts_dnstest(back->r.req.proxy.name));      
  773.     }
  774.   } else return 1;    // prΩt, fichier local
  775. }
  776. #endif
  777.  
  778.  
  779.  
  780. // attente (gestion des buffers des sockets)
  781. void back_wait(lien_back* back,int back_max,httrackp* opt,cache_back* cache,double stat_timestart) {
  782.   int i;
  783.   T_SOC nfds=INVALID_SOCKET;
  784.   fd_set fds,fds_c,fds_e;     // fds pour lecture, connect (write), et erreur
  785.   struct timeval tv;
  786.   int do_wait=0;
  787.   int gestion_timeout=0;
  788.   int busy=0;    // pas de donnΘes pour le moment   
  789. #if HTS_ANALYSTE
  790.   int max_loop=8;  // nombre de boucles max α parcourir..
  791.   int max_loop_chk=0;
  792. #else
  793.   int max_loop=8;  // nombre de boucles max α parcourir..
  794. #endif
  795.  
  796.  
  797.   // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
  798.   do_wait=0;
  799.   gestion_timeout=0;
  800.   do {
  801.     int max_c;
  802.     busy=0;
  803.  
  804.     check_rate(stat_timestart,opt->maxrate);    // vΘrifier taux de transfert
  805.     // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
  806.     FD_ZERO(&fds);
  807.     FD_ZERO(&fds_c);
  808.     FD_ZERO(&fds_e);
  809.  
  810.     max_c=1;
  811.     for(i=0;i<back_max;i++) {
  812.  
  813.       // en cas de gestion du connect prΘemptif
  814. #if HTS_XCONN
  815.       if (back[i].status==100) {      // connexion
  816.         do_wait=1;
  817.  
  818.         // noter socket write
  819.         FD_SET(back[i].r.soc,&fds_c);
  820.         
  821.         // noter socket erreur
  822.         FD_SET(back[i].r.soc,&fds_e);
  823.  
  824.         // calculer max
  825.         if (max_c) {
  826.           max_c=0;
  827.           nfds=back[i].r.soc;
  828.         } else if (back[i].r.soc>nfds) {
  829.           // ID socket la plus ΘlevΘe
  830.           nfds=back[i].r.soc;
  831.         }
  832.         
  833.       } else
  834. #endif
  835. #if HTS_XGETHOST
  836.       if (back[i].status==101) {      // attente
  837.         // rien α faire..
  838.       } else
  839. #endif
  840.       // poll pour la lecture sur les sockets
  841.       if ((back[i].status>0) && (back[i].status<100)) {  // en rΘception http
  842.             
  843. #if BDEBUG==1
  844.         //printf("....socket in progress: %d\n",back[i].r.soc);
  845. #endif
  846.         // non local et non ftp
  847.         if (strncmp(back[i].url_adr,"file://",7)) {
  848.         //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
  849.           
  850.           // vΘrification de sΘcuritΘ
  851.           if ((back[i].r.soc!=INVALID_SOCKET) && (!back[i].r.is_file)) {  // hey, you never know..
  852.             do_wait=1;
  853.             
  854.             // noter socket read
  855.             FD_SET(back[i].r.soc,&fds);
  856.             
  857.             // noter socket error
  858.             FD_SET(back[i].r.soc,&fds_e);
  859.             
  860.             // calculer max
  861.             if (max_c) {
  862.               max_c=0;
  863.               nfds=back[i].r.soc;
  864.             } else if (back[i].r.soc>nfds) {
  865.               // ID socket la plus ΘlevΘe
  866.               nfds=back[i].r.soc;
  867.             }
  868.           } 
  869. #if WIDE_DEBUG
  870.           else {
  871.             DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
  872.           }
  873. #endif
  874.           
  875.         }
  876.         
  877.       }
  878.     }    
  879.     nfds++;
  880.     
  881.     if (do_wait) {  // attendre
  882.       // temps d'attente max: 2.5 seconde
  883.       tv.tv_sec=HTS_SOCK_SEC;
  884.       tv.tv_usec=HTS_SOCK_MS;
  885.       
  886. #if BDEBUG==1
  887.       printf("..select\n");
  888. #endif
  889.       
  890.       // poller les sockets-attention au noyau sous Unix..
  891. #if HTS_WIDE_DEBUG    
  892.       DEBUG_W("select\n");
  893. #endif
  894.       select(nfds,&fds,&fds_c,&fds_e,&tv);
  895. #if HTS_WIDE_DEBUG    
  896.       DEBUG_W("select done\n");
  897. #endif      
  898.     }
  899.      
  900.     // recevoir les donnΘes arrivΘes
  901.     for(i=0;i<back_max;i++) {
  902.       
  903.       if (back[i].status>0) {
  904.         if ((back[i].r.soc!=INVALID_SOCKET) && (!back[i].r.is_file)) {  // hey, you never know..
  905.           int err;
  906.           // erreur?
  907.           err=FD_ISSET(back[i].r.soc,&fds_e);        
  908.           if (err) {
  909.             if (back[i].r.soc!=INVALID_SOCKET) {
  910. #if HTS_DEBUG_CLOSESOCK
  911.               DEBUG_W("back_wait: deletehttp\n");
  912. #endif
  913.               deletehttp(&back[i].r);
  914.             }
  915.             back[i].r.soc=INVALID_SOCKET;
  916.             back[i].r.statuscode=-4;
  917.             if (back[i].status==100)
  918.               strcpy(back[i].r.msg,"Connect Error");
  919.             else
  920.               strcpy(back[i].r.msg,"Receive Error");
  921.             back[i].status=0;  // terminΘ
  922.           }
  923.         }
  924.       }
  925.  
  926.       // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
  927.       if (back[i].status==100) {   // attendre connect
  928.         int dispo=0;
  929.         // vΘrifier l'existance de timeout-check
  930.         if (!gestion_timeout)
  931.           if (back[i].timeout>0)
  932.             gestion_timeout=1;
  933.           
  934.         // connectΘ?
  935.         dispo=FD_ISSET(back[i].r.soc,&fds_c);
  936.         if (dispo) {    // ok
  937.           busy=1;
  938. #if BDEBUG==1
  939.           printf("..connect ok on socket %d\n",back[i].r.soc);
  940. #endif
  941.           /* limit nb. connections/seconds to avoid server overload */
  942.           if (opt->maxconn>0) {
  943.             Sleep(1000/opt->maxconn);
  944.           }
  945.  
  946.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  947.             back[i].timeout_refresh=time_local();
  948.           }
  949.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  950.             back[i].rateout_time=time_local();
  951.           }
  952.           // envoyer header
  953.           //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0)    // vrai get
  954.           if (!back[i].head_request)
  955.             http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  956.           else if (back[i].head_request==2)  // test en GET!
  957.             http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  958.           else        // test!
  959.             http_sendhead(opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  960.           back[i].status=99;  // attendre en tΩte maintenant
  961.         }
  962.  
  963.         // attente gethostbyname
  964.       } 
  965. #if HTS_XGETHOST
  966.       else if (back[i].status==101) {  // attendre gethostbyname
  967. #if DEBUGDNS 
  968.         //printf("status 101 for %s\n",back[i].url_adr);
  969. #endif
  970.  
  971.         if (!gestion_timeout)
  972.           if (back[i].timeout>0)
  973.             gestion_timeout=1;
  974.  
  975.         if (host_wait(&back[i])) {    // prΩt
  976.           back[i].status=100;        // attente connexion
  977.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  978.             back[i].timeout_refresh=time_local();
  979.           }
  980.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  981.             back[i].rateout_time=time_local();
  982.           }
  983.  
  984.           back[i].r.soc=http_xfopen(0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
  985.           if (back[i].r.soc==INVALID_SOCKET) {
  986.             back[i].status=0;  // fini, erreur
  987.             if (back[i].r.soc!=INVALID_SOCKET) {
  988. #if HTS_DEBUG_CLOSESOCK
  989.               DEBUG_W("back_wait(2): deletehttp\n");
  990. #endif
  991.               deletehttp(&back[i].r);
  992.             }
  993.             back[i].r.soc=INVALID_SOCKET;
  994.             back[i].r.statuscode=-5;
  995.             if (strnotempty(back[i].r.msg)==0) 
  996.               strcpy(back[i].r.msg,"Unable to establish host name");
  997.           }
  998.         }
  999.         
  1000.  
  1001.       // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
  1002.       }
  1003. #endif
  1004. #if USE_BEGINTHREAD
  1005.       // ..rien α faire, c'est magic les threads
  1006. #else
  1007.       else if (back[i].status==1000) {  // en rΘception ftp
  1008.         if (!fexist(back[i].location_buffer)) {    // terminΘ
  1009.           FILE* fp;
  1010.           fp=fopen(fconcat(back[i].location_buffer,".ok"),"rb");
  1011.           if (fp) {
  1012.             int j=0;
  1013.             fscanf(fp,"%d ",&(back[i].r.statuscode));
  1014.             while(!feof(fp)) {
  1015.               int c = fgetc(fp);
  1016.               if (c!=EOF)
  1017.                 back[i].r.msg[j++]=c;
  1018.             }
  1019.             back[i].r.msg[j++]='\0';
  1020.             fclose(fp);
  1021.             remove(fconcat(back[i].location_buffer,".ok"));
  1022.             strcpy(fconcat(back[i].location_buffer,".ok"),"");
  1023.           } else {
  1024.             strcpy(back[i].r.msg,"Unknown ftp result, check if file is ok");
  1025.             back[i].r.statuscode=-1;
  1026.           }
  1027.           back[i].status=0;
  1028.         }
  1029.       }
  1030. #endif
  1031.       else if ((back[i].status>0) && (back[i].status<1000)) {  // en rΘception http
  1032.         int dispo=0;
  1033.         
  1034.         // vΘrifier l'existance de timeout-check
  1035.         if (!gestion_timeout)
  1036.           if (back[i].timeout>0)
  1037.             gestion_timeout=1;
  1038.           
  1039.           // donnΘes dispo?
  1040.           //## if (back[i].url_adr[0]!=lOCAL_CHAR)
  1041.           if (strcmp(back[i].url_adr,"file://"))
  1042.             dispo=FD_ISSET(back[i].r.soc,&fds);
  1043.           else dispo=1;
  1044.           
  1045.           if (dispo) {    // donnΘes dispo
  1046.             LLint retour_fread;
  1047.             busy=1;    // on rΘcupΦre encore
  1048. #if BDEBUG==1
  1049.             printf("..data available on socket %d\n",back[i].r.soc);
  1050. #endif
  1051.             
  1052.  
  1053. #if HTS_SKIP_FULL_RANGE
  1054.             // range_req_size : we have request for a partial file
  1055.             // with a 'Range: NNN-'
  1056.             // and received a complete file (200), with 'Content-length: NNN'
  1057.             // it might be possible that we had the complete file
  1058.             // this is the case in *most* cases
  1059.             if (back[i].r.is_write==0) {  // mode mΘmoire
  1060.               if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1061.                 if (!back[i].testmode) {  // pas mode test
  1062.                   if (strnotempty(back[i].url_sav)) {
  1063.                     if (strcmp(back[i].url_fil,"/robots.txt")) {
  1064.                       if (back[i].r.statuscode==200) {  // 'OK'
  1065.                         if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1066.                           
  1067.                           if (back[i].r.statuscode==200) {      // "OK"
  1068.                             if (back[i].range_req_size>0) {     // but Range: requested
  1069.                               if (back[i].range_req_size == back[i].r.totalsize) {    // And same size
  1070. #if HTS_DEBUG_CLOSESOCK
  1071.                                 DEBUG_W("back_wait(skip_range): deletehttp\n");
  1072. #endif
  1073.                                 deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1074.                                 back[i].status=0;    // READY
  1075.                                 back[i].r.size=back[i].r.totalsize;
  1076.                                 filenote(back[i].url_sav,NULL);
  1077.                                 // back[i].r.statuscode=304;     // NOT MODIFIED
  1078.                                 if ((opt->debug>1) && (opt->log!=NULL)) {
  1079.                                   fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete, breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1080.                                 }
  1081.                               }
  1082.                             }
  1083.                           }
  1084.                           
  1085.                         }
  1086.                       }
  1087.                     }
  1088.                   }
  1089.                 }
  1090.               }
  1091.             }
  1092. #endif
  1093.  
  1094. #if HTS_DIRECTDISK
  1095.             // Court-circuit:
  1096.             // Peut-on stocker le fichier directement sur disque?
  1097.             // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
  1098.             if (back[i].status) {
  1099.               if (back[i].r.is_write==0) {  // mode mΘmoire
  1100.                 if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1101.                   if (!back[i].testmode) {  // pas mode test
  1102.                     if (strnotempty(back[i].url_sav)) {
  1103.                       if (strcmp(back[i].url_fil,"/robots.txt")) {
  1104.                         if (back[i].r.statuscode==200) {  // 'OK'
  1105.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1106.                             if (opt->getmode&2) {    // on peut ecrire des non html
  1107.                               back[i].r.is_write=1;    // Θcrire
  1108.                               back[i].r.out=filecreate(back[i].url_sav);
  1109. #if HDEBUG
  1110.                               printf("direct-disk: %s\n",back[i].url_sav);
  1111. #endif
  1112.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1113.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1114.                               }
  1115.                               
  1116.                               if (back[i].r.out==NULL) {
  1117.                                 back[i].r.is_write=0;    // erreur, abandonner
  1118. #if HDEBUG
  1119.                                 printf("..error!\n");
  1120. #endif
  1121.                               }
  1122. #if HTS_WIN==0
  1123.                               else chmod(back[i].url_sav,HTS_ACCESS_FILE);      
  1124. #endif          
  1125.                             } else {  // on coupe tout!
  1126.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1127.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1128.                               }
  1129.                               back[i].status=0;  // terminΘ
  1130.                               if (!back[i].testmode)
  1131.                                 back[i].r.statuscode=-10;    // EUHH CANCEL
  1132.                               else
  1133.                                 back[i].r.statuscode=-10;    // "TEST OK"
  1134.                               if (back[i].r.soc!=INVALID_SOCKET) {
  1135. #if HTS_DEBUG_CLOSESOCK
  1136.                                 DEBUG_W("back_wait(3): deletehttp\n");
  1137. #endif
  1138.                                 deletehttp(&back[i].r);
  1139.                               }
  1140.                               back[i].r.soc=INVALID_SOCKET;
  1141.                             }
  1142.                           }
  1143.                         }
  1144.                       }
  1145.                     }
  1146.                   }
  1147.                 }
  1148.               }
  1149.             }
  1150. #endif              
  1151.  
  1152.             // rΘception de donnΘes depuis socket ou fichier
  1153.             if (back[i].status) {
  1154.               if (back[i].status==99)  // recevoir caractΦre par caractΦre
  1155.                 retour_fread=http_xfread1(&(back[i].r),0);
  1156.               else if (back[i].status==98) { // recevoir longueur chunk en hexa caractΦre par caractΦre
  1157.                 // backuper pour lire dans le buffer chunk
  1158.                 htsblk r;
  1159.                 bcopy((char*) &(back[i].r), (char*) &r, sizeof(htsblk));
  1160.                 back[i].r.is_write=0;                   // mΘmoire
  1161.                 back[i].r.adr=back[i].chunk_adr;        // adresse
  1162.                 back[i].r.size=back[i].chunk_size;      // taille taille chunk
  1163.                 back[i].r.totalsize=-1;                 // total inconnu
  1164.                 back[i].r.out=NULL;
  1165.                 back[i].r.is_file=0;
  1166.                 //
  1167.                 retour_fread=http_xfread1(&(back[i].r),0);
  1168.                 // modifier et restaurer
  1169.                 back[i].chunk_adr=back[i].r.adr;        // adresse
  1170.                 back[i].chunk_size=back[i].r.size;      // taille taille chunk
  1171.                 bcopy((char*) &r, (char*) &(back[i].r), sizeof(htsblk));    // restaurer vΘritable r
  1172.               }
  1173.               else if (back[i].is_chunk) {         // attention chunk, limiter taille α lire
  1174. #if CHUNKDEBUG==1
  1175.                 printf("read %d bytes\n",(int)min(back[i].r.totalsize-back[i].r.size,TAILLE_BUFFER));
  1176. #endif
  1177.                 retour_fread=http_xfread1(&(back[i].r),(int)min(back[i].r.totalsize-back[i].r.size,TAILLE_BUFFER));
  1178.               } else
  1179.                 retour_fread=http_fread1(&(back[i].r));
  1180.             } else
  1181.               retour_fread=-1;                    // interruption ou annulation interne (peut ne pas Ωtre une erreur)
  1182.             
  1183.             // Si rΘception chunk, tester si on est pas α la fin!
  1184.             if (back[i].status==1) {
  1185.               if (back[i].is_chunk) {     // attendre prochain chunk
  1186.                 if (back[i].r.size==back[i].r.totalsize) {      // fin chunk!
  1187.                   //printf("chunk end at %d\n",back[i].r.size);
  1188.                   back[i].status=98;  // prochain chunk
  1189.                   if (back[i].chunk_adr!=NULL) { freet(back[i].chunk_adr); back[i].chunk_adr=NULL; } back[i].chunk_size=0;
  1190.                   retour_fread=0;       // pas d'erreur
  1191. #if CHUNKDEBUG==1
  1192.                   printf("waiting for next chunk header (soc %d)..\n",back[i].r.soc);
  1193. #endif
  1194.                 }
  1195.               }
  1196.             }
  1197.                           
  1198.             if (retour_fread==-1) {    // erreur rΘception
  1199.               back[i].status=0;    // terminΘ
  1200.               if (back[i].r.soc!=INVALID_SOCKET) {
  1201. #if HTS_DEBUG_CLOSESOCK
  1202.                 DEBUG_W("back_wait(4): deletehttp\n");
  1203. #endif
  1204.                 deletehttp(&back[i].r);
  1205.               }
  1206.               back[i].r.soc=INVALID_SOCKET;
  1207. #if CHUNKDEBUG==1
  1208.               if (back[i].is_chunk)
  1209.                 printf("must be the last chunk for %s (connection closed) - %d/%d\n",back[i].url_fil,back[i].r.size,back[i].r.totalsize);
  1210. #endif
  1211.               //if ((back[i].r.statuscode==-1) && (strnotempty(back[i].r.msg)==0)) {
  1212.               if ((back[i].r.statuscode<0) && (strnotempty(back[i].r.msg)==0)) {
  1213. #if HDEBUG
  1214.                 printf("error interruped: %s\n",back[i].r.adr);
  1215. #endif        
  1216.                 if (back[i].r.size>0)
  1217.                   strcat(back[i].r.msg,"Interrupted transfer");
  1218.                 else
  1219.                   strcat(back[i].r.msg,"No data (connection closed)");
  1220.                 back[i].r.statuscode=-4;
  1221.               }
  1222.  
  1223.               if (back[i].r.totalsize>0) {    // tester totalsize
  1224.               //if ((back[i].r.totalsize>0) && (back[i].status==99)) {    // tester totalsize
  1225.                 if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1226.                   if (!opt->tolerant) {
  1227.                     //#if HTS_CL_IS_FATAL
  1228.                     if (back[i].r.adr) freet(back[i].r.adr); back[i].r.adr=NULL;
  1229.                     if (back[i].r.size<back[i].r.totalsize)
  1230.                       back[i].r.statuscode=-4;        // recatch
  1231.                     sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",back[i].r.size,back[i].r.totalsize);
  1232.                   } else {
  1233.                     //#else
  1234.                     // Un warning suffira..
  1235.                     if (cache->errlog!=NULL) {
  1236.                       fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,back[i].r.size,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1237.                     }
  1238.                     //#endif
  1239.                   }
  1240.                 }
  1241.               }
  1242. #if BDEBUG==1
  1243.               printf("transfer ok\n");
  1244. #endif
  1245.             } else {    // pas d'erreur de rΘception
  1246.               if (back[i].timeout>0) {    // refresh timeout si besoin est
  1247.                 back[i].timeout_refresh=time_local();
  1248.               }
  1249.  
  1250.               // Traitement des en tΩtes chunks ou en tΩtes
  1251.               if (back[i].status==98) {        // rΘception taille chunk en hexa (  aprΦs les en tΩtes, peut ne pas
  1252.                 if (back[i].chunk_size>=2) {
  1253.                   int chunk_size=-1;
  1254.                   // Ωtre prΘsent)
  1255.                   if (back[i].chunk_adr[back[i].chunk_size-1]==10) {    // LF, fin ligne chunk
  1256.                     char chunk_data[64];
  1257.                     if (back[i].chunk_size<32) {      // pas trop gros
  1258.                       back[i].chunk_adr[ back[i].chunk_size-1]='\0';    // octet nul 
  1259.                       strcpy(chunk_data,"");    // hex number
  1260.                       strcat(chunk_data,back[i].chunk_adr);
  1261. #if CHUNKDEBUG==1
  1262.                       printf("chunk received and read: %s\n",chunk_data);
  1263. #endif
  1264.                       if (back[i].r.totalsize<0)
  1265.                         back[i].r.totalsize=0;        // initialiser α 0
  1266.                       if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
  1267.                         back[i].r.totalsize+=chunk_size;    // noter taille
  1268.                         back[i].r.adr=(char*) realloct(back[i].r.adr,(INTsys) back[i].r.totalsize + 1);
  1269.                         if (!back[i].r.adr) {
  1270.                           if (cache->errlog!=NULL) {
  1271.                             fprintf(cache->errlog,"Error: Not enough memory ("LLintP") for %s%s"LF,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1272.                           }
  1273.                         }
  1274. #if CHUNKDEBUG==1
  1275.                         printf("chunk length: %d - next total "LLintP":\n",chunk_size,back[i].r.totalsize);
  1276. #endif
  1277.                       } else                                
  1278.                         if (cache->errlog!=NULL) {
  1279.                           fprintf(cache->errlog,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  1280.                         }
  1281.                     } else {                                  
  1282.                       if (cache->errlog!=NULL) {
  1283.                         fprintf(cache->errlog,"Warning: Chunk too big ("LLintP") for %s%s"LF,back[i].chunk_size,back[i].url_adr,back[i].url_fil);
  1284.                       }
  1285.                     }
  1286.                     
  1287.                     // ok, continuer sur le body
  1288.                     
  1289.                     // si chunk non nul continuer (ou commencer)
  1290.                     if (chunk_size>0) {
  1291.                       back[i].status=1;     // continuer body    
  1292. #if CHUNKDEBUG==1
  1293.                       printf("waiting for body (chunk)\n");
  1294. #endif
  1295.                     } else {                // chunk nul, c'est la fin
  1296. #if CHUNKDEBUG==1
  1297.                       printf("chunk end, total: %d\n",back[i].r.size);
  1298. #endif
  1299.                       back[i].status=0;     // fin    
  1300.                       if (back[i].r.soc!=INVALID_SOCKET) {
  1301. #if HTS_DEBUG_CLOSESOCK
  1302.                         DEBUG_W("back_wait(5): deletehttp\n");
  1303. #endif
  1304.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1305.  
  1306.                         /* Tester totalsize en fin de chunk */
  1307.                         if ((back[i].r.totalsize>0)) {    // tester totalsize
  1308.                           if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1309. #if HTS_CL_IS_FATAL
  1310.                             if (back[i].r.adr) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1311.                             back[i].r.statuscode=-1;
  1312.                             strcpy(back[i].r.msg,"Incorrect length");
  1313. #else
  1314.                             // Un warning suffira..
  1315.                             if (cache->errlog!=NULL) {
  1316.                               fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,back[i].r.size,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1317.                             }
  1318. #endif
  1319.                           }
  1320.                         }
  1321.                         
  1322.                       
  1323.                       }
  1324.                     }
  1325.  
  1326.                     // effacer buffer (chunk en tete)
  1327.                     if (back[i].chunk_adr!=NULL) {
  1328.                       freet(back[i].chunk_adr);
  1329.                       back[i].chunk_adr=NULL;
  1330.                       back[i].chunk_size=0;
  1331.                     }
  1332.                   
  1333.                   } // chunk LF?
  1334.                 }  // taille buffer chunk>2
  1335.                 //
  1336.               } else if (back[i].status==99) {        // en tΩtes (avant le chunk si il est prΘsent)
  1337.                 //
  1338.                 if (back[i].r.size>=2) {
  1339.                   if ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) {
  1340.                     char rcvd[2048];
  1341.                     int ptr=0;
  1342.                     
  1343. #if BDEBUG==1
  1344.                     printf("..ok, header received\n");
  1345. #endif
  1346.                     
  1347.                     // ----------------------------------------
  1348.                     // traiter en-tΩte!
  1349.                     // status-line α rΘcupΘrer
  1350.                     ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  1351.                     if (strnotempty(rcvd)==0)
  1352.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1353.                     
  1354.                     // traiter status-line
  1355.                     treatfirstline(&back[i].r,rcvd);
  1356.                     
  1357. #if HDEBUG
  1358.                     printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
  1359. #endif
  1360.                     if (_DEBUG_HEAD) {
  1361.                       if (ioinfo) {
  1362.                         fprintf(ioinfo,"\r\nresponse for %s%s:\r\n",back[i].url_adr,back[i].url_fil);
  1363.                         fprintf(ioinfo,"(Buffer) Status-Code=%d\r\n",back[i].r.statuscode);
  1364.                         fflush(ioinfo);
  1365.                       }                    // en-tΩte
  1366.                     }
  1367.                       
  1368.                     // header // ** !attention! HTTP/0.9 non supportΘ
  1369.                     do {
  1370.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);          
  1371. #if HDEBUG
  1372.                       printf("(buffer)>%s\n",rcvd);      
  1373. #endif
  1374.                       if (_DEBUG_HEAD) {
  1375.                         if (ioinfo) {
  1376.                           fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);      
  1377.                           fflush(ioinfo);
  1378.                         }
  1379.                       }
  1380.  
  1381.                       if (strnotempty(rcvd))
  1382.                         treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd);  // traiter
  1383.                       
  1384.                       // parfois les serveurs buggΘs renvoient un content-range avec un 200
  1385.                       if (back[i].r.statuscode==200)  // 'OK'
  1386.                         if (strfield(rcvd,"content-range:"))  // Avec un content-range: relisez les RFC..
  1387.                           back[i].r.statuscode=206;    // FORCER A 206 !!!!!
  1388.                         
  1389.                     } while(strnotempty(rcvd));
  1390.                     // ----------------------------------------                    
  1391.                     
  1392.                     // libΘrer mΘmoire  -- aprΦs! --
  1393.                     if (back[i].r.adr!=NULL) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1394.                    
  1395.                     /* Interdiction taille par le wizard? */
  1396.                     if (back[i].r.soc!=INVALID_SOCKET) {
  1397.                       if (!back_checksize(opt,&back[i],1)) {
  1398.                         back[i].status=0;  // FINI
  1399.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1400.                         if (!back[i].testmode)
  1401.                           strcpy(back[i].r.msg,"File too big");
  1402.                         else
  1403.                           strcpy(back[i].r.msg,"Test: File too big");
  1404.                       }
  1405.                     }
  1406.  
  1407.                     /* sinon, continuer */
  1408.                     if (back[i].r.soc!=INVALID_SOCKET) {   // ok rΘcupΘrer body?
  1409.                       // head: terminΘ
  1410.                       if (back[i].head_request) {
  1411.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  1412.                           fspc(opt->log,"debug"); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1413.                         }
  1414. #if HTS_DEBUG_CLOSESOCK
  1415.                         DEBUG_W("back_wait(head request): deletehttp\n");
  1416. #endif
  1417.                         // Couper connexion
  1418.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1419.                         back[i].status=0;  // terminΘ
  1420.                       }
  1421.                       // traiter une Θventuelle erreur 304 (cache α jour utilisable)
  1422.                       else if (back[i].r.statuscode==304) {  // document α jour dans le cache
  1423.                         // lire dans le cache
  1424.                         // ** NOTE: pas de vΘrif de la taille ici!!
  1425. #if HTS_DEBUG_CLOSESOCK
  1426.                         DEBUG_W("back_wait(file is not modified): deletehttp\n");
  1427. #endif
  1428.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1429.                         back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  1430.                         if (!back[i].r.location)
  1431.                           back[i].r.location=back[i].location_buffer;
  1432.                         else {        /* recopier */
  1433.                           strcpy(back[i].location_buffer,back[i].r.location);
  1434.                           back[i].r.location=back[i].location_buffer;
  1435.                         }
  1436.                         if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
  1437.                           back[i].status=0;         // OK prΩt
  1438.                           back[i].r.notmodified=1;  // NON modifiΘ!
  1439.                           if ((opt->debug>0) && (opt->log!=NULL)) {
  1440.                             fspc(opt->log,"debug"); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1441.                           }
  1442. #if DEBUGCA
  1443.                           printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
  1444. #endif
  1445.                           
  1446.                           //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  1447.                         } else {  // erreur
  1448.                           back[i].status=0;  // terminΘ
  1449.                           //printf("erreur cache\n");
  1450.                           
  1451.                         } 
  1452.                         
  1453.                       } else if ((back[i].r.statuscode==301) || 
  1454.                         (back[i].r.statuscode==302) || 
  1455.                         (back[i].r.statuscode==412)) {   // Ne pas prendre le html, erreurs connues et gΘrΘes
  1456. #if HTS_DEBUG_CLOSESOCK
  1457.                         DEBUG_W("back_wait(301,302,412..): deletehttp\n");
  1458. #endif
  1459.                         // Couper connexion
  1460.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1461.                         back[i].status=0;  // terminΘ
  1462.                         
  1463.                       } else {    // il faut aller le chercher
  1464.                         
  1465.                         // effacer buffer (requΦte)
  1466.                         if (back[i].r.adr!=NULL) {
  1467.                           freet(back[i].r.adr);
  1468.                           back[i].r.adr=NULL;
  1469.                         }
  1470.                         back[i].r.size=0;                                 
  1471.                         
  1472.                         // traiter 206 (partial content)
  1473.                         // xxc SI CHUNK VERIFIER QUE CA MARCHE??
  1474.                         if (back[i].r.statuscode==206) {  // on nous envoie un morceau (la fin) coz une partie sur disque!
  1475.                           LLint sz=fsize(back[i].url_sav);
  1476. #if HDEBUG
  1477.                           printf("partial content: "LLintP" on disk..\n",(LLint)sz);
  1478. #endif
  1479.                           if (sz>=0) {
  1480.                             if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1481.                               if (opt->getmode&2) {    // on peut ecrire des non html  **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
  1482.                                 filenote(back[i].url_sav,NULL);    // noter fichier comme connu
  1483.                                 back[i].r.out=fopen(fconv(back[i].url_sav),"ab");  // append
  1484.                                 if (back[i].r.out) {
  1485.                                   back[i].r.is_write=1;    // Θcrire
  1486.                                   back[i].r.size=sz;    // dΘja Θcrit
  1487.                                   back[i].r.statuscode=200;  // Forcer 'OK'
  1488.                                   if (back[i].r.totalsize>0)
  1489.                                     back[i].r.totalsize+=sz;    // plus en fait
  1490.                                   fseek(back[i].r.out,0,SEEK_END);  // α la fin
  1491. #if HDEBUG
  1492.                                   printf("continue interrupted file\n");
  1493. #endif
  1494.                                 } else {    // On est dans la m**
  1495.                                   back[i].status=0;  // terminΘ (voir plus loin)
  1496.                                   strcpy(back[i].r.msg,"Can not open partial file");
  1497.                                 }
  1498.                               }
  1499.                             } else {    // mΘmoire
  1500.                               FILE* fp=fopen(fconv(back[i].url_sav),"rb");
  1501.                               if (fp) {
  1502.                                 LLint alloc_mem=sz + 1;
  1503.                                 if (back[i].r.totalsize>0)
  1504.                                   alloc_mem+=back[i].r.totalsize;            // AJOUTER RESTANT!
  1505.                                 if ( (back[i].r.adr=(char*) malloct((INTsys) alloc_mem)) ) {
  1506.                                   back[i].r.size=sz;
  1507.                                   if (back[i].r.totalsize>0)
  1508.                                     back[i].r.totalsize+=sz;    // plus en fait
  1509.                                   if (((int) fread(back[i].r.adr,1,(INTsys)sz,fp)) != sz) {
  1510.                                     back[i].status=0;  // terminΘ (voir plus loin)
  1511.                                     strcpy(back[i].r.msg,"Can not read partial file");
  1512.                                   } else {
  1513.                                     back[i].r.statuscode=200;  // Forcer 'OK'
  1514. #if HDEBUG
  1515.                                     printf("continue in mem interrupted file\n");
  1516. #endif
  1517.                                   }
  1518.                                 } else {
  1519.                                   back[i].status=0;  // terminΘ (voir plus loin)
  1520.                                   strcpy(back[i].r.msg,"No memory for partial file");
  1521.                                 }
  1522.                               } else {  // Argh.. 
  1523.                                 back[i].status=0;  // terminΘ (voir plus loin)
  1524.                                 strcpy(back[i].r.msg,"Can not open partial file");
  1525.                               }
  1526.                             }
  1527.                           } else {    // Non trouvΘ??
  1528.                             back[i].status=0;  // terminΘ (voir plus loin)
  1529.                             strcpy(back[i].r.msg,"Can not find partial file");
  1530.                           }
  1531.                           // Erreur?
  1532.                           if (back[i].status==0) {
  1533.                             if (back[i].r.soc!=INVALID_SOCKET) {
  1534. #if HTS_DEBUG_CLOSESOCK
  1535.                               DEBUG_W("back_wait(206 solve problems): deletehttp\n");
  1536. #endif
  1537.                               deletehttp(&back[i].r);
  1538.                             }
  1539.                             back[i].r.soc=INVALID_SOCKET;
  1540.                             //back[i].r.statuscode=206;  ????????
  1541.                             back[i].r.statuscode=-5;
  1542.                             if (strnotempty(back[i].r.msg))
  1543.                               strcpy(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
  1544.                           }
  1545.                         }
  1546.                         
  1547.                         if (back[i].status!=0) {  // non terminΘ (erreur)
  1548.                           if (!back[i].testmode) {    // fichier normal
  1549.  
  1550.                             if (!back[i].r.is_chunk) {    // pas de chunk
  1551.                               //if (back[i].r.http11!=2) {    // pas de chunk
  1552.                               back[i].is_chunk=0;
  1553.                               back[i].status=1;     // start body
  1554.                             } else {
  1555. #if CHUNKDEBUG==1
  1556.                               printf("chunk encoding detected %s..\n",back[i].url_fil);
  1557. #endif
  1558.                               back[i].is_chunk=1;
  1559.                               back[i].chunk_adr=NULL;
  1560.                               back[i].chunk_size=0;
  1561.                               back[i].status=98;    // start body wait chunk
  1562.                             }
  1563.                             if (back[i].rateout>0) {
  1564.                               back[i].rateout_time=time_local();  // refresh pour transfer rate
  1565.                             }
  1566. #if HDEBUG
  1567.                             printf("(buffer) start body!\n");
  1568. #endif
  1569.                           } else {     // mode test, ne pas passer en 1!!
  1570.                             back[i].status=0;    // READY
  1571. #if HTS_DEBUG_CLOSESOCK
  1572.                             DEBUG_W("back_wait(test ok): deletehttp\n");
  1573. #endif
  1574.                             deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1575.                             if (back[i].r.statuscode==200) {
  1576.                               strcpy(back[i].r.msg,"Test: OK");
  1577.                               back[i].r.statuscode=-10;    // test rΘussi
  1578.                             }
  1579.                             else {    // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
  1580.                               char tempo[1000];
  1581.                               strcpy(tempo,back[i].r.msg);
  1582.                               strcpy(back[i].r.msg,"Test: ");
  1583.                               strcat(back[i].r.msg,tempo);
  1584.                             }
  1585.                             
  1586.                           }
  1587.                         }
  1588.                         
  1589.                       } 
  1590.                       
  1591.                       
  1592.                       
  1593.                     }
  1594.                     
  1595.                   }  // si LF
  1596.                 }  // r.size>2
  1597.               }  // si == 99
  1598.                   
  1599.             } // si pas d'erreurs
  1600. #if BDEBUG==1
  1601.             printf("bytes overall: %d\n",back[i].r.size);
  1602. #endif
  1603.           }  // donnΘes dispo
  1604.           
  1605.           // en cas d'erreur cl, supprimer Θventuel fichier sur disque
  1606. #if HTS_REMOVE_BAD_FILES
  1607.           if (back[i].status<0) {
  1608.             if (!back[i].testmode) {    // pas en test
  1609.               remove(back[i].url_sav);    // Θliminer fichier (endommagΘ)
  1610.               //printf("&& %s\n",back[i].url_sav);
  1611.             }
  1612.           }
  1613. #endif
  1614.  
  1615.           /* funny log for commandline users */
  1616.           if (!opt->quiet) {  // petite animation
  1617.             if (opt->verbosedisplay) {
  1618.               if (back[i].status==0) {
  1619.                 if (back[i].r.statuscode==200)
  1620.                   printf("* %s%s ("LLintP" bytes) - OK\33[K\r",back[i].url_adr,back[i].url_fil,back[i].r.size);
  1621.                 else
  1622.                   printf("* %s%s ("LLintP" bytes) - %d\33[K\r",back[i].url_adr,back[i].url_fil,back[i].r.size,back[i].r.statuscode);
  1623.                 fflush(stdout);
  1624.               }
  1625.             }
  1626.           }
  1627.           
  1628.  
  1629.       } // status>0
  1630.     }  // for
  1631.     
  1632.     // vΘrifier timeouts
  1633.     if (gestion_timeout) {
  1634.       double act;
  1635.       act=time_local();    // temps en secondes
  1636.       for(i=0;i<back_max;i++) {
  1637.         if (back[i].status>0) {  // rΘception/connexion/..
  1638.           if (back[i].timeout>0) {
  1639.             //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
  1640.             if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
  1641.               if (back[i].r.soc!=INVALID_SOCKET) {
  1642. #if HTS_DEBUG_CLOSESOCK
  1643.                 DEBUG_W("back_wait(timeout): deletehttp\n");
  1644. #endif
  1645.                 deletehttp(&back[i].r);
  1646.               }
  1647.               back[i].r.soc=INVALID_SOCKET;
  1648.               back[i].r.statuscode=-2;
  1649.               if (back[i].status==100)
  1650.                 strcpy(back[i].r.msg,"Connect Time Out");
  1651.               else if (back[i].status==101)
  1652.                 strcpy(back[i].r.msg,"DNS Time Out");
  1653.               else
  1654.                 strcpy(back[i].r.msg,"Receive Time Out");
  1655.               back[i].status=0;  // terminΘ
  1656.             } else if ((back[i].rateout>0) && (back[i].status<99)) {
  1657.               if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) {   // checker au bout de 15s
  1658.                 if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) {  // trop lent
  1659.                   back[i].status=0;  // terminΘ
  1660.                   if (back[i].r.soc!=INVALID_SOCKET) {
  1661. #if HTS_DEBUG_CLOSESOCK
  1662.                     DEBUG_W("back_wait(rateout): deletehttp\n");
  1663. #endif
  1664.                     deletehttp(&back[i].r);
  1665.                   }
  1666.                   back[i].r.soc=INVALID_SOCKET;
  1667.                   back[i].r.statuscode=-3;
  1668.                   strcpy(back[i].r.msg,"Transfer Rate Too Low");
  1669.                 }
  1670.               }
  1671.             }
  1672.           }
  1673.         }
  1674.       }
  1675.     }
  1676.     max_loop--;
  1677. #if HTS_ANALYSTE==2
  1678.     max_loop_chk++;
  1679. #endif
  1680.   } while((busy) && (max_loop>0));
  1681. #if HTS_ANALYSTE==2
  1682.   if (!busy) {
  1683.     if (max_loop_chk>=1) {
  1684.       Sleep(10);    // un tite pause pour Θviter les lag..
  1685.     }
  1686.   }
  1687. #endif
  1688. }
  1689.  
  1690. int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
  1691.   LLint size_to_test;
  1692.   if (check_only_totalsize)
  1693.     size_to_test=eback->r.totalsize;
  1694.   else
  1695.     size_to_test=max(eback->r.totalsize,eback->r.size);
  1696.   if (size_to_test>=0) {
  1697.     
  1698.     /* Interdiction taille par le wizard? */
  1699.     if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,(eback->r.totalsize+1023)/1024)==-1) {
  1700.       return 0;     /* interdit */
  1701.     }                     
  1702.     
  1703.     /* vΘrifier taille classique (heml et non html) */
  1704.     if ((istoobig(size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
  1705.       return 0;     /* interdit */
  1706.     }
  1707.   }
  1708.   return 1;
  1709. }
  1710.  
  1711.  
  1712. // octets transfΘrΘs + add
  1713. LLint back_transfered(LLint nb,lien_back* back,int back_max) {
  1714.   int i;
  1715.   // ajouter octets en instance
  1716.   for(i=0;i<back_max;i++)
  1717.     if ((back[i].status>0) && (back[i].status<99))
  1718.       nb+=back[i].r.size;
  1719.   return nb;      
  1720. }
  1721.  
  1722. // infos backing
  1723. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  1724. void back_info(lien_back* back,int i,int j,FILE* fp) {
  1725.   if (back[i].status>=0) {
  1726.     char s[256]; 
  1727.          s[0]='\0';
  1728.     back_infostr(back,i,j,s);
  1729.     strcat(s,LF);
  1730.     fprintf(fp,"%s",s);
  1731.   }
  1732. }
  1733.  
  1734. // infos backing
  1735. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  1736. void back_infostr(lien_back* back,int i,int j,char* s) {
  1737.   if (back[i].status>=0) {
  1738.     int aff=0;
  1739.     if (j & 1) {
  1740.       if (back[i].status==100) {
  1741.         strcat(s,"CONNECT ");
  1742.       } else if (back[i].status==99) {
  1743.         strcat(s,"INFOS ");
  1744.         aff=1;
  1745.       } else if (back[i].status==98) {
  1746.         strcat(s,"INFOSC");             // infos chunk
  1747.         aff=1;
  1748.       }
  1749.       else if (back[i].status>0) {
  1750. #if HTS_ANALYSTE==2
  1751.         strcat(s,"WAIT ");
  1752. #else
  1753.         strcat(s,"RECEIVE "); 
  1754. #endif
  1755.         aff=1; 
  1756.       }
  1757.     } 
  1758.     if (j & 2) {
  1759.       if (back[i].status==0) {
  1760.         switch (back[i].r.statuscode) {
  1761.         case 200:
  1762.           strcat(s,"READY ");
  1763.           aff=1;
  1764.           break;
  1765. #if HTS_ANALYSTE==2
  1766.         default:
  1767.           strcat(s,"ERROR ");
  1768.           break;
  1769. #else
  1770.         case -1:
  1771.           strcat(s,"ERROR ");
  1772.           aff=1;
  1773.           break;
  1774.         case -2:
  1775.           strcat(s,"TIMEOUT ");
  1776.           aff=1;
  1777.           break;
  1778.         case -3:
  1779.           strcat(s,"TOOSLOW ");
  1780.           aff=1;
  1781.           break;
  1782.         case 400:
  1783.           strcat(s,"BADREQUEST ");
  1784.           aff=1;
  1785.           break;
  1786.         case 401: case 403:
  1787.           strcat(s,"FORBIDDEN ");
  1788.           aff=1;
  1789.           break;
  1790.         case 404:
  1791.           strcat(s,"NOT FOUND ");
  1792.           aff=1;
  1793.           break;
  1794.         case 500:
  1795.           strcat(s,"SERVERROR ");
  1796.           aff=1;
  1797.           break;
  1798.         default:
  1799.           {
  1800.             char s2[256];
  1801.             sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
  1802.             strcat(s,s2);
  1803.           }
  1804.           aff=1;
  1805. #endif
  1806.         }
  1807.       }
  1808.     }
  1809.     
  1810.     if (aff) {
  1811.       {
  1812.         char s2[256];
  1813.         sprintf(s2,"\"%s",back[i].url_adr); strcat(s,s2);
  1814.         
  1815.         if (back[i].url_fil[0]!='/') strcat(s,"/");
  1816.         sprintf(s2,"%s\" ",back[i].url_fil); strcat(s,s2);
  1817.         sprintf(s,LLintP" "LLintP" ",back[i].r.size,back[i].r.totalsize); strcat(s,s2);
  1818.       }
  1819.     }
  1820.   }
  1821. }
  1822.  
  1823. // -- backing --
  1824.  
  1825. #undef test_flush
  1826.