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

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche, Yann Philippot and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. This project has been developed by Xavier Roche and Yann Philippot,
  29. from the company Serianet at Caen, France (http://www.serianet.com)
  30. and other contributors (see the greetings file)
  31.  
  32. Please visit our Website: http://www.httrack.com
  33. */
  34.  
  35.  
  36. /* ------------------------------------------------------------ */
  37. /* File: Main source                                            */
  38. /* Author: Xavier Roche                                         */
  39. /* ------------------------------------------------------------ */
  40.  
  41. #include "httrack.h"
  42.  
  43. /* specific definitions */
  44. #include "htsbase.h"
  45. #include "htsnet.h"
  46. #include "htsbauth.h"
  47. #include "htsmd5.h"
  48. #include "htsindex.h"
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <time.h>
  53. #include <fcntl.h>
  54. #include <ctype.h>
  55. /* END specific definitions */
  56.  
  57.  
  58. /* HTML parsing */
  59. #if HTS_ANALYSTE==2
  60. char _hts_errmsg[1100]="";
  61. int _hts_in_html_parsing=0;
  62. int _hts_in_html_done=0;  // % done
  63. int _hts_in_html_poll=0;  // parsing
  64. int _hts_setpause=0;
  65. httrackp* _hts_setopt=NULL;
  66. char** _hts_addurl=NULL;
  67. //
  68. int _hts_cancel=0;
  69. #endif
  70.  
  71.  
  72.  
  73. char* structcheck_buff=NULL;
  74. int exit_xh;          /* quick exit (fatal error or interrupt) */
  75.  
  76. /* debug */
  77. #if DEBUG_SHOWTYPES
  78. char REG[32768]="\n";
  79. #endif
  80. #if NSDEBUG
  81. int nsocDEBUG=0;
  82. #endif
  83.  
  84. //
  85. #define _CLRSCR printf("\33[m\33[2J");
  86. #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
  87.  
  88. #if DEBUG_CHECKINT
  89.  #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
  90.  #define _CHECKINT(obj_ptr,message) \
  91.    if (obj_ptr) {\
  92.      if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
  93.        char msg[1100];\
  94.        if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
  95.          sprintf(msg,"* PANIC: Integrity error (structure crushed)  in: %s",message);\
  96.        else if ( * ((char*) (obj_ptr)) != 0)\
  97.          sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
  98.        else\
  99.          sprintf(msg,"* PANIC: Integrity error (end of structure)   in: %s",message);\
  100.        _CHECKINT_FAIL(msg);\
  101.      }\
  102.    } else {\
  103.      char msg[1100];\
  104.      sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
  105.      _CHECKINT_FAIL(msg);\
  106.    }
  107. #endif
  108.  
  109. #if DEBUG_HASH
  110.   // longest hash chain?
  111.   int longest_hash[3]={0,0,0},hashnumber=0;
  112. #endif
  113.  
  114. // demande d'interaction avec le shell
  115. #if HTS_ANALYSTE==2
  116. char HTbuff[1100];
  117. #endif
  118.  
  119.  
  120.  
  121. // DΘbut de httpmirror, routines annexes
  122.  
  123. // version 1 pour httpmirror
  124. // flusher si on doit lire peu α peu le fichier
  125. #define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); }
  126.  
  127. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  128. #define urladr   (liens[ptr]->adr)
  129. #define urlfil   (liens[ptr]->fil)
  130. #define savename (liens[ptr]->sav)
  131. //#define level    (liens[ptr]->depth)
  132. #define new_stat_bytes (HTS_STAT.HTS_TOTAL_RECV)
  133.  
  134. // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc)
  135. // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants
  136. // ne sont plus α nous.. agh! [dur celui-lα]
  137. #if HTS_ANALYSTE
  138.  #define HTMLCHECK_UNINIT hts_htmlcheck_end();
  139. #else
  140. #define HTMLCHECK_UNINIT 
  141. #endif
  142.  
  143. #define XH_extuninit { \
  144.   int i; \
  145.   HTMLCHECK_UNINIT \
  146.   if (liens!=NULL) { \
  147.   for(i=lien_max-1;i>0;i--) { \
  148.   if (liens[i]) { \
  149.   if (liens[i]->firstblock==1) { \
  150.   freet(liens[i]); \
  151.   liens[i]=NULL; \
  152.   } \
  153.   } \
  154.   } \
  155.   liens=NULL; \
  156.   } \
  157.   if (filters[0]) { \
  158.   freet(filters[0]); filters[0]=NULL; \
  159.   } \
  160.   if (back) { \
  161.   int i; \
  162.   for(i=0;i<back_max;i++) { \
  163.   back_delete(back,i); \
  164.   } \
  165.   freet(back); back=NULL;  \
  166.   } \
  167.   checkrobots_free(&robots);\
  168.   if (cache.use) { freet(cache.use); cache.use=NULL; } \
  169.   if (cache.dat) { fclose(cache.dat); cache.dat=NULL; }  \
  170.   if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
  171.   if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
  172.   if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
  173.   if (opt.log) fflush(opt.log); \
  174.   if (opt.errlog) fflush(opt.errlog);\
  175.   if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
  176.   if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
  177.   if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \
  178.   if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
  179.   if (cache_hash) { inthash_del(cache_hash,cache_hash_size); cache_hash=NULL; } \
  180. }
  181. #define XH_uninit XH_extuninit if (r.adr) { freet(r.adr); r.adr=NULL; } 
  182.  
  183. // Enregistrement d'un lien:
  184. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  185. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  186. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  187. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  188. // FA,FS: former_adr et former_fil, lien original
  189. #define HTS_ALIGN 4
  190. #if HTS_HASH
  191. #define liens_record_sav_len(A) 
  192. #else
  193. #define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav)
  194. #endif
  195.  
  196. #define liens_record(A,F,S,FA,FF) { \
  197. int notecode=0; \
  198. int adr_len=strlen(A),fil_len=strlen(F),sav_len=strlen(S),cod_len=0,former_adr_len=strlen(FA),former_fil_len=strlen(FF); \
  199. if (former_adr_len>0) {\
  200. former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \
  201. former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \
  202. } else former_adr_len=former_fil_len=0;\
  203. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  204. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; } \
  205. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \
  206. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+sizeof(lien_url))) { \
  207. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  208. lien_size=add_tab_alloc; \
  209. if (lien_buffer!=NULL) { \
  210. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=sizeof(lien_url); lien_size-=sizeof(lien_url); \
  211. liens[lien_tot]->firstblock=1; \
  212. } \
  213. } else { \
  214. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=sizeof(lien_url); lien_size-=sizeof(lien_url); \
  215. liens[lien_tot]->firstblock=0; \
  216. } \
  217. if (liens[lien_tot]!=NULL) { \
  218. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  219. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  220. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  221. liens[lien_tot]->cod=NULL; \
  222. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpy(liens[lien_tot]->cod,codebase); } \
  223. if (former_adr_len>0) {\
  224. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  225. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  226. strcpy(liens[lien_tot]->former_adr,FA); \
  227. strcpy(liens[lien_tot]->former_fil,FF); \
  228. }\
  229. strcpy(liens[lien_tot]->adr,A); \
  230. strcpy(liens[lien_tot]->fil,F); \
  231. strcpy(liens[lien_tot]->sav,S); \
  232. liens_record_sav_len(liens[lien_tot]); \
  233. hash_write(&hash,lien_tot);  \
  234. } \
  235. }
  236.  
  237. /* - abandonnΘ (simplifie) -
  238. // Ajouter α un lien EXISTANT deux champs former_adr et former_fil pour indiquer le nom d'un fichier avant un "move"
  239. // NOTE: si un alloc est fait ici il n'y aura pas de freet() α la fin, tant pis (firstbloc)
  240. #define liens_add_former(index,A,F) { \
  241. int adr_len=strlen(A),fil_len=strlen(F); \
  242. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \
  243. if ((int) lien_size < (int) (adr_len+fil_len)) { \
  244. lien_buffer=(char*) calloct(add_tab_alloc,1); \
  245. lien_size=add_tab_alloc; \
  246. } \
  247. if (lien_buffer!=NULL) { \
  248. if (liens[lien_tot]!=NULL) { \
  249. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  250. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  251. strcpy(liens[lien_tot]->former_adr,A); \
  252. strcpy(liens[lien_tot]->former_fil,F); \
  253. } \
  254. } \
  255. }
  256. */
  257.  
  258. #if 0
  259. #define HT_ADD_ADR { \
  260.   fwrite(lastsaved,1,((int) adr)- ((int) lastsaved),fp); \
  261.   lastsaved=adr; }
  262. #define HT_ADD(A) fwrite(A,1,(int) strlen(A),fp);
  263. #define HT_ADD_START
  264. #define HT_ADD_END if (fp) { fclose(fp); fp=NULL; }
  265. #define HT_ADD_FOP { \
  266.   fp=filecreate(savename); \
  267.   if (fp==NULL) { \
  268.   if (opt.errlog) { \
  269.   fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to create %s for %s%s"LF,savename,urladr,urlfil); \
  270.   test_flush; \
  271.   } \
  272.   freet(r.adr); r.adr=NULL; \
  273.   error=1; \
  274.   } \
  275.   }
  276. #else
  277. // version optimisΘe, qui permet de ne pas toucher aux html non modifiΘs (update)
  278. #define HT_ADD_CHK(A) if (((int) A+ht_len+1)>ht_size) { \
  279.   ht_size=A+ht_len+8192; \
  280.   ht_buff=(char*) realloct(ht_buff,ht_size); \
  281.   if (ht_buff==NULL) { \
  282.   printf("PANIC! : Not enough memory [%d]\n",__LINE__); \
  283.   XH_uninit; \
  284.   } \
  285.   } \
  286.   ht_len+=A;
  287. #define HT_ADD_ADR { int i,j=ht_len; HT_ADD_CHK(((int) adr)- ((int) lastsaved)) \
  288.   for(i=0;i<((int) adr)- ((int) lastsaved);i++) \
  289.   ht_buff[j+i]=lastsaved[i]; \
  290.   ht_buff[j+((int) adr)- ((int) lastsaved)]='\0'; \
  291.   lastsaved=adr; }
  292. #define HT_ADD(A) { HT_ADD_CHK(strlen(A)) strcat(ht_buff,A); }
  293. #define HT_ADD_START \
  294.   int ht_size=(int)(r.size*5)/4+8192; \
  295.   int ht_len=0; \
  296.   char* ht_buff=NULL; \
  297.   if ((opt.getmode & 1) && (ptr>0)) { \
  298.   ht_buff=(char*) malloct(ht_size); \
  299.   if (ht_buff==NULL) { \
  300.   printf("PANIC! : Not enough memory [%d]\n",__LINE__); \
  301.   XH_uninit; \
  302.   } \
  303.   ht_buff[0]='\0'; \
  304.   }
  305. #define HT_ADD_END { \
  306.   int ok=0;\
  307.   if (ht_buff) { \
  308.   int file_len=(int) strlen(ht_buff);\
  309.   char digest[32+2];\
  310.   digest[0]='\0';\
  311.   domd5mem(ht_buff,file_len,digest,1,0);\
  312.   if (fsize(antislash(savename))==file_len) { \
  313.   int mlen;\
  314.   char* mbuff;\
  315.   cache_readdata(&cache,"//[HTML-MD5]//",savename,&mbuff,&mlen);\
  316.   if (mlen) mbuff[mlen]='\0';\
  317.   if ((mlen == 32) && (strcmp(((mbuff!=NULL)?mbuff:""),digest)==0)) {\
  318.   ok=1;\
  319.   if ( (opt.debug>1) && (opt.log!=NULL) ) {\
  320.   fspc(opt.log,"debug"); fprintf(opt.log,"File not re-written (md5): %s"LF,savename);\
  321.   test_flush;\
  322.   }\
  323.   } else {\
  324.   FILE* fp2; \
  325.   int i=0; \
  326.   fp2=fopen(fconv(savename),"rb"); \
  327.   if (fp2) { \
  328.   ok=1; \
  329.   while((!feof(fp2)) && (ok)) { int c=fgetc(fp2); if (c!=EOF) { if ((char) c!=(char) ht_buff[i++]) ok=0; } } \
  330.   fclose(fp2); \
  331.   } \
  332.   } \
  333.   }\
  334.   if (!ok) { \
  335.   fp=filecreate(savename); \
  336.   if (fp) { \
  337.   if ((int)fwrite(ht_buff,1,file_len,fp) != file_len) { \
  338.   if (opt.errlog) {   \
  339.   fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to write HTML file %s"LF,savename);\
  340.   test_flush;\
  341.   }\
  342.   }\
  343.   fclose(fp); fp=NULL; \
  344.   if (strnotempty(r.lastmodified)) \
  345.   set_filetime_rfc822(savename,r.lastmodified); \
  346.   usercommand(0,NULL,antislash(savename)); \
  347.   } \
  348.   } else filenote(savename,NULL); \
  349.   if (cache.ndx)\
  350.   cache_writedata(cache.ndx,cache.dat,"//[HTML-MD5]//",savename,digest,(int)strlen(digest));\
  351.   } \
  352.   freet(ht_buff); ht_buff=NULL; \
  353.   }
  354. #define HT_ADD_FOP 
  355. #endif
  356.  
  357. // libΘrer filters[0] pour insΘrer un ΘlΘment dans filters[0]
  358. #define HT_INSERT_FILTERS0 {\
  359.   int i;\
  360.   if (filptr>0) {\
  361.     for(i=filptr-1;i>=0;i--) {\
  362.       strcpy(filters[i+1],filters[i]);\
  363.     }\
  364.   }\
  365.   strcpy(filters[0],"");\
  366.   filptr++;\
  367.   filptr=minimum(filptr,filter_max);\
  368. }
  369.  
  370. // DΘbut de httpmirror, robot
  371. // url1 peut Ωtre multiple
  372. int httpmirror(char* url1,httrackp opt) {
  373.   char* primary=NULL;          // premiΦre page, contenant les liens α scanner
  374.   int lien_tot=0;              // nombre de liens pour le moment
  375.   lien_url** liens=NULL;       // les pointeurs sur les liens
  376.   hash_struct hash;            // systΦme de hachage, accΘlΦre la recherche dans les liens
  377.   t_cookie cookie;             // gestion des cookies
  378.   int lien_max=0;
  379.   int lien_size=0;        // octets restants dans buffer liens dispo
  380.   char* lien_buffer=NULL; // buffer liens actuel
  381.   int add_tab_alloc=256000;    // +256K de liens α chaque fois
  382.   //char* tab_alloc=NULL;
  383.   int ptr;             // pointeur actuel sur les liens
  384.   //
  385.   int numero_passe=0;  // deux passes pour html puis images
  386.   int back_max=0;      // fichiers qui peuvent Ωtre en local
  387.   lien_back* back=NULL; // backing en local
  388.   htsblk r;            // retour de certaines fonctions
  389.   double lastime=0;    // pour affichage infos de tmp en tmp
  390.   // pour les stats, nombre de fichiers & octets Θcrits
  391.   LLint stat_fragment=0;  // pour la fragmentation
  392.   //double istat_timestart;   // dΘpart pour calcul instantannΘ
  393.   //
  394.   double last_info_shell=0;
  395.   int info_shell=0;
  396.   // note: α amΘliorer // **
  397.   char* filters[usd_max];
  398.   int filter_max=0;
  399.   int filptr=0;
  400.   //
  401.   int makeindex_done=0;  // lorsque l'index sera fait
  402.   FILE* makeindex_fp=NULL;
  403.   int makeindex_links=0;
  404.   char makeindex_firstlink[HTS_URLMAXSIZE*2];
  405.   // statistiques (mode #Z)
  406.   FILE* makestat_fp=NULL;    // fichier de stats taux transfert
  407.   FILE* maketrack_fp=NULL;   // idem pour le tracking
  408.   double makestat_time=0;    // attente (secondes)
  409.   LLint makestat_total=0;    // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat
  410.   int makestat_lnk=0;        // idem, pour le nombre de liens
  411.   //
  412.   char codebase[HTS_URLMAXSIZE*2];  // base pour applet java
  413.   char base[HTS_URLMAXSIZE*2];      // base pour les autres fichiers
  414.   //
  415.   cache_back cache;
  416.   robots_wizard robots;    // gestion robots.txt
  417.   hash_chain** cache_hash=NULL;
  418.   int cache_hash_size=0;
  419.   //
  420.   codebase[0]='\0'; base[0]='\0';
  421.   //
  422.   cookie.auth.next=NULL;
  423.   cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
  424.   //
  425.  
  426.   // noter heure actuelle de dΘpart en secondes
  427.   bzero((char *)&HTS_STAT, sizeof(HTS_STAT));
  428.   HTS_STAT.stat_timestart=time_local();
  429.   //istat_timestart=stat_timestart;
  430.   HTS_STAT.imstat_timestart=mtime_local();
  431.   /* reset stats */
  432.   new_stat_bytes=0;
  433.   HTS_STAT.istat_bytes=0;
  434.   if (opt.aff_progress)
  435.     lastime=HTS_STAT.stat_timestart;
  436.   if (opt.shell) {
  437.     last_info_shell=HTS_STAT.stat_timestart;
  438.   }
  439.   if ((opt.makestat) || (opt.maketrack)){
  440.     makestat_time=HTS_STAT.stat_timestart;
  441.   }
  442.  
  443.   // initialiser cookie
  444.   if (opt.accept_cookie) {
  445.     opt.cookie=&cookie;
  446.     cookie.max_len=30000;       // max len
  447.     strcpy(cookie.data,"");
  448.     // Charger cookies.txt par dΘfaut ou cookies.txt du miroir
  449.     if (fexist(fconcat(opt.path_log,"cookies.txt")))
  450.       cookie_load(opt.cookie,opt.path_log,"cookies.txt");
  451.     else if (fexist("cookies.txt"))
  452.       cookie_load(opt.cookie,"","cookies.txt");
  453.   } else
  454.     opt.cookie=NULL;
  455.  
  456.   // initialiser exit_xh
  457.   exit_xh=0;          // sortir prΘmaturΘment (var globale)
  458.  
  459.   // initialiser usercommand
  460.   usercommand(opt.sys_com_exec,opt.sys_com,"");
  461.   
  462.   // Initialiser indexation
  463.   if (opt.kindex)
  464.     index_init(opt.path_html);
  465.  
  466.   // effacer bloc cache
  467.   bzero((char *)&cache, sizeof(cache_back));
  468.   cache.type=opt.cache;  // cache?
  469.   cache.errlog=opt.errlog;  // err log?
  470.   cache.ptr_ant=cache.ptr_last=0;   // pointeur pour anticiper
  471.  
  472.   // initialiser hash cache
  473.   if (!cache_hash_size) 
  474.     cache_hash_size=HTS_HASH_SIZE;
  475.   cache_hash=(hash_chain**)calloc(cache_hash_size,sizeof(hash_chain*));
  476.   if (cache_hash==NULL) {
  477.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  478.     filters[0]=NULL; back_max=0;    // uniquement a cause du warning de XH_extuninit
  479.     XH_extuninit;
  480.     return 0;
  481.   }
  482.   inthash_init(cache_hash,cache_hash_size);
  483.   cache.hash=(void**)cache_hash;      /* copy backcache hash */
  484.   cache.hash_size=cache_hash_size;
  485.  
  486.   // initialiser cache DNS
  487.   _hts_lockdns(-999);
  488.  
  489.   // robots.txt
  490.   strcpy(robots.adr,"!");    // dummy
  491.   robots.token[0]='\0';
  492.   robots.next=NULL;          // suivant
  493.   
  494.   // effacer filters
  495.   filter_max=maximum(opt.maxfilter,128);
  496.   filters[0]=(char*) malloct((filter_max+1)*(HTS_URLMAXSIZE*2));
  497.   if (filters[0]==NULL) {
  498.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  499.     back_max=0;    // uniquement a cause du warning de XH_extuninit
  500.     XH_extuninit;
  501.     return 0;
  502.   } else {
  503.     int i;
  504.     for(i=0;i<=filter_max;i++) {    // PLUS UN (sΘcuritΘ)
  505.       filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
  506.       filters[i][0]='\0';
  507.     }
  508.   }
  509.   opt.filters.filptr=&filptr;
  510.   opt.filters.filter_max=&filter_max;
  511.   opt.filters.filters=filters;
  512.  
  513.   // tableau de pointeurs sur les liens
  514.   lien_max=maximum(opt.maxlink,32);
  515.   liens=(lien_url**) malloct(lien_max*sizeof(lien_url*));   // tableau de pointeurs sur les liens
  516.   if (liens==NULL) {
  517.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  518.     //XH_uninit;
  519.     return 0;
  520.   } else {
  521.     int i;
  522.     for(i=0;i<lien_max;i++) {
  523.       liens[i]=NULL;     
  524.     }
  525.   }
  526.   // initialiser ptr et lien_tot
  527.   ptr=0;
  528.   lien_tot=0;
  529. #if HTS_HASH
  530.   // initialiser hachage
  531.   {
  532.     int i;
  533.     for(i=0;i<HTS_HASH_SIZE;i++)
  534.       hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1;    // pas d'entrΘes
  535.     hash.liens = liens;
  536.     hash.max_lien=0;
  537.   }
  538. #endif
  539.  
  540.   
  541.   // copier adresse(s) dans liste des adresses
  542.   {
  543.     char *a=url1;
  544.     int primary_len=8192;
  545.     if (strnotempty(opt.filelist)) {
  546.       primary_len+=max(0,fsize(opt.filelist)*2);
  547.     }
  548.     primary_len+=strlen(url1)*2;
  549.  
  550.     // crΘation de la premiΦre page, qui contient les liens de base α scanner
  551.     // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile
  552.     // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires"
  553.     primary=(char*) malloct(primary_len); 
  554.     if (primary) {
  555.       primary[0]='\0';
  556.     } else {
  557.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  558.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  559.       XH_extuninit;
  560.       return 0;
  561.     }
  562.     
  563.     while(*a) {
  564.       int i;
  565.       int joker=0;
  566.  
  567.       // vΘrifier qu'il n'y a pas de * dans l'url
  568.       if (*a=='+')
  569.         joker=1;
  570.       else if (*a=='-')
  571.         joker=1;
  572.       /* NON, certaines URL ont des * (!)
  573.       else {
  574.         int i=0;
  575.         while((a[i]!=0) && (a[i]!=' ')) if (a[i++]=='*') joker=1;
  576.       }
  577.       */
  578.       
  579.       if (joker) {    // joker ou filters
  580.         //char* p;
  581.         char tempo[HTS_URLMAXSIZE*2];
  582.         int type; int plus=0;
  583.  
  584.         // noter joker (dans b)
  585.         if (*a=='+') {  // champ +
  586.           type=1; plus=1; a++;
  587.         } else if (*a=='-') {  // champ forbidden[]
  588.           type=0; a++;
  589.         } else {  // champ + avec joker sans doute
  590.           type=1;
  591.         }
  592.  
  593.         // recopier prochaine chaine (+ ou -)
  594.         i=0;
  595.         while((*a!=0) && (*a!=' ')) { tempo[i++]=*a; a++; }  
  596.         tempo[i++]='\0';
  597.         while(*a==' ') { a++; }
  598.  
  599.         // sauter les + sans rien aprΦs..
  600.         if (strnotempty(tempo)) {
  601.           if ((plus==0) && (type==1)) {  // implicite: *www.edf.fr par exemple
  602.             if (tempo[strlen(tempo)-1]!='*') {
  603.               strcat(tempo,"*");  // ajouter un *
  604.             }
  605.           }
  606.           if (type)
  607.             strcpy(filters[filptr],"+");
  608.           else
  609.             strcpy(filters[filptr],"-");
  610.           if (strncmp(tempo,"http://",7)==0)
  611.             strcat(filters[filptr],tempo+7);        // ignorer http://
  612.           else if (strncmp(tempo,"ftp://",6)==0)
  613.             strcat(filters[filptr],tempo+6);        // ignorer ftp://
  614.           else
  615.             strcat(filters[filptr],tempo);
  616.           filptr++;          
  617.         }
  618.         
  619.       } else {    // adresse normale
  620.         char url[HTS_URLMAXSIZE*2];
  621.         // prochaine adresse
  622.         i=0;
  623.         while((*a!=0) && (*a!=' ')) { url[i++]=*a; a++; }  
  624.         while(*a==' ') { a++; }
  625.         url[i++]='\0';
  626.  
  627.         strcat(primary,"<PRIMARY=\"");
  628.         if (strstr(url,":/")==NULL)
  629.           strcat(primary,"http://");
  630.         strcat(primary,url);
  631.         strcat(primary,"\">\n");
  632.       }
  633.     }  // while
  634.  
  635.     /* intΘgrer liste de fichiers */
  636.     if (strnotempty(opt.filelist)) {
  637.       FILE* fp=fopen(opt.filelist,"rb");
  638.       if (fp) {
  639.         int n=0;
  640.         char line[512];
  641.         while(!feof(fp)) {
  642.           linput(fp,line,500);
  643.           if (strnotempty(line)) {
  644.             n++;
  645.             strcat(primary,"<PRIMARY=\"");
  646.             if (strstr(line,":/")==NULL)
  647.               strcat(primary,"http://");
  648.             strcat(primary,line);
  649.             strcat(primary,"\">\n");
  650.           }
  651.         }
  652.         fclose(fp);
  653.         if (opt.log!=NULL) {
  654.           fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush;
  655.         }
  656.       } else {
  657.         if (opt.errlog!=NULL) {
  658.           fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush;
  659.         }
  660.       }
  661.     }
  662.  
  663.  
  664.     // lien primaire
  665.     liens_record("primary","/primary","primary.html","","");
  666.     if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  667.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  668.       if (opt.errlog) {
  669.         fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url));
  670.         test_flush;
  671.       }
  672.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  673.       XH_extuninit;    // dΘsallocation mΘmoire & buffers
  674.       return 0;
  675.     }    
  676.     liens[lien_tot]->testmode=0;          // pas mode test
  677.     liens[lien_tot]->link_import=0;       // pas mode import
  678.     liens[lien_tot]->depth=opt.depth+1;   // lien de prioritΘ maximale
  679.     liens[lien_tot]->pass2=0;             // 1Φre passe
  680.     liens[lien_tot]->retry=opt.retry;     // lien de prioritΘ maximale
  681.     liens[lien_tot]->premier=lien_tot;    // premier lien, objet-pΦre=objet              
  682.     liens[lien_tot]->precedent=lien_tot;  // lien prΘcΘdent
  683.     lien_tot++;  
  684.  
  685.     // Initialiser cache
  686.     cache_init(&cache,&opt);
  687.   }
  688.   
  689. #if BDEBUG==3
  690.   {
  691.     int i;
  692.     for(i=0;i<lien_tot;i++) {
  693.       printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
  694.     }
  695.     for(i=0;i<filptr;i++) {
  696.       printf("%d>filters=%s\n",i,filters[i]);
  697.     }
  698.   }
  699. #endif
  700.    
  701.   // backing
  702.   //soc_max=opt.maxsoc;
  703.   if (opt.maxsoc>0) {
  704. #if BDEBUG==2
  705.     _CLRSCR;
  706. #endif
  707.     // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe
  708.     // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les
  709.     // fichiers non html sont sauvΘs en direct sur disque.
  710.     // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment
  711.     back_max=opt.maxsoc*32+1024;
  712.     //back_max=opt.maxsoc*8+32;
  713.     back=(lien_back*) calloct((back_max+1),sizeof(lien_back));
  714.     if (back==NULL) {
  715.       if (opt.errlog)
  716.         fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(opt.maxsoc+1)*sizeof(lien_back));
  717.       return 0;
  718.     } else {    // copier buffer-location & effacer
  719.       int i;
  720.       for(i=0;i<back_max;i++){
  721.         back[i].r.location=back[i].location_buffer;
  722.         back[i].status=-1;
  723.         back[i].r.soc=INVALID_SOCKET;
  724.       }
  725.     }
  726.   }
  727.  
  728.  
  729.   // flush
  730.   test_flush;
  731.  
  732.   // statistiques
  733.   if (opt.makestat) {
  734.     makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb");
  735.     if (makestat_fp != NULL) {
  736.       fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
  737.     }
  738.   }
  739.  
  740.   // tracking -- dΘbuggage
  741.   if (opt.maketrack) {
  742.     maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb");
  743.     if (maketrack_fp != NULL) {
  744.       fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
  745.     }
  746.   }
  747.  
  748.   // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..)
  749.   if (lien_tot<=0) {
  750.     if (opt.errlog) {
  751.       fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
  752.     }
  753.   }
  754.  
  755.  
  756.   // attendre une certaine heure..
  757.   if (opt.waittime>0) {
  758.     int rollover=0;
  759.     int ok=0;
  760.     {
  761.       double tl=0;
  762.       time_t tt;
  763.       struct tm* A;
  764.       tt=time(NULL);
  765.       A=localtime(&tt);
  766.       tl+=A->tm_sec;
  767.       tl+=A->tm_min*60;
  768.       tl+=A->tm_hour*60*60;
  769.       if (tl>opt.waittime)  // attendre minuit
  770.         rollover=1;
  771.     }
  772.  
  773.     // attendre..
  774.     do {
  775.       double tl=0;
  776.       time_t tt;
  777.       struct tm* A;
  778.       tt=time(NULL);
  779.       A=localtime(&tt);
  780.       tl+=A->tm_sec;
  781.       tl+=A->tm_min*60;
  782.       tl+=A->tm_hour*60*60;
  783.  
  784.       if (rollover) {
  785.         if (tl<=opt.waittime)
  786.           rollover=0;  // attendre heure
  787.       } else {
  788.         if (tl>opt.waittime)
  789.           ok=1;  // ok!
  790.       }
  791.       
  792. #if HTS_ANALYSTE
  793.       {  
  794.         int r;
  795.         if (rollover)
  796.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,0,0,(int) (opt.waittime-tl+24*3600),-1,-1,-1,-1,-1,-1);
  797.         else
  798.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,0,0,(int) (opt.waittime-tl),-1,-1,-1,-1,-1,-1);
  799.         if (!r) {
  800.           exit_xh=1;  // exit requested
  801.           ok=1;          
  802.         } else
  803.           Sleep(100);
  804.       }
  805. #endif
  806.     } while(!ok);    
  807.     
  808.     // note: recopie de plus haut
  809.     // noter heure actuelle de dΘpart en secondes
  810.     HTS_STAT.stat_timestart=time_local();
  811.     if (opt.aff_progress)
  812.       lastime=HTS_STAT.stat_timestart;
  813.     if (opt.shell) {
  814.       last_info_shell=HTS_STAT.stat_timestart;
  815.     }
  816.     if ((opt.makestat) || (opt.maketrack)){
  817.       makestat_time=HTS_STAT.stat_timestart;
  818.     }
  819.  
  820.  
  821.   }  
  822. #if HTS_ANALYSTE
  823.   /*
  824.   if (!hts_htmlcheck_loop(back,back_max,0,0,lien_tot,0,0,0,-1,-1,-1,-1,-1)) {
  825.     XH_extuninit;
  826.     return 1;
  827.   }
  828.   Sleep(100);
  829.   */
  830.   if (!hts_htmlcheck_start()) {
  831.     XH_extuninit;
  832.     return 1;
  833.   }
  834. #endif
  835.   
  836.  
  837.   // ------------------------------------------------------------
  838.  
  839.   // ------------------------------------------------------------
  840.   // Boucle gΘnΘrale de parcours des liens
  841.   // ------------------------------------------------------------
  842.   do {
  843.     int error=0;          // si error alors sauter
  844.     int store_errpage=0;  // c'est une erreur mais on enregistre le html
  845.     char loc[HTS_URLMAXSIZE*2];    // adresse de relocation
  846.  
  847.     // Ici on charge le fichier (html, gif..) en mΘmoire
  848.     // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante)
  849.  
  850.     // effacer r
  851.     bzero((char *)&r, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  852.     r.location=loc;    // en cas d'erreur 3xx (moved)
  853.     // recopier proxy
  854.     bcopy((char*) &opt.proxy,(char*) &(r.req.proxy), sizeof(opt.proxy));
  855.     // et user-agent
  856.     strcpy(r.req.user_agent,opt.user_agent);
  857.     r.req.user_agent_send=opt.user_agent_send;
  858.  
  859.     if (!error) {
  860.       
  861.       // Skip empty/invalid/done in background
  862.       if (liens[ptr]) {
  863.         while (  (liens[ptr]) && (
  864.                     ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
  865.                     ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
  866.                     ( (liens[ptr]->pass2 == -1) )
  867.                  )
  868.                ) {  // sauter si lien annulΘ (ou fil vide)
  869.           if ((opt.debug>1) && (opt.log!=NULL)) {
  870.             fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  871.             test_flush;
  872.           }
  873.           ptr++;
  874.         }
  875.       }
  876.       if (liens[ptr]) {    // on a qq chose α rΘcupΘrer?
  877.  
  878.         if ( (opt.debug>1) && (opt.log!=NULL) ) {
  879.           fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil);
  880.           test_flush;
  881. #if DEBUG_ROBOTS
  882.           if (strcmp(urlfil,"/robots.txt") == 0) {
  883.             printf("robots.txt detected\n");
  884.           }
  885. #endif
  886.         }    
  887.         // ------------------------------------------------------------
  888.         // DEBUT --RECUPERATION LIEN---
  889.         if (ptr==0) {              // premier lien α parcourir: lien primaire construit avant
  890.           r.adr=primary; primary=NULL;
  891.           r.statuscode=200;
  892.           r.size=strlen(r.adr);
  893.           r.soc=INVALID_SOCKET;
  894.           strcpy(r.contenttype,"text/html");
  895.         /*} else if (opt.maxsoc<=0) {   // fichiers 1 α 1 en attente (pas de backing)
  896.           // charger le fichier en mΘmoire tout bΩtement
  897.           r=xhttpget(urladr,urlfil);
  898.           //
  899.         */
  900.         } else {    // backing, multiples sockets
  901.           //
  902.           int b;
  903.           int n;
  904.           
  905. #if BDEBUG==1
  906.           printf("\nBack test..\n");
  907. #endif
  908.  
  909.           if (opt.fragment>0) {
  910.             if ((HTS_STAT.stat_bytes-stat_fragment) > opt.fragment) {
  911.               while (back_nsoc(back,back_max)>0) {                  // attendre fin des transferts
  912.                 back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
  913.                 Sleep(100);
  914.               }
  915.               // On dΘsalloue le buffer d'enregistrement des chemins crΘΘe, au cas o∙ pendant la pause
  916.               // l'utilisateur ferait un rm -r aprΦs avoir effectuΘ un tar
  917.               if (structcheck_buff) {
  918.                 freet(structcheck_buff);
  919.                 structcheck_buff=NULL;
  920.               }
  921.               {
  922.                 FILE* fp = fopen(fconcat(opt.path_log,"hts-paused.lock"),"wb");
  923.                 if (fp) {
  924.                   fspc(fp,"info");  // dater
  925.                   fprintf(fp,"Pause\nHTTrack is paused after retreiving "LLintP" bytes\nDelete this file to continue the mirror...\n\n",HTS_STAT.stat_bytes);
  926.                   fclose(fp);
  927.                 }
  928.               }
  929.               stat_fragment=HTS_STAT.stat_bytes;
  930.               while (fexist(fconcat(opt.path_log,"hts-paused.lock"))) {
  931.                 //back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);   inutile!! (plus de sockets actives)
  932.                 Sleep(1000);
  933.               }
  934.             }
  935.           }
  936.  
  937. #if HTS_ANALYSTE==2
  938.           // changement dans les prΘfΘrences
  939.           if (_hts_setopt) {
  940.             copy_htsopt(_hts_setopt,&opt);    // copier au besoin
  941.             _hts_setopt=NULL;                 // effacer callback
  942.           }
  943.           if (_hts_addurl) {
  944.             char add_adr[HTS_URLMAXSIZE*2];
  945.             char add_fil[HTS_URLMAXSIZE*2];
  946.             while(*_hts_addurl) {
  947.               char add_url[HTS_URLMAXSIZE*2];
  948.               add_adr[0]=add_fil[0]=add_url[0]='\0';
  949.               if (strstr(*_hts_addurl,"://")==NULL)
  950.                 strcpy(add_url,"http://");          // ajouter http://
  951.               strcat(add_url,*_hts_addurl);
  952.               if (ident_url(add_url,add_adr,add_fil)>=0) {
  953.                 // ----Ajout----
  954.                 // noter NOUVEAU lien
  955.                 char add_sav[HTS_URLMAXSIZE*2];
  956.                 // calculer lien et Θventuellement modifier addresse/fichier
  957.                 if (url_savename(add_adr,add_fil,add_sav,NULL,NULL,NULL,NULL,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe)!=-1) { 
  958.                   if (hash_read(&hash,add_sav,"",0)<0) {      // n'existe pas dΘja
  959.                     // enregistrer lien (MACRO)
  960.                     liens_record(add_adr,add_fil,add_sav,"","");
  961.                     if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  962.                       liens[lien_tot]->testmode=0;          // mode test?
  963.                       liens[lien_tot]->link_import=0;       // mode normal
  964.                       liens[lien_tot]->depth=opt.depth;
  965.                       liens[lien_tot]->pass2=max(0,numero_passe);
  966.                       liens[lien_tot]->retry=opt.retry;
  967.                       liens[lien_tot]->premier=lien_tot;
  968.                       liens[lien_tot]->precedent=lien_tot;
  969.                       lien_tot++;
  970.                       //
  971.                       if ((opt.debug>0) && (opt.log!=NULL)) {
  972.                         fspc(opt.log,"info"); fprintf(opt.log,"Link added by user: %s%s"LF,add_adr,add_fil); test_flush;
  973.                       }
  974.                       //
  975.                     } else {  // oups erreur, plus de mΘmoire!!
  976.                       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  977.                       if (opt.errlog) {
  978.                         fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url));
  979.                         test_flush;
  980.                       }
  981.                       //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  982.                       XH_uninit;    // dΘsallocation mΘmoire & buffers
  983.                       return 0;
  984.                     }
  985.                   } else {
  986.                     if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  987.                       fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Existing link %s not added after user request"LF,add_adr,add_fil);
  988.                       test_flush;
  989.                     }
  990.                   }
  991.                   
  992.                 }
  993.               } else {
  994.                 if (opt.errlog) {
  995.                   fspc(opt.errlog,"error");
  996.                   fprintf(opt.errlog,"Error during URL decoding for %s%s"LF,add_url);
  997.                   test_flush;
  998.                 }
  999.               }
  1000.               // ----Fin Ajout----
  1001.               _hts_addurl++;                  // suivante
  1002.             }
  1003.             _hts_addurl=NULL;           // libΘrer _hts_addurl
  1004.           }
  1005.           // si une pause a ΘtΘ demandΘe
  1006.           if (_hts_setpause) {
  1007.             // index du lien actuel
  1008.             int b=back_index(back,back_max,urladr,urlfil,savename);
  1009.             if (b<0) b=0;    // forcer pour les stats
  1010.             while(_hts_setpause) {    // on fait la pause..
  1011.               LLint nb;
  1012.               int nbk;
  1013.               back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
  1014.               nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  1015.               nbk=backlinks_done(liens,lien_tot,ptr);
  1016.               engine_stats();
  1017.               if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,nb,new_stat_bytes,(int) (time_local()-HTS_STAT.stat_timestart),back_nsoc(back,back_max),HTS_STAT.stat_files,HTS_STAT.stat_updated_files,fspc(NULL,"error"),(int)HTS_STAT.rate,nbk )) {
  1018.                 if (opt.errlog) {
  1019.                   fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
  1020.                   test_flush;
  1021.                 }
  1022.                 exit_xh=1;  // exit requested
  1023.                 XH_uninit;
  1024.                 return 0;
  1025.               }
  1026.               if (back_nsoc(back,back_max)==0)
  1027.                 Sleep(250);  // tite pause
  1028.             }
  1029.           }
  1030. #endif
  1031.           
  1032.           // si le fichier n'est pas en backing, le mettre..
  1033.           if (!back_exist(back,back_max,urladr,urlfil,savename)) {
  1034. #if BDEBUG==1
  1035.             printf("crash backing: %s%s\n",liens[ptr]->adr,liens[ptr]->fil);
  1036. #endif
  1037.             if (back_add(back,back_max,&opt,&cache,urladr,urlfil,savename,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil,liens[ptr]->testmode,&liens[ptr]->pass2)==-1) {
  1038.               printf("PANIC! : Crash adding error, unexpected error found.. [%d]\n",__LINE__);
  1039. #if BDEBUG==1
  1040.               printf("error while crash adding\n");
  1041. #endif
  1042.               if (opt.errlog) {
  1043.                 fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unexpected backing error for %s%s"LF,urladr,urlfil);
  1044.                 test_flush;
  1045.               } 
  1046.               
  1047.             }
  1048.           }
  1049.           
  1050. #if BDEBUG==1
  1051.           printf("test number of socks\n");
  1052. #endif
  1053.           
  1054.           // ajouter autant de socket qu'on peut ajouter
  1055.           n=opt.maxsoc-back_nsoc(back,back_max);
  1056. #if BDEBUG==1
  1057.           printf("%d sockets available for backing\n",n);
  1058. #endif
  1059.  
  1060. #if HTS_ANALYSTE==2
  1061.           if ((n>0) && (!_hts_setpause)) {   // si sockets libre et pas en pause, ajouter
  1062. #else
  1063.           if (n>0) {                         // si sockets libre
  1064. #endif
  1065.             // remplir autant que l'on peut le cache (backing)
  1066.             back_fillmax(back,back_max,&opt,&cache,liens,ptr,numero_passe,lien_tot);
  1067.           }
  1068.           
  1069.           // index du lien actuel
  1070. /*
  1071.           b=back_index(back,back_max,urladr,urlfil,savename);
  1072.           
  1073.           if (b>=0) 
  1074. */
  1075.           {
  1076.             // ------------------------------------------------------------
  1077.             // attendre que le fichier actuel soit prΩt - BOUCLE D'ATTENTE
  1078.             do {
  1079.  
  1080.               // index du lien actuel
  1081.               b=back_index(back,back_max,urladr,urlfil,savename);
  1082. #if BDEBUG==1
  1083.               printf("back index %d, waiting\n",b);
  1084. #endif
  1085.               // Continue to the loop if link still present
  1086.               if (b<0)
  1087.                 continue;
  1088.               
  1089.               // Receive data
  1090.               if (back[b].status>0)
  1091.                 back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
  1092.               
  1093.               // Continue to the loop if link still present
  1094.               b=back_index(back,back_max,urladr,urlfil,savename);
  1095.               if (b<0)
  1096.                 continue;
  1097.               
  1098.               // And fill the backing stack
  1099.               if (back[b].status>0)
  1100.                 back_fillmax(back,back_max,&opt,&cache,liens,ptr,numero_passe,lien_tot);
  1101.               
  1102.               // Continue to the loop if link still present
  1103.               b=back_index(back,back_max,urladr,urlfil,savename);
  1104.               if (b<0)
  1105.                 continue;
  1106.  
  1107.               // autres occupations de HTTrack: statistiques, boucle d'attente, etc.
  1108.               if ((opt.makestat) || (opt.maketrack)) {
  1109.                 double l=time_local();
  1110.                 if ((int) (l-makestat_time) >= 60) {   
  1111.                   if (makestat_fp != NULL) {
  1112.                     fspc(makestat_fp,"info");
  1113.                     fprintf(makestat_fp,"Rate= %d (/"LLintP") \11NewLinks= %d (/%d)"LF,(int) ((new_stat_bytes-makestat_total)/(l-makestat_time)), new_stat_bytes,(int) lien_tot-makestat_lnk,(int) lien_tot);
  1114.                     fflush(makestat_fp);
  1115.                     makestat_total=new_stat_bytes;
  1116.                     makestat_lnk=lien_tot;
  1117.                   }
  1118.                   if (maketrack_fp!=NULL) {
  1119.                     int i;
  1120.                     fspc(maketrack_fp,"info"); fprintf(maketrack_fp,LF);
  1121.                     for(i=0;i<back_max;i++) {
  1122.                       back_info(back,i,3,maketrack_fp);
  1123.                     }
  1124.                     fprintf(maketrack_fp,LF);
  1125.                     
  1126.                   }
  1127.                   makestat_time=l;
  1128.                 }
  1129.               }
  1130. #if HTS_ANALYSTE==2
  1131.               {
  1132.                 LLint nb;
  1133.                 int nbk;
  1134.                 int i;
  1135.                 {
  1136.                   char* s=hts_cancel_file("");
  1137.                   if (strnotempty(s)) {    // fichier α canceller
  1138.                     for(i=0;i<back_max;i++) {
  1139.                       if ((back[i].status>0)) {
  1140.                         if (strcmp(back[i].url_sav,s)==0) {  // ok trouvΘ
  1141.                           if (back[i].status != 1000) {
  1142. #if HTS_DEBUG_CLOSESOCK
  1143.                             DEBUG_W("user cancel: deletehttp\n");
  1144. #endif
  1145.                             if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  1146.                             back[i].r.soc=INVALID_SOCKET;
  1147.                             back[i].r.statuscode=-1;
  1148.                             strcpy(back[i].r.msg,"Cancelled by User");
  1149.                             back[i].status=0;  // terminΘ
  1150.                           } else    // cancel ftp.. flag α 1
  1151.                             back[i].stop_ftp = 1;
  1152.                         }
  1153.                       }
  1154.                     }
  1155.                     s[0]='\0';
  1156.                   }
  1157.                 }
  1158.                 
  1159.                 engine_stats();
  1160.                 nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
  1161.                 nbk=backlinks_done(liens,lien_tot,ptr);
  1162.                 if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,nb,new_stat_bytes,(int) (time_local()-HTS_STAT.stat_timestart),back_nsoc(back,back_max),HTS_STAT.stat_files,HTS_STAT.stat_updated_files,fspc(NULL,"error"),(int)HTS_STAT.rate,nbk )) {
  1163.                   if (opt.errlog) {
  1164.                     fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
  1165.                     test_flush;
  1166.                   } 
  1167.                   exit_xh=1;  // exit requested
  1168.                   XH_uninit;
  1169.                   return 0;
  1170.                 }
  1171.               }
  1172.               
  1173. #endif
  1174. #if HTS_POLL      
  1175.               if ((opt.shell) || (opt.keyboard)) {
  1176.                 int rcvd=0;
  1177.                 double tl;
  1178.                 info_shell=1;
  1179.                 // Traitement Θventuel des requΦtes stdin etc.
  1180.                 while (check_stdin()) {  // donnΘes disponibles
  1181.                   char com[256];
  1182.                   com[0]='\0';
  1183.                   
  1184.                   if (!rcvd) rcvd=1;
  1185.                   linput(stdin,com,256);
  1186.  
  1187.                   if (strnotempty(com)) {
  1188.                     if (strlen(com)<=2) {
  1189.                       switch(*com) {
  1190.                       case '?': {    // Status?
  1191.                         if (back[b].status>0) printf("WAIT\n"); 
  1192.                         else printf("READY\n");
  1193.                                 }
  1194.                         break;
  1195.                       case 'f': {    // Fichier en attente?
  1196.                         if (back[b].status>0) printf("WAIT %s\n",back[b].url_fil); 
  1197.                         else printf("READY %s\n",back[b].url_fil);
  1198.                                 }
  1199.                         break;
  1200.                       case 'A': case 'F': {    // filters
  1201.                         int i;
  1202.                         for(i=0;i<filptr;i++) {
  1203.                           printf("%s ",filters[i]);
  1204.                         }
  1205.                         printf("\n");
  1206.                                 }
  1207.                         break;
  1208.                       case '#': {    // Afficher statistique sur le nombre de liens, etc
  1209.                         switch(*(com+1)) {
  1210.                         case 'l': printf("%d\n",lien_tot); break;  // nombre de liens enregistrΘs
  1211.                         case 's': printf("%d\n",back_nsoc(back,back_max)); break;  // nombre de sockets
  1212.                         case 'r': printf("%d\n",(int) (new_stat_bytes/(time_local()-HTS_STAT.stat_timestart))); break;  // taux de transfert
  1213.                         }
  1214.                                 }
  1215.                         break;
  1216.                       case 'K': if (*(com+1)=='!') {  // Kill
  1217.                         XH_uninit;
  1218.                         return -1;
  1219.                                 }
  1220.                         break;
  1221.                       case 'X': if (*(com+1)=='!') {  // exit
  1222.                         exit_xh=1;
  1223.                                 }
  1224.                         break;
  1225.                       case 'I': if (*(com+1)=='+') info_shell=1; else info_shell=0;
  1226.                         break;
  1227.                       }
  1228.                       io_flush;
  1229.                     } else if (*com=='@') {
  1230.                       printf("%s\n",com+1);
  1231.                       io_flush;
  1232.                     }
  1233.                   } 
  1234.                   
  1235.                 }  // while
  1236.                 tl=time_local();
  1237.                 
  1238.                 // gΘnΘrer un message d'infos sur l'Θtat actuel
  1239.                 if (opt.shell) {    // si shell
  1240.                   if ((tl-last_info_shell)>0) {    // toute les 1 sec
  1241.                     FILE* fp=stdout;
  1242.                     int a=0;
  1243.                     last_info_shell=tl;
  1244.                     if (fexist(fconcat(opt.path_log,"hts-autopsy"))) {  // dΘbuggage: teste si le robot est vivant
  1245.                       // (oui je sais un robot vivant.. mais bon.. il a le droit de vivre lui aussi)
  1246.                       // (libΘrons les robots esclaves de l'internet!)
  1247.                       remove(fconcat(opt.path_log,"hts-autopsy"));
  1248.                       fp=fopen(fconcat(opt.path_log,"hts-isalive"),"wb");
  1249.                       a=1;
  1250.                     }
  1251.                     if ((info_shell) || a) {
  1252.                       int i,j;
  1253.                       
  1254.                       fprintf(fp,"TIME %d"LF,(int) (tl-HTS_STAT.stat_timestart));
  1255.                       fprintf(fp,"TOTAL %d"LF,(int) HTS_STAT.stat_bytes);
  1256.                       fprintf(fp,"RATE %d"LF,(int) (new_stat_bytes/(tl-HTS_STAT.stat_timestart)));
  1257.                       fprintf(fp,"SOCKET %d"LF,back_nsoc(back,back_max));
  1258.                       fprintf(fp,"LINK %d"LF,lien_tot);
  1259.                       {
  1260.                         LLint mem=0;
  1261.                         for(i=0;i<back_max;i++)
  1262.                           if (back[i].r.adr!=NULL)
  1263.                             mem+=back[i].r.size;
  1264.                           fprintf(fp,"INMEM "LLintP""LF,mem);
  1265.                       }
  1266.                       for(j=0;j<2;j++) {  // passes pour ready et wait
  1267.                         for(i=0;i<back_max;i++) {
  1268.                           back_info(back,i,j+1,stdout);    // maketrack_fp a la place de stdout ?? // **
  1269.                         }
  1270.                       }
  1271.                       fprintf(fp,LF);
  1272.                       if (a)
  1273.                         fclose(fp);
  1274.                       io_flush;
  1275.                     }
  1276.                   }
  1277.                 }  // si shell
  1278.                 
  1279.               }  // si shell ou keyboard (option)
  1280.               //
  1281. #endif
  1282.             } while((b>=0) && (back[max(b,0)].status>0));
  1283.  
  1284.  
  1285.             // If link not found on the stack, it's because it has already been downloaded
  1286.             // in background
  1287.             // Then, skip it and go to the next one
  1288.             if (b<0) {
  1289.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1290.                 fspc(opt.log,"debug"); fprintf(opt.log,"link #%d is ready, no more on the stack, skipping: %s%s.."LF,ptr,urladr,urlfil);
  1291.                 test_flush;
  1292.               }
  1293.  
  1294.               // prochain lien
  1295.               ptr++;
  1296.  
  1297.               // Jump to 'continue'
  1298.               // This is one of the very very rare cases where goto
  1299.               // is acceptable
  1300.               // A supplemental flag and if() { } would be really messy
  1301.               goto jump_if_done;
  1302.             }
  1303.             
  1304.  
  1305. #if HTS_ANALYSTE
  1306. #else
  1307.             if (!opt.quiet) {  // petite animation
  1308.               if (!opt.verbosedisplay) {
  1309.                 static int roll=0;
  1310.                 roll=(roll+1)%4;
  1311.                 printf("%c\x0d",("/-\\|")[roll]);
  1312.                 fflush(stdout);
  1313.               } else {
  1314.                 if (back[b].r.statuscode==200)
  1315.                   printf("%d/%d: %s%s ("LLintP" bytes) - OK\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,back[b].r.size);
  1316.                 else
  1317.                   printf("%d/%d: %s%s ("LLintP" bytes) - %d\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,back[b].r.size,back[b].r.statuscode);
  1318.                 fflush(stdout);
  1319.               }
  1320.             }
  1321. #endif
  1322.             // ------------------------------------------------------------
  1323.             // VΘrificateur d'intΘgritΘ
  1324. #if DEBUG_CHECKINT
  1325.             _CHECKINT(&back[b],"Retour de back_wait, aprΦs le while")
  1326.             {
  1327.               int i;
  1328.               for(i=0;i<back_max;i++) {
  1329.                 char si[256];
  1330.                 sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1331.                 _CHECKINT(&back[i],si)
  1332.               }
  1333.             }
  1334. #endif
  1335.             
  1336.             // copier structure rΘponse htsblk
  1337.             bcopy((char*) &(back[b].r), (char*) &r, sizeof(htsblk));
  1338.             r.location=loc;    // ne PAS copier location!! adresse, pas de buffer
  1339.             if (back[b].r.location) 
  1340.               strcpy(r.location,back[b].r.location);
  1341.             back[b].r.adr=NULL;    // ne pas faire de desalloc ensuite
  1342.  
  1343.             // libΘrer emplacement backing
  1344.             back_delete(back,b);
  1345.             
  1346.             // progression
  1347.             if (opt.aff_progress) {
  1348.               double tl=time_local();
  1349.               if ((tl-lastime)>0) {
  1350.                 char s[32];
  1351.                 int i=0;
  1352.                 lastime=tl;
  1353.                 _CLRSCR; _GOTOXY("1","1");
  1354.                 printf("Rate=%d B/sec\n",(int) (new_stat_bytes/(tl-HTS_STAT.stat_timestart)));
  1355.                 while(i<minimum(back_max,99)) {  // **
  1356.                   if (back[i].status>=0) {  // loading..
  1357.                     s[0]='\0';
  1358.                     if (strlen(back[i].url_fil)>16)
  1359.                       strcat(s,back[i].url_fil+strlen(back[i].url_fil)-16);       
  1360.                     else
  1361.                       strncat(s,back[i].url_fil,16);
  1362.                     printf("%s : ",s);
  1363.                     
  1364.                     printf("[");
  1365.                     if (back[i].r.totalsize>0) {
  1366.                       int p;
  1367.                       int j;
  1368.                       p=(int)((back[i].r.size*10)/back[i].r.totalsize);
  1369.                       p=minimum(10,p);
  1370.                       for(j=0;j<p;j++) printf("*");
  1371.                       for(j=0;j<(10-p);j++) printf("-");
  1372.                     } else { 
  1373.                       printf(LLintP,back[i].r.size);                      
  1374.                     }
  1375.                     printf("]");
  1376.                     
  1377.                     //} else if (back[i].status==0) {
  1378.                     //  strcpy(s,"ENDED");
  1379.                   } 
  1380.                   printf("\n");
  1381.                   i++;
  1382.                 }
  1383.                 io_flush;
  1384.               }
  1385.             }
  1386.             
  1387.             // dΘbug graphique
  1388. #if BDEBUG==2
  1389.             {
  1390.               char s[12];
  1391.               int i=0;
  1392.               _GOTOXY(1,1);
  1393.               printf("Rate=%d B/sec\n",(int) (new_stat_bytes/(time_local()-HTS_STAT.stat_timestart)));
  1394.               while(i<minimum(back_max,160)) {
  1395.                 if (back[i].status>0) {
  1396.                   sprintf(s,"%d",back[i].r.size);
  1397.                 } else if (back[i].status==0) {
  1398.                   strcpy(s,"ENDED");
  1399.                 } else 
  1400.                   strcpy(s,"   -   ");
  1401.                 while(strlen(s)<8) strcat(s," ");
  1402.                 printf("%s",s); io_flush;
  1403.                 i++;
  1404.               }
  1405.             }
  1406. #endif
  1407.             
  1408.             
  1409. #if BDEBUG==1
  1410.             printf("statuscode=%d with %s / msg=%s\n",r.statuscode,r.contenttype,r.msg);
  1411. #endif
  1412.             
  1413.           }
  1414.           /*else {
  1415. #if BDEBUG==1
  1416.             printf("back index error\n");
  1417. #endif
  1418.           }
  1419.           */
  1420.           
  1421.         }
  1422.         // FIN --RECUPERATION LIEN--- 
  1423.         // ------------------------------------------------------------
  1424.  
  1425.  
  1426.  
  1427.       } else {    // lien vide..
  1428.         if (opt.errlog) {
  1429.           fprintf(opt.errlog,"Error Link empty"LF); test_flush;
  1430.           error=1;
  1431.         }         
  1432.       }  // test si url existe (non vide!)
  1433.       
  1434.  
  1435.  
  1436.       // ---tester taille a posteriori---
  1437.       // tester r.adr
  1438.       if (!error) {
  1439.         // erreur, pas de fichier chargΘ:
  1440.         if ((!r.adr) && (r.is_write==0) 
  1441.           && (r.statuscode!=301) 
  1442.           && (r.statuscode!=302) 
  1443.           && (r.statuscode!=303) 
  1444.           && (r.statuscode!=307) 
  1445.           && (r.statuscode!=412)
  1446.           && (r.statuscode!=416)
  1447.          ) { 
  1448.           error=1;
  1449.           
  1450.           // peut Ωtre que le fichier Θtait trop gros?
  1451.           if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))
  1452.            || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) {
  1453.             error=0;
  1454.             if (opt.errlog) {
  1455.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
  1456.               test_flush;
  1457.             }
  1458.           }
  1459.           error=1;    // ne pas traiter la suite -- euhh si finalement..
  1460.         }
  1461.       }
  1462.       // ---fin tester taille a posteriori---    
  1463.  
  1464.  
  1465.  
  1466.       // ---stockage en cache---
  1467.       // stocker dans le cache?
  1468.       if (!error) {
  1469.         if (ptr>0) {
  1470.           if (liens[ptr]) {
  1471.             cache_mayadd(&opt,&cache,&r,urladr,urlfil,savename);
  1472. #if 0        
  1473.             if (opt.cache) {
  1474.               if (cache.dat!=NULL) {
  1475.                 // c'est le seul endroit ou l'on ajoute des elements dans le cache (fichier entier ou header)
  1476.                 // on stocke tout fichier "ok", mais Θgalement les rΘponses 404,301,302...
  1477.                 if ((r.statuscode==200)         /* stocker rΘponse standard, plus */
  1478.                   || (r.statuscode==204)     /* no content */
  1479.                   || (r.statuscode==301)     /* moved perm */
  1480.                   || (r.statuscode==302)     /* moved temp */
  1481.                   || (r.statuscode==303)     /* moved temp */
  1482.                   || (r.statuscode==307)     /* moved temp */
  1483.                   || (r.statuscode==401)     /* authorization */
  1484.                   || (r.statuscode==403)     /* unauthorized */
  1485.                   || (r.statuscode==404)     /* not found */
  1486.                   || (r.statuscode==410)     /* gone */
  1487.                   )
  1488.                 {        /* ne pas stocker si la page gΘnΘrΘe est une erreur */
  1489.                   if (!r.is_file) {
  1490.                     // stocker fichiers (et robots.txt)
  1491.                     if ( (strnotempty(savename)) || (strcmp(urlfil,"/robots.txt")==0)) {
  1492.                       // ajouter le fichier au cache
  1493.                       cache_add(r,urladr,urlfil,savename,cache.ndx,cache.dat,opt.all_in_cache);
  1494.                     }
  1495.                   }
  1496.                 }
  1497.               }
  1498.             }
  1499. #endif
  1500.           } else
  1501.             error=1;
  1502.         }
  1503.       }
  1504.       // ---fin stockage en cache---
  1505.       
  1506.  
  1507.  
  1508.       // DEBUT rattrapage des 301,302,307..
  1509.       // ------------------------------------------------------------
  1510.       if (!error) {
  1511.       ////////{
  1512.         // on a chargΘ un fichier en plus
  1513.         // if (!error) stat_loaded+=r.size;
  1514.         
  1515.         // ------------------------------------------------------------
  1516.         // Rattrapage des 301,302,307 (moved) et 412,416 - les 304 le sont dans le backing 
  1517.         // ------------------------------------------------------------
  1518.         if ( (r.statuscode==301) 
  1519.           || (r.statuscode==302)
  1520.           || (r.statuscode==303)
  1521.           || (r.statuscode==307)
  1522.           ) {          
  1523.           //if (r.adr!=NULL) {   // adr==null si fichier direct. [catch: davename normalement si cgi]
  1524.             //int i=0;
  1525.             char *rn=NULL;
  1526.             char* p;
  1527.             
  1528.             if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  1529.             //if (opt.errlog) {
  1530.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"%s for %s%s"LF,r.msg,urladr,urlfil);
  1531.               test_flush;
  1532.             }
  1533.             
  1534.             
  1535. #if 0
  1536.             //do {
  1537.             //  if (strfield(r.adr+i,"href=")) {    // URL trouvΘe
  1538. #endif
  1539.             {
  1540.               char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
  1541.               int n=0;
  1542.               int reponse=0;
  1543.               mov_url[0]='\0'; mov_adr[0]='\0'; mov_fil[0]='\0';
  1544.               //
  1545.               //printf("location panic! %s\n",r.location);
  1546.               
  1547.               ////p=r.adr+i;
  1548.               ////p+=5;    // sauter href
  1549.               p=r.location;
  1550.               while(is_space(*p)) p++;  // sauter espaces, " & cie
  1551.               while((!is_space(p[n])) && (p[n] != 0) && (p[n] != '>')) n++;  // compter caractΦres
  1552.               strcpy (mov_url,"");
  1553.               strncat(mov_url,p,n);    // copier URL
  1554.               
  1555.               // url qque -> adresse+fichier
  1556.               if ((reponse=ident_url_relatif(mov_url,urladr,urlfil,mov_adr,mov_fil))>=0) {                        
  1557.                 int get_it=0;         // ne pas prendre le fichier α la mΩme adresse par dΘfaut
  1558.                 int set_prio_to=0;    // pas de priotitΘ fixΘd par wizard
  1559.                 
  1560.                 //if (ident_url(mov_url,mov_adr,mov_fil)!=-1) {    // ok URL reconnue
  1561.                 // c'est (en gros) la mΩme URL..
  1562.                 // si c'est un problΦme de casse dans le host c'est que le serveur est buggΘ
  1563.                 // ("RFC says.." : host name IS case insensitive)
  1564.                 if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) {  // identique α casse prΦs
  1565.                   // on tourne en rond
  1566.                   if (strcmp(mov_fil,urlfil)==0) {
  1567.                     error=1;
  1568.                     get_it=-1;        // ne rien faire
  1569.                     if (opt.errlog) {
  1570.                       fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Can not bear crazy server (%s) for %s%s"LF,r.msg,urladr,urlfil);
  1571.                       test_flush;
  1572.                     }
  1573.                   } else {    // mauvaise casse, effacer entrΘe dans la pile et rejouer une fois
  1574.                     get_it=1;
  1575.                   }
  1576.                 } else {
  1577.                   if (ishtml(mov_url)==0) {   // pas mΩme adresse MAIS c'est un fichier (pas de page moved possible)
  1578.                     // -> on prend α cette adresse, le lien sera enregistrΘ avec lien_record() (hash)
  1579.                     if ((opt.debug>1) && (opt.log!=NULL)) {
  1580.                       fspc(opt.log,"debug"); fprintf(opt.log,"wizard link test for moved file at %s%s.."LF,mov_adr,mov_fil);
  1581.                       test_flush;
  1582.                     }
  1583.                     if (hts_acceptlink(&opt,ptr,lien_tot,liens,
  1584.                       mov_adr,mov_fil,
  1585.                       filters,&filptr,filter_max,
  1586.                       &robots,
  1587.                       &set_prio_to,
  1588.                       NULL) != 1) {                /* nouvelle adresse non refusΘe ? */
  1589.                       get_it=1;
  1590.                       if ((opt.debug>1) && (opt.log!=NULL)) {
  1591.                         fspc(opt.log,"debug"); fprintf(opt.log,"moved link accepted: %s%s"LF,mov_adr,mov_fil);
  1592.                         test_flush;
  1593.                       }
  1594.                     }
  1595.                   } /* sinon traitΘ normalement */
  1596.                 }
  1597.                 
  1598.                 //if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) {  // identique α casse prΦs
  1599.                 if (get_it==1) {
  1600.                   // court-circuiter le reste du traitement
  1601.                   // et reculer pour mieux sauter
  1602.                   if (opt.errlog) {
  1603.                     fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning wrong case ignored for %s%s (real one is %s%s)"LF,urladr,urlfil,mov_adr,mov_fil);
  1604.                     test_flush;
  1605.                   }          
  1606.                   // canceller lien actuel
  1607.                   error=1;
  1608.                   strcpy(liens[ptr]->adr,"!");  // caractΦre bidon (invalide hash)
  1609. #if HTS_HASH
  1610. #else
  1611.                   liens[ptr]->sav_len=-1;       // taille invalide
  1612. #endif
  1613.                   // noter NOUVEAU lien
  1614.                   {
  1615.                     char mov_sav[HTS_URLMAXSIZE*2];
  1616.                     // calculer lien et Θventuellement modifier addresse/fichier
  1617.                     if (url_savename(mov_adr,mov_fil,mov_sav,NULL,NULL,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe)!=-1) { 
  1618.                       if (hash_read(&hash,mov_sav,"",0)<0) {      // n'existe pas dΘja
  1619.                         // enregistrer lien (MACRO) avec SAV IDENTIQUE
  1620.                         liens_record(mov_adr,mov_fil,liens[ptr]->sav,"","");
  1621.                         //liens_record(mov_adr,mov_fil,mov_sav,"","");
  1622.                         if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  1623.                           // mode test?
  1624.                           liens[lien_tot]->testmode=liens[ptr]->testmode;
  1625.                           liens[lien_tot]->link_import=0;       // mode normal
  1626.                           if (!set_prio_to)
  1627.                             liens[lien_tot]->depth=liens[ptr]->depth;
  1628.                           else
  1629.                             liens[lien_tot]->depth=max(0,min(set_prio_to-1,liens[ptr]->depth));       // PRIORITE NULLE (catch page)
  1630.                           liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
  1631.                           liens[lien_tot]->retry=liens[ptr]->retry;
  1632.                           liens[lien_tot]->premier=liens[ptr]->premier;
  1633.                           liens[lien_tot]->precedent=liens[ptr]->precedent;
  1634.                           lien_tot++;
  1635.                         } else {  // oups erreur, plus de mΘmoire!!
  1636.                           printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  1637.                           if (opt.errlog) {
  1638.                             fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url));
  1639.                             test_flush;
  1640.                           }
  1641.                           //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  1642.                           XH_uninit;    // dΘsallocation mΘmoire & buffers
  1643.                           return 0;
  1644.                         }
  1645.                       } else {
  1646.                         if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  1647.                           fspc(opt.errlog,"warning"); fprintf(opt.errlog,"moving %s to an existing file %s"LF,liens[ptr]->fil,urlfil);
  1648.                           test_flush;
  1649.                         }
  1650.                       }
  1651.                       
  1652.                     }
  1653.                   }
  1654.                   
  1655.                   //printf("-> %s %s %s\n",liens[lien_tot-1]->adr,liens[lien_tot-1]->fil,liens[lien_tot-1]->sav);
  1656.                   
  1657.                   // note mΘtaphysique: il se peut qu'il y ait un index.html et un INDEX.HTML
  1658.                   // sous DOS ca marche pas trΦs bien... mais comme je suis gΘnial url_savename()
  1659.                   // est α mΩme de rΘgler ce problΦme
  1660.                 } else if (get_it==0) {    // adresse vraiment diffΘrente et potentiellement en html (pas de possibilitΘ de bouger la page tel quel α cause des <img src..> et cie)
  1661.                   rn=(char*) calloct(8192,1);
  1662.                   if (rn!=NULL) {
  1663.                     // On prΘpare une page qui sautera immΘdiatement sur la bonne URL
  1664.                     // Le scanner re-changera, ensuite, cette URL, pour la mirrorer!
  1665.                     strcpy(rn,"<HTML>"CRLF);
  1666.                     strcat(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF);
  1667.                     strcat(rn,"<HEAD>"CRLF"<TITLE>Page has moved</TITLE>"CRLF"</HEAD>"CRLF"<BODY>"CRLF);
  1668.                     strcat(rn,"<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=");
  1669.                     strcat(rn,mov_url);    // URL
  1670.                     strcat(rn,"\">"CRLF);
  1671.                     strcat(rn,"<A HREF=\"");
  1672.                     strcat(rn,mov_url);
  1673.                     strcat(rn,"\">");
  1674.                     strcat(rn,"<B>Click here...</B></A>"CRLF);
  1675.                     strcat(rn,"</BODY>"CRLF);
  1676.                     strcat(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF);
  1677.                     strcat(rn,"</HTML>"CRLF);
  1678.                     
  1679.                     // changer la page
  1680.                     if (r.adr) { freet(r.adr); r.adr=NULL; }
  1681.                     r.adr=rn;
  1682.                     r.size=strlen(r.adr);
  1683.                     strcpy(r.contenttype,"text/html");
  1684.                     if (opt.errlog) {
  1685.                       fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File has moved from %s%s to %s"LF,urladr,urlfil,mov_url);
  1686.                       test_flush;
  1687.                     }
  1688.  
  1689.                     // dΘclarer page comme α Θcraser par le fichier si fichier binaire
  1690.                     // on va donc modifier la structure physique du site
  1691.                     // MAIS, en cas d'update, cela fonctionnera, car:
  1692.                     // 1. page moved: pas en cache (moved)
  1693.                     // 2. fichier qui Θcrase: mΩme en cas de get avec range:, comme c'est une erreur il 
  1694.                     // n'y aura pas de rΘponse "partial content"
  1695.                     /*
  1696.                     if (ishtml(mov_url)==0) {
  1697.                       if (!fexist(fconcat(opt.path_log,"moved.lst"))) {
  1698.                         FILE* fp=fopen(fconcat(opt.path_log,"moved.lst"),"wb");
  1699.                         if (fp) fclose(fp);
  1700.                       }
  1701.                       {
  1702.                         FILE* fp=fopen(fconcat(opt.path_log,"moved.lst"),"ab");
  1703.                         if (fp) {
  1704.                           fprintf(fp,"%s\n",mov_url);
  1705.                           fclose(fp);
  1706.                         }
  1707.                       }
  1708.                     }
  1709.                     */
  1710.  
  1711.                   }
  1712.                 }
  1713.               } else {
  1714.                 if (opt.errlog) {
  1715.                   fspc(opt.errlog,"error");
  1716.                   if (reponse==-2)
  1717.                     fprintf(opt.errlog,"Protocol ftp:// not supported for %s in file %s"LF,urladr,urlfil);
  1718.                   else
  1719.                     fprintf(opt.errlog,"Unrecoverable %s for %s%s (error move to %s)"LF,r.msg,urladr,urlfil,mov_url);
  1720.                   test_flush;
  1721.                 }
  1722.                 error=1;    // URL non reconnue
  1723.               }
  1724.             }
  1725. #if 0
  1726.             // i++;
  1727.             //} while((i<r.size) && (rn==NULL) && (error==0));
  1728. #endif
  1729.                       
  1730.           // erreur HTTP (ex: 404, not found)
  1731.         } else if (   (r.statuscode==412)
  1732.                    || (r.statuscode==416)
  1733.           ) {    // Precondition Failed, c'est α dire pour nous redemander TOUT le fichier
  1734.           if (fexist(liens[ptr]->sav)) {
  1735.             remove(liens[ptr]->sav);    // Eliminer
  1736.             if (!fexist(liens[ptr]->sav)) {  // Bien ΘliminΘ? (sinon on boucle..)
  1737. #if HDEBUG
  1738.               printf("Partial content NOT up-to-date, reget all file for %s\n",liens[ptr]->sav);
  1739. #endif
  1740.               if ( (opt.debug>1) && (opt.errlog!=NULL) ) {
  1741.                 //if (opt.errlog) {
  1742.                 fspc(opt.errlog,"debug"); fprintf(opt.errlog,"Partial file reget (%s) for %s%s"LF,r.msg,urladr,urlfil);
  1743.                 test_flush;
  1744.               }
  1745.               // enregistrer le MEME lien (MACRO)
  1746.               liens_record(liens[ptr]->adr,liens[ptr]->fil,liens[ptr]->sav,"","");
  1747.               if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  1748.                 liens[lien_tot]->testmode=liens[ptr]->testmode;          // mode test?
  1749.                 liens[lien_tot]->link_import=0;       // pas mode import
  1750.                 liens[lien_tot]->depth=liens[ptr]->depth;
  1751.                 liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
  1752.                 liens[lien_tot]->retry=liens[ptr]->retry;
  1753.                 liens[lien_tot]->premier=liens[ptr]->premier;
  1754.                 liens[lien_tot]->precedent=ptr;
  1755.                 lien_tot++;
  1756.                 //
  1757.                 // canceller lien actuel
  1758.                 error=1;
  1759.                 strcpy(liens[ptr]->adr,"!");  // caractΦre bidon (invalide hash)
  1760. #if HTS_HASH
  1761. #else
  1762.                 liens[ptr]->sav_len=-1;       // taille invalide
  1763. #endif
  1764.                 //
  1765.               } else {  // oups erreur, plus de mΘmoire!!
  1766.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  1767.                 if (opt.errlog) {
  1768.                   fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url));
  1769.                   test_flush;
  1770.                 }
  1771.                 //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  1772.                 XH_uninit;    // dΘsallocation mΘmoire & buffers
  1773.                 return 0;
  1774.               } 
  1775.             } else {
  1776.               if (opt.errlog!=NULL) {
  1777.                 fspc(opt.errlog,"error"); fprintf(opt.errlog,"Can not remove old file %s"LF,urlfil);
  1778.                 test_flush;
  1779.               }
  1780.             }
  1781.           } else {
  1782.             if (opt.errlog!=NULL) {
  1783.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Unexpected 412/416 error (%s) for %s%s"LF,r.msg,urladr,urlfil);
  1784.               test_flush;
  1785.             }
  1786.           }
  1787.         } else if (r.statuscode!=200) {
  1788.           int can_retry=0;
  1789.  
  1790.           // cas o∙ l'on peut reessayer
  1791.           // -2=timeout -3=rateout (interne α httrack)
  1792.           switch(r.statuscode) {
  1793.           //case -1: can_retry=1; break;
  1794.           case -2: if (opt.hostcontrol) {    // timeout et retry ΘpuisΘs
  1795.             if ((opt.hostcontrol & 1) && (liens[ptr]->retry<=0)) {
  1796.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1797.                 fspc(opt.log,"debug"); fprintf(opt.log,"Link banned: %s%s"LF,urladr,urlfil); test_flush;
  1798.               }
  1799.               host_ban(&opt,liens,ptr,lien_tot,back,back_max,filters,filter_max,&filptr,jump_identification(urladr));
  1800.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1801.                 fspc(opt.log,"debug"); fprintf(opt.log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush;
  1802.               }
  1803.             } else can_retry=1;
  1804.                    } else can_retry=1;
  1805.             break;
  1806.           case -3: if ((opt.hostcontrol) && (liens[ptr]->retry<=0)) {    // too slow
  1807.             if (opt.hostcontrol & 2) {
  1808.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1809.                 fspc(opt.log,"debug"); fprintf(opt.log,"Link banned: %s%s"LF,urladr,urlfil); test_flush;
  1810.               }
  1811.               host_ban(&opt,liens,ptr,lien_tot,back,back_max,filters,filter_max,&filptr,jump_identification(urladr));
  1812.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1813.                 fspc(opt.log,"debug"); fprintf(opt.log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush;
  1814.               }
  1815.             } else can_retry=1;
  1816.                    } else can_retry=1;
  1817.             break;
  1818.           case -4:            // connect closed
  1819.             can_retry=1;
  1820.             break;
  1821.           case -5:            // other (non fatal) error
  1822.             can_retry=1;
  1823.             break;
  1824.           case 408: case 409: case 500: case 502: case 504: can_retry=1;
  1825.             break;
  1826.           }
  1827.           
  1828.           if ( strcmp(liens[ptr]->fil,"/primary") ) {    // pas primary (page 0)
  1829.             if ((liens[ptr]->retry<=0) || (!can_retry) ) {  // retry ΘpuisΘs (ou retry impossible)
  1830.               if (opt.errlog) {
  1831.                 if ((opt.retry>0) && (can_retry)){
  1832.                   fspc(opt.errlog,"error"); 
  1833.                   fprintf(opt.errlog,"\"%s\" (%d) after %d retries at link %s%s (from %s%s)"LF,r.msg,r.statuscode,opt.retry,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  1834.                 } else {
  1835.                   if (r.statuscode==-10) {    // test OK
  1836.                     if ((opt.debug>0) && (opt.errlog!=NULL)) {
  1837.                       fspc(opt.errlog,"info"); 
  1838.                       fprintf(opt.errlog,"Test OK at link %s%s (from %s%s)"LF,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  1839.                     }
  1840.                   } else {
  1841.                     if (strcmp(urlfil,"/robots.txt")) {       // ne pas afficher d'infos sur robots.txt par dΘfaut
  1842.                       fspc(opt.errlog,"error"); 
  1843.                       fprintf(opt.errlog,"\"%s\" (%d) at link %s%s (from %s%s)"LF,r.msg,r.statuscode,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  1844.                     } else {
  1845.                       if (opt.debug>0) {  // on fera un alert si le retry Θchoue               
  1846.                         fspc(opt.errlog,"info"); fprintf(opt.errlog,"No robots.txt rules at %s"LF,urladr);
  1847.                         test_flush;
  1848.                       }
  1849.                     }
  1850.                   }
  1851.                 }
  1852.                 test_flush;
  1853.               }
  1854.               
  1855.               // ici on teste si on doit enregistrer la page tout de mΩme
  1856.               if (opt.errpage) {
  1857.                 // NO error in trop level
  1858.                 // due to the "no connection -> previous restored" hack
  1859.                 if (liens[ptr]->precedent != 0) {
  1860.                   store_errpage=1;
  1861.                 }
  1862.               }
  1863.               
  1864.             } else {    // retry!!
  1865.               if (opt.debug>0) {  // on fera un alert si le retry Θchoue               
  1866.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Retry after error %d (%s) at link %s%s (from %s%s)"LF,r.statuscode,r.msg,urladr,urlfil,liens[liens[ptr]->precedent]->adr,liens[liens[ptr]->precedent]->fil);
  1867.                 test_flush;
  1868.               }
  1869.               // redemander fichier
  1870.               liens_record(urladr,urlfil,savename,"","");
  1871.               if (liens[lien_tot]!=NULL) {    // OK, pas d'erreur
  1872.                 liens[lien_tot]->testmode=liens[ptr]->testmode;          // mode test?
  1873.                 liens[lien_tot]->link_import=0;       // pas mode import
  1874.                 liens[lien_tot]->depth=liens[ptr]->depth;
  1875.                 liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
  1876.                 liens[lien_tot]->retry=liens[ptr]->retry-1;    // moins 1 retry!
  1877.                 liens[lien_tot]->premier=liens[ptr]->premier;
  1878.                 liens[lien_tot]->precedent=liens[ptr]->precedent;
  1879.                 lien_tot++;
  1880.               } else {  // oups erreur, plus de mΘmoire!!
  1881.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  1882.                 if (opt.errlog) {
  1883.                   fspc(opt.errlog,"panic"); 
  1884.                   fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url));
  1885.                   test_flush;
  1886.                 }
  1887.                 //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
  1888.                 XH_uninit;    // dΘsallocation mΘmoire & buffers
  1889.                 return 0;
  1890.               } 
  1891.             }
  1892.           } else {
  1893.             if (opt.errlog) {
  1894.               fspc(opt.errlog,"info"); 
  1895.               fprintf(opt.errlog,"Info: no robots.txt at %s%s"LF,urladr,urlfil);
  1896.             }
  1897.           }
  1898.           if (!store_errpage) {
  1899.             if (r.adr) { freet(r.adr); r.adr=NULL; }  // dΘsalloc
  1900.             error=1;  // erreur!
  1901.           }
  1902.         }
  1903.         // FIN rattrapage des 301,302,307..
  1904.         // ------------------------------------------------------------
  1905.         
  1906.         
  1907.  
  1908.       }  // if !error
  1909.     }  // if !error
  1910.     
  1911.     if (!error) {  
  1912. #if DEBUG_SHOWTYPES
  1913.       if (strstr(REG,r.contenttype)==NULL) {
  1914.         strcat(REG,r.contenttype);
  1915.         strcat(REG,"\n");
  1916.         printf("%s\n",r.contenttype);
  1917.         io_flush;
  1918.       }
  1919. #endif
  1920.       
  1921.       // ------------------------------------------------------
  1922.       // ok, fichier chargΘ localement
  1923.       // ------------------------------------------------------
  1924.       
  1925.       // VΘrificateur d'intΘgritΘ
  1926.       #if DEBUG_CHECKINT
  1927.       {
  1928.         int i;
  1929.         for(i=0;i<back_max;i++) {
  1930.           char si[256];
  1931.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1932.           _CHECKINT(&back[i],si)
  1933.         }
  1934.       }
  1935.       #endif
  1936.  
  1937.  
  1938.       /* info: updated */
  1939.       if (ptr>0) {
  1940.         // "mis α jour"
  1941.         if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) {    // page modifiΘe
  1942.           if (strnotempty(savename)) {
  1943.             HTS_STAT.stat_updated_files++;
  1944.             if (opt.log!=NULL) {
  1945.               //if ((opt.debug>0) && (opt.log!=NULL)) {
  1946.               fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil);
  1947.               test_flush;
  1948.             }
  1949.           }
  1950.         } else {
  1951.           if (!store_errpage) {
  1952.             if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1953.               fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil);
  1954.               test_flush;
  1955.             }
  1956.           }
  1957.         }
  1958.       }
  1959.       
  1960.       // ------------------------------------------------------
  1961.       // traitement (parsing)
  1962.       // ------------------------------------------------------
  1963.  
  1964.       // traiter
  1965.       if (
  1966.            (is_hypertext_mime(r.contenttype))   /* Is HTML or Js, .. */
  1967.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1968.         && (r.adr!=NULL)        /* HTML Data exists */
  1969.         && (r.size>0)           /* And not empty */
  1970.         && (!store_errpage)     /* Not an html error page */
  1971.         && (savename[0]!='\0')  /* Output filename exists */
  1972.       ) {    // ne traiter que le html si autorisΘ
  1973.         // -- -- -- --
  1974.         // Parsing HTML
  1975.         if (!error) {
  1976.           // I'll have to segment this part
  1977. #include "htsparse.c"
  1978.         }
  1979.         // Fin parsing HTML
  1980.         // -- -- -- --
  1981.  
  1982.  
  1983.       }  // si text/html
  1984.       // -- -- --
  1985.       else {    // sauver fichier quelconque
  1986.         // -- -- --
  1987.         // sauver fichier
  1988.  
  1989.  
  1990.         /* En cas d'erreur, vΘrifier que fichier d'erreur existe */
  1991.         if (strnotempty(savename) == 0) {           // chemin de sauvegarde existant
  1992.           if (strcmp(urlfil,"/robots.txt")==0) {    // pas robots.txt
  1993.             if (store_errpage) {                    // c'est une page d'erreur
  1994.               int create_html_warning=0;
  1995.               int create_gif_warning=0;
  1996.               switch (ishtml(urlfil)) {      /* pas fichier html */
  1997.               case 0:                        /* non html */
  1998.                 {
  1999.                   char buff[256];
  2000.                   guess_httptype(buff,urlfil);
  2001.                   if (strcmp(buff,"image/gif")==0)
  2002.                     create_gif_warning=1;
  2003.                 }
  2004.                 break;
  2005.               case 1:                        /* html */
  2006.                 if (!r.adr) {
  2007.                 }
  2008.                 break;
  2009.               default:                       /* don't know.. */
  2010.                 break;    
  2011.               }
  2012.               /* CrΘer message d'erreur ? */
  2013.               if (create_html_warning) {
  2014.                 char* adr=(char*)malloc(strlen(HTS_DATA_ERROR_HTML)+1100);
  2015.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  2016.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg);
  2017.                   test_flush;
  2018.                 }
  2019.                 if (adr) {
  2020.                   if (r.adr) {
  2021.                     freet(r.adr);
  2022.                     r.adr=NULL;
  2023.                   }
  2024.                   sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
  2025.                   r.adr=adr;
  2026.                 }
  2027.               } else if (create_gif_warning) {
  2028.                 char* adr=(char*)malloc(HTS_DATA_UNKNOWN_GIF_LEN);
  2029.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  2030.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg);
  2031.                   test_flush;
  2032.                 }
  2033.                 if (r.adr) {
  2034.                   freet(r.adr);
  2035.                   r.adr=NULL;
  2036.                 }
  2037.                 bcopy(HTS_DATA_UNKNOWN_GIF,adr,HTS_DATA_UNKNOWN_GIF_LEN);
  2038.                 r.adr=adr;
  2039.               }
  2040.             }
  2041.           }
  2042.         }
  2043.  
  2044.         if (strnotempty(savename) == 0) {    // pas de chemin de sauvegarde
  2045.           if (strcmp(urlfil,"/robots.txt")==0) {    // robots.txt
  2046.             if (r.adr) {
  2047.               int bptr=0;
  2048.               char line[256];
  2049.               char buff[8192];
  2050.               char infobuff[8192];
  2051.               int record=0;
  2052.               line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
  2053.               //
  2054. #if DEBUG_ROBOTS
  2055.               printf("robots.txt dump:\n%s\n",r.adr);
  2056. #endif
  2057.               do {
  2058.                 bptr+=binput(r.adr+bptr,line,200);
  2059.                 if (strfield(line,"user-agent:")) {
  2060.                   char* a;
  2061.                   a=line+11;
  2062.                   while(*a==' ') a++;    // sauter espace(s)
  2063.                   if (*a == '*') {
  2064.                     if (record != 2)
  2065.                       record=1;    // c pour nous
  2066.                   } else if (strfield(a,"httrack")) {
  2067.                     buff[0]='\0';      // re-enregistrer
  2068.                     infobuff[0]='\0';
  2069.                     record=2;          // locked
  2070. #if DEBUG_ROBOTS
  2071.                     printf("explicit disallow for httrack\n");
  2072. #endif
  2073.                   }
  2074.                   else record=0;
  2075.                 } else if (record) {
  2076.                   if (strfield(line,"disallow:")) {
  2077.                     char* a;
  2078.                     a=strchr(line,'#');
  2079.                     if (a) *a='\0';
  2080.                     while((line[strlen(line)-1]==' ') || (line[strlen(line)-1]==10) || (line[strlen(line)-1]==13))
  2081.                       line[strlen(line)-1]='\0';   // supprimer espaces
  2082.                     a=line+9;
  2083.                     while((*a==' ') || (*a==10) || (*a==13))
  2084.                       a++;    // sauter espace(s)
  2085.                     if (strnotempty(a)) {
  2086.                       if (strcmp(a,"/")) {      /* ignoring disallow: / */
  2087.                         strcat(buff,a);
  2088.                         strcat(buff,"\n");
  2089.                         if (strnotempty(infobuff)) strcat(infobuff,", ");
  2090.                         strcat(infobuff,a);
  2091.                       } else {
  2092.                         if (opt.errlog!=NULL) {
  2093.                           fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
  2094.                           test_flush;
  2095.                         }
  2096.                       }
  2097.                     }
  2098.                   }
  2099.                 }
  2100.               } while( (bptr<r.size) && (strlen(buff)<4096) );
  2101.               if (strnotempty(buff)) {
  2102.                 checkrobots_set(&robots,urladr,buff);
  2103.                 if (opt.log!=NULL) {
  2104.                   if (opt.log != opt.errlog) {
  2105.                     fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
  2106.                     test_flush;
  2107.                   } 
  2108.                 }
  2109.                 if (opt.errlog!=NULL) {
  2110.                   fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff);
  2111.                   test_flush;
  2112.                 }
  2113.               }
  2114.             }
  2115.           }
  2116.         } else if (r.is_write) {    // dΘja sauvΘ sur disque
  2117.           if (!ishttperror(r.statuscode))
  2118.             HTS_STAT.stat_files++;
  2119.           HTS_STAT.stat_bytes+=r.size;
  2120.           //printf("ok......\n");
  2121.         } else {
  2122.           // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
  2123.           // rΘcursion nous en empΩche
  2124.           // Dans ce cas on met un fichier indiquant ce fait
  2125.           // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus
  2126.           // fort, on supprimera le readme, et on scannera le fichier html!
  2127.           // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!)
  2128.           if ( (is_hypertext_mime(r.contenttype)) && (!store_errpage) && (r.size>0)) {  // c'est du html!!
  2129.             char tempo[HTS_URLMAXSIZE*2];
  2130.             FILE* fp;
  2131.             tempo[0]='\0';
  2132.             strcpy(tempo,savename);
  2133.             strcat(tempo,".readme");
  2134.             
  2135. #if HTS_DOSNAME
  2136.             // remplacer / par des slash arriΦre
  2137.             {
  2138.               int i=0;
  2139.               while(tempo[i]) {
  2140.                 if (tempo[i]=='/')
  2141.                   tempo[i]='\\';
  2142.                 i++;
  2143.               } 
  2144.             } 
  2145.             // a partir d'ici le slash devient antislash
  2146. #endif
  2147.             
  2148.             if ((fp=fopen(tempo,"wb"))!=NULL) {
  2149.               fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION""CRLF""CRLF);
  2150.               fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
  2151.               fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
  2152.               fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
  2153.               fprintf(fp,"and to rescan the URL."CRLF);
  2154.               fclose(fp);
  2155. #if HTS_WIN==0
  2156.               chmod(tempo,HTS_ACCESS_FILE);      
  2157. #endif
  2158.               usercommand(0,NULL,antislash(tempo));
  2159.             }
  2160.             
  2161.             
  2162.             if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  2163.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
  2164.               test_flush;
  2165.             }
  2166.           } else {
  2167.             if ((opt.getmode & 2)!=0) {    // ok autorisΘ
  2168.               if ( (opt.debug>1) && (opt.log!=NULL) ) {
  2169.                 fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename);
  2170.                 test_flush;
  2171.               }
  2172.             } else {    // lien non autorisΘ! (ex: cgi-bin en html)
  2173.               if ((opt.debug>1) && (opt.log!=NULL)) {
  2174.                 fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
  2175.                 test_flush;
  2176.               } 
  2177.               freet(r.adr); r.adr=NULL;
  2178.             }
  2179.           }
  2180.           
  2181.           //printf("extern=%s\n",r.contenttype);
  2182.  
  2183.           // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!          
  2184.           if (r.adr) {
  2185.             if (filesave(r.adr,(int)r.size,savename)!=0) {
  2186.               if (opt.errlog) {   
  2187.                 fprintf(opt.errlog,"Unable to save file %s"LF,savename);
  2188.                 test_flush;
  2189.               }
  2190.             } else {
  2191.               if (!ishttperror(r.statuscode))
  2192.                 HTS_STAT.stat_files++;
  2193.               HTS_STAT.stat_bytes+=r.size;
  2194.             }
  2195.           }
  2196.           
  2197.         }
  2198.   
  2199.         //printf("check: %s\n",savename);
  2200.         // parser classes java
  2201.         if (opt.parsejava) {
  2202.           if (strlen(savename)>6) {  // fichier.class
  2203.             if (strfield(savename+strlen(savename)-6,".class")) {  // ok c'est une classe
  2204.               if (fexist(savename)) {   // ok, existe bien!
  2205.                 char err_msg[1100];
  2206.                 int r;
  2207.                 err_msg[0]='\0';
  2208.                 
  2209.                 //##char* buffer;
  2210.                 // JavaParsing f34R!
  2211.                 if ((opt.debug>1) && (opt.log!=NULL)) {
  2212.                   fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): parsing %s"LF,savename); test_flush;
  2213.                 }
  2214.                 
  2215.                 //##buffer=(char*) malloct(32768);
  2216.                 //##if (buffer) {
  2217.                 //
  2218.                 //##strcpy(buffer,"$BUFFER$");
  2219.                 //##hts_add_file(buffer);    // dΘclarer buffer
  2220.                 while(hts_add_file(NULL,-1) >= 0);   // clear chain
  2221.                 
  2222.                 r=hts_parse_java(savename,(char*) &err_msg);  // parsing
  2223.                 if (!r) {    // error
  2224.                   if (opt.errlog) {   
  2225.                     fprintf(opt.errlog,"Unable to parse java file %s : %s"LF,savename,err_msg);
  2226.                     test_flush;
  2227.                   }
  2228.                 } else {  // ok
  2229.                   char adr[HTS_URLMAXSIZE*2],fil[HTS_URLMAXSIZE*2],save[HTS_URLMAXSIZE*2];  // nom du fichier α sauver dans la boucle
  2230.                   char codebase[HTS_URLMAXSIZE*2];                  // codebase classe java
  2231.                   char lien[HTS_URLMAXSIZE*2];
  2232.                   //##char* a;
  2233.                   int file_position;
  2234.                   int pass_fix,prio_fix;
  2235.                   codebase[0]='\0';
  2236.                   //
  2237.                   
  2238.                   if ((opt.debug>1) && (opt.log!=NULL)) {
  2239.                     fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): parsing finished, now copying links.."LF); test_flush;
  2240.                   }
  2241.                   // recopie de "creer le lien"
  2242.                   //
  2243.                   
  2244.                   // adr = c'est la mΩme
  2245.                   // fil et save: save2 et fil2
  2246.                   prio_fix=maximum(liens[ptr]->depth-1,0);
  2247.                   pass_fix=max(liens[ptr]->pass2,numero_passe);
  2248.                   if (liens[ptr]->cod) strcpy(codebase,liens[ptr]->cod);       // codebase valable pour tt les classes descendantes
  2249.                   if (strnotempty(codebase)==0) {    // pas de codebase, construire
  2250.                     char* a;
  2251.                     strcpy(codebase,liens[ptr]->fil);
  2252.                     a=codebase+strlen(codebase)-1;
  2253.                     while((*a) && (*a!='/') && ((int) a > (int) codebase)) a--;
  2254.                     if (*a=='/')
  2255.                       *(a+1)='\0';    // couper
  2256.                   } else {    // couper http:// Θventuel
  2257.                     if (strfield(codebase,"http://")) {
  2258.                       char tempo[HTS_URLMAXSIZE*2];
  2259.                       char* a=codebase+7;
  2260.                       a=strchr(a,'/');    // aprΦs host
  2261.                       if (a) {  // ** msg erreur et vΘrifier?
  2262.                         strcpy(tempo,a);
  2263.                         strcpy(codebase,tempo);    // couper host
  2264.                       } else {
  2265.                         if (opt.errlog) {   
  2266.                           fprintf(opt.errlog,"Unexpected strstr error in base %s"LF,codebase);
  2267.                           test_flush;
  2268.                         }
  2269.                       }
  2270.                     }
  2271.                   }
  2272.                   //##a=buffer;
  2273.                   //##strcat(buffer,"&");  // fin du buffer
  2274.                   if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) {    // trop long
  2275.                     if (opt.errlog) {   
  2276.                       fprintf(opt.errlog,"Codebase too long, parsing skipped (%s)"LF,codebase);
  2277.                       test_flush;
  2278.                     }
  2279.                     //##a=NULL;
  2280.                     while(hts_add_file(NULL,-1) >= 0);   // clear chain
  2281.                   }
  2282.                   while ( (file_position=hts_add_file(lien,-1)) >= 0 ) {
  2283.                     int dejafait=0;
  2284.                     /* //##
  2285.                     char* b;
  2286.                     
  2287.                      // prochain fichier α noter!
  2288.                      lien[0]='\0';
  2289.                      b=strchr(a,'&');  // marqueur de fin de chaine (voir hts_add_file)
  2290.                      if (b) {
  2291.                      if ( ( ((int) b-(int) a) + strlen(codebase)) < HTS_URLMAXSIZE)
  2292.                      strncat(lien,a,(int) b-(int) a);    // nom du fichier
  2293.                      else {
  2294.                      if (opt.errlog) {   
  2295.                      fprintf(opt.errlog,"Error: Java-Parser generated link that exceeds %d bytes"LF,HTS_URLMAXSIZE);
  2296.                      test_flush;
  2297.                      }
  2298.                      }
  2299.                      } else a=NULL;
  2300.                      
  2301.                       if (strnotempty(lien)==0) a=NULL;  // fin
  2302.                       if (a)
  2303.                       a=b+1;
  2304.                     */
  2305.                     
  2306.                     if (strnotempty(lien)) {
  2307.                       
  2308.                       // calculer les chemins et noms de sauvegarde
  2309.                       if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
  2310.                         int r;
  2311.                         
  2312.                         //  patcher opt pour garder structure originale!! (on ne patche pas les noms dans la classe java!)
  2313.                         //##if (!strstr(lien,"://")) {         // PAS tester les http://.. inutile (on ne va pas patcher le binaire :-( )
  2314.                         if (1) {
  2315.                           char tempo[HTS_URLMAXSIZE*2];
  2316.                           int a,b;
  2317.                           tempo[0]='\0';
  2318.                           a=opt.savename_type;
  2319.                           b=opt.savename_83;
  2320.                           opt.savename_type=0;
  2321.                           opt.savename_83=0;
  2322.                           // note: adr,fil peuvent Ωtre patchΘs
  2323.                           r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe);
  2324.                           opt.savename_type=a;
  2325.                           opt.savename_83=b;
  2326.                           if (r != -1) {
  2327.                             if (savename) {
  2328.                               if (lienrelatif(tempo,save,savename)==0) {
  2329.                                 if ((opt.debug>1) && (opt.log!=NULL)) {
  2330.                                   fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
  2331.                                   test_flush;
  2332.                                 }
  2333.                                 //
  2334.                                 // xxc xxc xxc xxc TODO java:
  2335.                                 // rebuild the java class with patched strings...
  2336.                                 //
  2337.                                 if (strlen(tempo)<=strlen(lien)) {
  2338.                                   FILE* fp=fopen(savename,"r+b");
  2339.                                   if (fp) {
  2340.                                     if (!fseek(fp,file_position,SEEK_SET)) {
  2341.                                       //unsigned short int string_length=strlen(tempo);
  2342.                                       //fwrite(&valint,sizeof(string_length),1,fp);
  2343.                                       // xxc xxc ARGH! SI la taille est <, dΘcaler le code ?!
  2344.                                     } else {
  2345.                                       if (opt.log!=NULL) {
  2346.                                         fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): unable to patch: %s"LF,savename);
  2347.                                         test_flush;
  2348.                                       }
  2349.                                     }
  2350.                                     fclose(fp);
  2351.                                   } else {
  2352.                                     if (opt.log!=NULL) {
  2353.                                       fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): unable to open: %s"LF,savename);
  2354.                                       test_flush;
  2355.                                     }
  2356.                                   }
  2357.                                 } else {
  2358.                                   if (opt.log!=NULL) {
  2359.                                     fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): link too long, unable to write it: %s"LF,tempo);
  2360.                                     test_flush;
  2361.                                   }
  2362.                                 }
  2363.                               }
  2364.                             }
  2365.                           }
  2366.                         } else {
  2367.                           if ((opt.debug>1) && (opt.log!=NULL)) {
  2368.                             fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): file not caught: %s"LF,lien); test_flush;
  2369.                           }
  2370.                           r=-1;
  2371.                         }
  2372.                         //
  2373.                         if (r != -1) {
  2374.                           if ((opt.debug>1) && (opt.log!=NULL)) {
  2375.                             fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
  2376.                           }
  2377.                           
  2378.                           // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2)
  2379.                           
  2380.                           // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  2381.                           // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  2382.                           // au fichier est la plus grande des deux prioritΘs
  2383.                           //
  2384.                           // On part de la fin et on essaye de se presser (Θconomise temps machine)
  2385. #if HTS_HASH
  2386.                           {
  2387.                             int i=hash_read(&hash,save,"",0);      // lecture type 0 (sav)
  2388.                             if (i>=0) {
  2389.                               liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  2390.                               dejafait=1;
  2391.                             }
  2392.                           }
  2393. #else
  2394.                           {
  2395.                             register int l;
  2396.                             register int i;
  2397.                             l=strlen(save);
  2398.                             for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) {
  2399.                               if (liens[i]->sav_len==l) {    // mΩme taille de chaεne
  2400.                                 if (strcmp(liens[i]->sav,save)==0) {    // existe dΘja
  2401.                                   liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  2402.                                   dejafait=1;
  2403.                                 }
  2404.                               }
  2405.                             }
  2406.                           }
  2407. #endif
  2408.                           
  2409.                           
  2410.                           if (!dejafait) {
  2411.                             //
  2412.                             // >>>> CREER LE LIEN JAVA <<<<
  2413.                             
  2414.                             // enregistrer fichier de java (MACRO)
  2415.                             liens_record(adr,fil,save,"","");
  2416.                             if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  2417.                               printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  2418.                               if (opt.errlog) { 
  2419.                                 fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(add_tab_alloc+1)*sizeof(lien_url));
  2420.                                 test_flush;
  2421.                               }
  2422.                               // if ((opt.getmode & 1) && (ptr>0)) { if (fp) { fclose(fp); fp=NULL; } }
  2423.                               XH_extuninit;    // dΘsallocation mΘmoire & buffers
  2424.                               return 0;
  2425.                             }  
  2426.                             
  2427.                             // mode test?                          
  2428.                             liens[lien_tot]->testmode=0;          // pas mode test
  2429.                             
  2430.                             liens[lien_tot]->link_import=0;       // pas mode import
  2431.                             
  2432.                             // Θcrire autres paramΦtres de la structure-lien
  2433.                             //if (meme_adresse)                                 
  2434.                             liens[lien_tot]->premier=liens[ptr]->premier;
  2435.                             //else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  2436.                             //  liens[lien_tot]->premier=ptr;
  2437.                             
  2438.                             liens[lien_tot]->precedent=ptr;
  2439.                             // noter la prioritΘ
  2440.                             liens[lien_tot]->depth=prio_fix;
  2441.                             liens[lien_tot]->pass2=max(pass_fix,numero_passe);
  2442.                             liens[lien_tot]->retry=opt.retry;
  2443.                             
  2444.                             //strcpy(liens[lien_tot]->adr,adr);
  2445.                             //strcpy(liens[lien_tot]->fil,fil);
  2446.                             //strcpy(liens[lien_tot]->sav,save); 
  2447.                             if ((opt.debug>1) && (opt.log!=NULL)) {
  2448.                               fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  2449.                               test_flush;
  2450.                             }
  2451.                             
  2452.                             lien_tot++;  // UN LIEN DE PLUS
  2453.                           }
  2454.                         }      
  2455.                         }  
  2456.                         
  2457.                       }  
  2458.                     }
  2459.                     
  2460.                   }
  2461.                   //##// effacer buffer temporaire
  2462.                   //##if (buffer) freet(buffer); buffer=NULL;
  2463.                   //##}  // if buffer
  2464.               }  // if exist
  2465.             }  // if .class
  2466.           }  // if strlen-savename
  2467.         }  // if opt.parsejava
  2468.         
  2469.         
  2470.         
  2471.       }  // text/html ou autre
  2472.       
  2473.     }  // if !error
  2474.     
  2475.  
  2476. jump_if_done:
  2477.     // libΘrer les liens
  2478.     if (r.adr) { freet(r.adr); r.adr=NULL; }   // libΘrer la mΘmoire!
  2479.     
  2480.     // prochain lien
  2481.     ptr++;
  2482.     
  2483.     // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html)
  2484.     if (opt.getmode & 4) {    // sauver les non html aprΦs
  2485.       // sauter les fichiers selon la passe
  2486.       if (!numero_passe) {
  2487.         while((ptr<lien_tot)?(   liens[ptr]->pass2):0) ptr++;
  2488.       } else {
  2489.         while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
  2490.       }
  2491.       if (ptr>=lien_tot) {     // fin de boucle
  2492.         if (!numero_passe) { // premiΦre boucle
  2493.           if ((opt.debug>1) && (opt.log!=NULL)) {
  2494.             fprintf(opt.log,LF"Now getting non-html files..."LF);
  2495.             test_flush;
  2496.           }
  2497.           numero_passe=1;   // seconde boucle
  2498.           ptr=0;
  2499.           // prochain pass2
  2500.           while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
  2501.           
  2502.           //printf("first link==%d\n");
  2503.           
  2504.         }
  2505.       }  
  2506.     }
  2507.         
  2508.     // a-t-on dΘpassΘ le quota?
  2509.     if ((opt.maxsite>0) && (HTS_STAT.stat_bytes>=opt.maxsite)) {
  2510.       if (opt.errlog) {
  2511.         fprintf(opt.errlog,"More than %d bytes have been transfered.. giving up"LF,opt.maxsite);
  2512.         test_flush;
  2513.       } 
  2514.       ptr=lien_tot;
  2515.     } else if ((opt.maxtime>0) && ((time_local()-HTS_STAT.stat_timestart)>opt.maxtime)) {            
  2516.       if (opt.errlog) {
  2517.         fprintf(opt.errlog,"More than %d seconds passed.. giving up"LF,opt.maxtime);
  2518.         test_flush;
  2519.       } 
  2520.       ptr=lien_tot;
  2521.     } else if (exit_xh) {  // sortir
  2522.       if (opt.errlog) {
  2523.         fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
  2524.         test_flush;
  2525.       } 
  2526.       ptr=lien_tot;
  2527.     }
  2528.   } while(ptr<lien_tot);
  2529.   //
  2530.   //
  2531.   //
  2532.  
  2533.  
  2534.   // no data transfered, no data saved
  2535.   // we assume that something was bad (no connection)
  2536.   // just backup old cache and restore everything
  2537.   if ( (HTS_STAT.stat_files == 0) && (new_stat_bytes < 2048) ) {
  2538.     if (opt.errlog) {
  2539.       fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF);
  2540.       test_flush;
  2541.     } 
  2542.     XH_uninit;
  2543.     if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) {
  2544.       remove(fconcat(opt.path_log,"hts-cache/new.dat"));
  2545.       remove(fconcat(opt.path_log,"hts-cache/new.ndx"));
  2546.       remove(fconcat(opt.path_log,"hts-cache/new.lst"));
  2547.       rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat"));
  2548.       rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx"));
  2549.       rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst"));
  2550.     }
  2551.     exit_xh=2;        /* interrupted (no connection detected) */
  2552.     return 1;
  2553.   }
  2554.  
  2555.  
  2556.   // purger!
  2557.   if (opt.delete_old) {
  2558.     if (cache.lst) {
  2559.       FILE *old_lst,*new_lst;
  2560.       //
  2561. #if HTS_ANALYSTE==2
  2562.       _hts_in_html_parsing=3;
  2563. #endif
  2564.       //
  2565.       fclose(cache.lst); cache.lst=NULL;
  2566.       old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb");
  2567.       if (old_lst) {
  2568.         LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst"));
  2569.         new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb");
  2570.         if ((new_lst) && (sz>0)) {
  2571.           char* adr=(char*) malloct((INTsys)sz);
  2572.           if (adr) {
  2573.             if ((int) fread(adr,1,(INTsys)sz,new_lst) == sz) {
  2574.               char line[1100];
  2575.               int purge=0;
  2576.               while(!feof(old_lst)) {
  2577.                 linput(old_lst,line,1000);
  2578.                 if (!strstr(adr,line)) {    // fichier non trouvΘ dans le nouveau?
  2579.                   char file[HTS_URLMAXSIZE*2];
  2580.                   strcpy(file,opt.path_html);
  2581.                   strcat(file,line+1);
  2582.                   file[strlen(file)-1]='\0';
  2583.                   if (fexist(file)) {       // toujours sur disque: virer
  2584.                     if (opt.log) {
  2585.                       fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file);
  2586.                     }
  2587.                     remove(file); purge=1;
  2588.                   }
  2589.                 }
  2590.               }
  2591.               {
  2592.                 fseek(old_lst,0,SEEK_SET);
  2593.                 while(!feof(old_lst)) {
  2594.                   linput(old_lst,line,1000);
  2595.                   while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
  2596.                     line[strlen(line)-1]='\0';
  2597.                   }
  2598.                   if (strnotempty(line))
  2599.                     line[strlen(line)-1]='\0';
  2600.                   if (strnotempty(line))
  2601.                     if (!strstr(adr,line)) {    // non trouvΘ?
  2602.                       char file[HTS_URLMAXSIZE*2];
  2603.                       strcpy(file,opt.path_html);
  2604.                       strcat(file,line+1);
  2605.                       while ((strnotempty(file)) && (rmdir(file)==0)) {    // ok, ΘliminΘ (existait)
  2606.                         purge=1;
  2607.                         if (opt.log) {
  2608.                           fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file);
  2609.                           while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
  2610.                             file[strlen(file)-1]='\0';
  2611.                           }
  2612.                           if (strnotempty(file))
  2613.                             file[strlen(file)-1]='\0';
  2614.                         }
  2615.                       }
  2616.                     }
  2617.                 }
  2618.               }
  2619.               //
  2620.               if (!purge) {
  2621.                 if (opt.log) {
  2622.                   fprintf(opt.log,"No files purged"LF);
  2623.                 }
  2624.               }
  2625.             }
  2626.             freet(adr);
  2627.           }
  2628.           fclose(new_lst);
  2629.         }
  2630.         fclose(old_lst);
  2631.       }
  2632.       //
  2633. #if HTS_ANALYSTE==2
  2634.       _hts_in_html_parsing=0;
  2635. #endif
  2636.     }
  2637.   }
  2638.   // fin purge!
  2639.   
  2640.  
  2641.   // Indexation
  2642.   if (opt.kindex)
  2643.     index_finish(opt.path_html);
  2644.  
  2645.   // afficher rΘsumΘ dans log
  2646.   if (opt.log!=NULL) {
  2647.     int error   = fspc(NULL,"error");
  2648.     int warning = fspc(NULL,"warning");
  2649.     int info    = fspc(NULL,"info");
  2650.     char htstime[256];
  2651.     // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
  2652.     int n=(int) (new_stat_bytes/(time_local()-HTS_STAT.stat_timestart));
  2653.     sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
  2654.     //fprintf(opt.log,LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
  2655.     fprintf(opt.log,LF"HTTrack mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,(int)lien_tot-1,(int)HTS_STAT.stat_files,(int)HTS_STAT.stat_bytes,(int)new_stat_bytes,(int)n);
  2656.     if (error)
  2657.       fprintf(opt.log,"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
  2658.     else
  2659.       fprintf(opt.log,"(No errors, %d warnings, %d messages)"LF,warning,info);
  2660.     test_flush;
  2661.   }
  2662. #if DEBUG_HASH
  2663.   // noter les collisions
  2664.   {
  2665.     int i;
  2666.     int empty1=0,empty2=0,empty3=0;
  2667.     for(i=0;i<HTS_HASH_SIZE;i++) {
  2668.       if (hash.hash[0][i] == -1)
  2669.         empty1++;
  2670.       if (hash.hash[1][i] == -1)
  2671.         empty2++;
  2672.       if (hash.hash[2][i] == -1)
  2673.         empty3++;
  2674.     }
  2675.     printf("\n");
  2676.     printf("Debug info: Hash-table report\n");
  2677.     printf("Number of files entered:   %d\n",hashnumber);
  2678.     printf("Table size:                %d\n",HTS_HASH_SIZE);
  2679.     printf("\n");
  2680.     printf("Longest chain sav:              %d, empty: %d\n",longest_hash[0],empty1);
  2681.     printf("Longest chain adr,fil:          %d, empty: %d\n",longest_hash[1],empty2);
  2682.     printf("Longest chain former_adr/fil:   %d, empty: %d\n",longest_hash[2],empty3);
  2683.     printf("\n");
  2684.   }
  2685. #endif    
  2686.   // fin afficher rΘsumΘ dans log
  2687.   
  2688.   // dΘsallocation mΘmoire & buffers  
  2689.   XH_uninit    
  2690.  
  2691.   return 1;    // OK
  2692. }
  2693. // version 2 pour le reste
  2694. // flusher si on doit lire peu α peu le fichier
  2695. #undef test_flush
  2696. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  2697.  
  2698.  
  2699. // Estimate transfer rate
  2700. int engine_stats() {
  2701.   if ( ((mtime_local() - HTS_STAT.imstat_timestart) >= 2000) && (new_stat_bytes>2048) ) {
  2702.     double cdif;
  2703.     double dif;
  2704.     cdif=mtime_local();
  2705.     dif=cdif - HTS_STAT.imstat_timestart;
  2706.     if (dif) {
  2707.       LLint byt=(int) (new_stat_bytes-HTS_STAT.istat_bytes);
  2708.       HTS_STAT.rate=(LLint)((double) ((double)byt/(dif/1000.0)));
  2709.       //
  2710.       HTS_STAT.istat_bytes=new_stat_bytes;
  2711.       HTS_STAT.imstat_timestart=cdif;
  2712.     }
  2713.     return 1;       /* refreshed */
  2714.   }
  2715.   return 0;
  2716. }
  2717.  
  2718.  
  2719. // bannir host (trop lent etc)
  2720. void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,lien_back* back,int back_max,char** filters,int filter_max,int* filptr,char* host) {
  2721.   //register int l;
  2722.   register int i;
  2723.  
  2724.   if (host[0]=='!')
  2725.     return;    // erreur.. dΘja cancellΘ.. bizzard.. devrait pas arriver
  2726.  
  2727.   // interdire host
  2728.   if (*filptr < filter_max) {
  2729.     strcpy(filters[*filptr],"-");
  2730.     strcat(filters[*filptr],host);
  2731.     strcat(filters[*filptr],"/*");     // host/ * interdit
  2732.     (*filptr)++; *filptr=minimum(*filptr,filter_max);  
  2733.   }
  2734.   
  2735.   // oups
  2736.   if (strlen(host)<=1) {    // euhh?? longueur <= 1
  2737.     if (strcmp(host,"file://")) {
  2738.       //## if (host[0]!=lOCAL_CHAR) {  // pas local
  2739.       if (opt->log!=NULL) {
  2740.         fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
  2741.       }          
  2742.       return;  // purΘe
  2743.     }
  2744.   }
  2745.   
  2746.   // couper connexion
  2747.   for(i=0;i<back_max;i++) {
  2748.     if (back[i].status>=0)    // rΘception OU prΩt
  2749.       if (strfield2(back[i].url_adr,host)) {
  2750. #if HTS_DEBUG_CLOSESOCK
  2751.         DEBUG_W("host control: deletehttp\n");
  2752. #endif
  2753.         back[i].status=0;  // terminΘ
  2754.         if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  2755.         back[i].r.soc=INVALID_SOCKET;
  2756.         back[i].r.statuscode=-2;    // timeout (peu importe si c'est un traffic jam)
  2757.         strcpy(back[i].r.msg,"Link Cancelled by host control");
  2758.         
  2759.         if ((opt->debug>1) && (opt->log!=NULL)) {
  2760.           fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2761.         }          
  2762.       }
  2763.   }
  2764.   
  2765.   // effacer liens
  2766.   //l=strlen(host);
  2767.   for(i=0;i<lien_tot;i++) {
  2768.     //if (liens[i]->adr_len==l) {    // mΩme taille de chaεne
  2769.     // Calcul de taille sΘcurisΘe
  2770.     if (liens[i]) {
  2771.       if (liens[i]->adr) {
  2772.         int l = 0;
  2773.         while((liens[i]->adr[l]) && (l<1020)) l++;
  2774.         if ((l > 0) && (l<1020)) {   // sΘcuritΘ
  2775.           if (strfield2(jump_identification(liens[i]->adr),host)) {    // host
  2776.             if ((opt->debug>1) && (opt->log!=NULL)) {
  2777.               fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
  2778.             }
  2779.             strcpy(liens[i]->adr,"!");    // cancel (invalide hash)
  2780. #if HTS_HASH
  2781. #else
  2782.             liens[i]->sav_len=-1;         // taille invalide
  2783. #endif
  2784.             // on efface pas le hash, because si on rencontre le lien, reverif sav..
  2785.           }
  2786.         } else {
  2787.           if (opt->log!=NULL) {
  2788.             char dmp[1040];
  2789.             dmp[0]='\0';
  2790.             strncat(dmp,liens[i]->adr,1024);
  2791.             fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
  2792.             fprintf(opt->log,"dump 1024 bytes (address %d): "LF"%s"LF,(int)liens[i]->adr,dmp); test_flush;
  2793.           }          
  2794.         }
  2795.       } else {
  2796.         if (opt->log!=NULL) {
  2797.           fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
  2798.         }  
  2799.       }
  2800.     } else {
  2801.       if (opt->log!=NULL) {
  2802.         fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
  2803.       }  
  2804.     }
  2805.     //}
  2806.   }
  2807. }
  2808.  
  2809.  
  2810.  
  2811.  
  2812.  
  2813.  
  2814. // vΘrifier prΘsence de l'arbo
  2815. int structcheck(char* s) {
  2816.   // vΘrifier la prΘsence des dossier(s)
  2817.   char *a=s;
  2818.   char nom[HTS_URLMAXSIZE*2];
  2819.   char *b;
  2820.  
  2821.   if (strnotempty(s)==0) return 0;
  2822.   if (strlen(s)>HTS_URLMAXSIZE) return 0;
  2823.  
  2824.   if (structcheck_buff==NULL) {
  2825.     structcheck_buff=(char*) malloct(65536);  // ** ** non dΘsallouΘ
  2826.     strcpy(structcheck_buff,"#");
  2827.   } else if (strlen(structcheck_buff)>65000) {
  2828.     strcpy(structcheck_buff,"#");  // rΘinit.. c'est idiot ** **
  2829.   }
  2830.   
  2831.   if (structcheck_buff) {
  2832.     b=nom;
  2833.     do {    
  2834.       if (*a) *b++=*a++;
  2835.       while((*a!='/') && (*a!='\0')) *b++=*a++;
  2836.       *b='\0';    // pas de ++ pour boucler
  2837.       if (*a=='/') {    // toujours dossier
  2838.         if (strnotempty(nom)) {
  2839.           char tempo[HTS_URLMAXSIZE*2];
  2840.           
  2841.           strcpy(tempo,"#"); strcat(tempo,nom); strcat(tempo,"#");
  2842.           if (strstr(structcheck_buff,tempo)==NULL) {    // non encore crΘΘ
  2843.             strcat(structcheck_buff,"#"); strcat(structcheck_buff,nom); strcat(structcheck_buff,"#");  // ajouter α la liste
  2844.                         
  2845. #if HTS_WIN
  2846.             if (mkdir(fconv(nom))!=0)
  2847. #else    
  2848.               if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0)
  2849. #endif
  2850.               {
  2851. #if HTS_REMOVE_ANNOYING_INDEX
  2852.                 // might be a filename with same name than this folder
  2853.                 // then, remove it to allow folder creation
  2854.                 // it happends when servers gives a folder index while
  2855.                 // requesting / page
  2856.                 // -> if the file can be opened (not a folder) then rename it
  2857.                 FILE* fp=fopen(fconv(nom),"ab");
  2858.                 if (fp) {
  2859.                   fclose(fp);
  2860.                   rename(fconv(nom),fconcat(fconv(nom),".txt"));
  2861.                 }
  2862.                 // if it fails, that's too bad
  2863. #if HTS_WIN
  2864.                 mkdir(fconv(nom));
  2865. #else    
  2866.                 mkdir(fconv(nom),HTS_ACCESS_FOLDER);
  2867. #endif
  2868. #endif
  2869.                 // Si existe dΘja renvoie une erreur.. tant pis
  2870.               }
  2871. #if HTS_WIN==0
  2872.               chmod(fconv(nom),HTS_ACCESS_FOLDER);
  2873. #endif
  2874.           }
  2875.         }
  2876.         *b++=*a++;    // slash
  2877.       } 
  2878.     } while(*a);
  2879.   }
  2880.   return 0;
  2881. }
  2882.  
  2883.  
  2884. // sauver un fichier
  2885. int filesave(char* adr,int len,char* s) {
  2886.   FILE* fp;
  2887.   // Θcrire le fichier
  2888.   if ((fp=filecreate(s))!=NULL) {
  2889.     int nl=0;
  2890.     if (len>0) {
  2891.       nl=(int) fwrite(adr,1,len,fp);
  2892.     }
  2893.     fclose(fp);
  2894.     usercommand(0,NULL,antislash(s));
  2895.     if (nl!=len)  // erreur
  2896.       return -1;
  2897.   } else
  2898.     return -1;
  2899.   
  2900.   return 0;
  2901. }
  2902.  
  2903.  
  2904. // ouvrir un fichier (avec chemin Un*x)
  2905. FILE* filecreate(char* s) {
  2906.   char fname[HTS_URLMAXSIZE*2];
  2907.   FILE* fp;
  2908.   fname[0]='\0';
  2909.  
  2910.   // noter lst
  2911.   filenote(s,NULL);
  2912.   
  2913.   // if (*s=='/') strcpy(fname,s+1); else strcpy(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2914.   strcpy(fname,s);
  2915.  
  2916. #if HTS_DOSNAME
  2917.   // remplacer / par des slash arriΦre
  2918.   {
  2919.     int i=0;
  2920.     while(fname[i]) {
  2921.       if (fname[i]=='/')
  2922.         fname[i]='\\';
  2923.       i++;
  2924.     } 
  2925.   } 
  2926.   // a partir d'ici le slash devient antislash
  2927. #endif
  2928.   
  2929.   // construite le chemin si besoin est
  2930.   if (structcheck(s)!=0) {
  2931.     return NULL;
  2932.   }
  2933.   
  2934.   
  2935.   // ouvrir
  2936.   fp=fopen(fname,"wb");
  2937. #if HTS_WIN==0
  2938.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2939. #endif
  2940.   return fp;
  2941. }
  2942.  
  2943. // noter fichier
  2944. int filenote(char* s,filecreate_params* params) {
  2945. //int filenote(char* s,char* params) {
  2946.   static FILE* lst = NULL;
  2947.   static char path[HTS_URLMAXSIZE*2]="";
  2948.   
  2949.   // gestion du fichier liste liste
  2950.   if (params) {
  2951.     //filecreate_params* p = (filecreate_params*) params;
  2952.     strcpy(path,params->path);
  2953.     lst=params->lst;
  2954.     return 0;
  2955.   } else if (lst) {
  2956.     char savelst[HTS_URLMAXSIZE*2];
  2957.     strcpy(savelst,fslash(s));
  2958.     // couper chemin?
  2959.     if (strnotempty(path)) {
  2960.       if (strncmp(fslash(path),savelst,strlen(path))==0) {  // couper
  2961.         strcpy(savelst,s+strlen(path));
  2962.       }
  2963.     }
  2964.     fprintf(lst,"[%s]"LF,savelst);
  2965.     fflush(lst);
  2966.   }
  2967.   return 1;
  2968. }
  2969.  
  2970. // executer commande utilisateur
  2971. HTS_INLINE void usercommand(int _exe,char* _cmd,char* file) {
  2972.   static int exe=0;
  2973.   static char cmd[2048]="";
  2974.   if (_exe) {
  2975.     strcpy(cmd,_cmd);
  2976.     if (strnotempty(cmd))
  2977.       exe=_exe;
  2978.     else
  2979.       exe=0;
  2980.   }
  2981.   if (exe) {
  2982.     if (strnotempty(file)) {
  2983.       if (strnotempty(cmd)) {
  2984.         usercommand_exe(cmd,file);
  2985.       }
  2986.     }
  2987.   }
  2988. }
  2989. void usercommand_exe(char* cmd,char* file) {
  2990.   char temp[8192];
  2991.   char c[2]="";
  2992.   int i;
  2993.   temp[0]='\0';
  2994.   //
  2995.   for(i=0;i<(int) strlen(cmd);i++) {
  2996.     if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
  2997.       strcat(temp,file);
  2998.       i++;
  2999.     } else {
  3000.       c[0]=cmd[i]; c[1]='\0';
  3001.       strcat(temp,c);
  3002.     }
  3003.   }
  3004.   system(temp);
  3005. }
  3006.  
  3007. // Θcrire n espaces dans fp
  3008. HTS_INLINE int fspc(FILE* fp,char* type) {
  3009.   static int error=0,warning=0,info=0;
  3010.   //
  3011.   if (fp) {
  3012.     char s[256];
  3013.     time_t tt;
  3014.     struct tm* A;
  3015.     tt=time(NULL);
  3016.     A=localtime(&tt);
  3017.     strftime(s,250,"%H:%M:%S",A);
  3018.     if (strnotempty(type))
  3019.       fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
  3020.     else
  3021.       fprintf(fp,"%s\t \t",s);
  3022.     if (strcmp(type,"warning")==0)
  3023.       warning++;
  3024.     else if (strcmp(type,"error")==0)
  3025.       error++;
  3026.     else if (strcmp(type,"info")==0)
  3027.       info++;
  3028.   } 
  3029.   else if (strcmp(type,"warning")==0)
  3030.     return warning;
  3031.   else if (strcmp(type,"error")==0)
  3032.     return error;
  3033.   else if (strcmp(type,"info")==0)
  3034.     return info;
  3035.   return 0;
  3036. }
  3037.  
  3038.  
  3039. // vΘrifier taux de transfert
  3040. void check_rate(double stat_timestart,int maxrate) {
  3041.   // vΘrifier taux de transfert (pas trop grand?)
  3042.   if (maxrate>0) {
  3043.     int r = (int) (new_stat_bytes/(time_local()-stat_timestart));    // taux actuel de transfert
  3044.     HTS_STAT.HTS_TOTAL_RECV_STATE=0;
  3045.     if (r>maxrate) {    // taux>taux autorisΘ
  3046.       int taux = (int) (((double) (r - maxrate) * 100) / (double) maxrate);
  3047.       if (taux<15)
  3048.         HTS_STAT.HTS_TOTAL_RECV_STATE=1;   // ralentir un peu (<15% dΘpassement)
  3049.       else if (taux<50)
  3050.         HTS_STAT.HTS_TOTAL_RECV_STATE=2;   // beaucoup (<50% dΘpassement)
  3051.       else
  3052.         HTS_STAT.HTS_TOTAL_RECV_STATE=3;   // ΘnormΘment (>50% dΘpassement)
  3053.     }
  3054.   }
  3055. }
  3056.  
  3057.  
  3058. // ---
  3059. // sous routines liΘes au moteur et au backing
  3060.  
  3061. // supplemental links ready (done) after ptr
  3062. int backlinks_done(lien_url** liens,int lien_tot,int ptr) {
  3063.   int n=0;
  3064.   int i;
  3065.   //Links done and stored in cache
  3066.   for(i=ptr+1;i<lien_tot;i++) {
  3067.     if (liens[i]) {
  3068.       if (liens[i]->pass2 == -1) {
  3069.         n++;
  3070.       }
  3071.     }
  3072.   }
  3073.   return n;
  3074. }
  3075.  
  3076. // remplir backing si moins de max_bytes en mΘmoire
  3077. HTS_INLINE int back_fillmax(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  3078.   if (back_incache(back,back_max)<opt->maxcache) {  // pas trop en mΘmoire?
  3079.     return back_fill(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  3080.   }
  3081.   return -1;                /* plus de place */
  3082. }
  3083.  
  3084. // remplir backing
  3085. int back_fill(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  3086.   int n;
  3087.  
  3088.   // ajouter autant de socket qu'on peut ajouter
  3089.   n=opt->maxsoc-back_nsoc(back,back_max);
  3090.  
  3091.   // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait)
  3092.   n=min( n, back_available(back,back_max) - 8 );
  3093.  
  3094.   // no space left on backing stack - do not back anymore
  3095.   if (back_stack_available(back,back_max) <= 2)
  3096.     n=0;
  3097.  
  3098.   if (n>0) {
  3099.     int p;
  3100.  
  3101.     if (ptr<cache->ptr_last) {      /* restart (2 scans: first html, then non html) */
  3102.       cache->ptr_ant=0;
  3103.     }
  3104.  
  3105.     p=ptr+1;
  3106.     /* on a dΘja parcouru */
  3107.     if (p<cache->ptr_ant)
  3108.       p=cache->ptr_ant;
  3109.     while( (p<lien_tot) && (n>0) ) {
  3110.     //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
  3111.       int ok=1;
  3112.       
  3113.       // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs
  3114.       if (liens[p]->pass2) {  // 2Φ passe
  3115.         if (numero_passe!=1)
  3116.           ok=0;
  3117.       } else {
  3118.         if (numero_passe!=0)
  3119.           ok=0;
  3120.       }
  3121.       
  3122.       // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que
  3123.       // le ptr l'atteigne
  3124.       if (ok) {
  3125.         if (!back_exist(back,back_max,liens[p]->adr,liens[p]->fil,liens[p]->sav)) {
  3126.           if (back_add(back,back_max,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode,&liens[p]->pass2)==-1) {
  3127.             if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  3128.               fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF);
  3129.               test_flush;
  3130.             }                    
  3131. #if BDEBUG==1
  3132.             printf("error while adding\n");
  3133. #endif                  
  3134.             n=0;    // sortir
  3135.           } else {
  3136.             n--;
  3137. #if BDEBUG==1
  3138.             printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);          
  3139. #endif
  3140.           } 
  3141.         }
  3142.       }
  3143.       p++;
  3144.     }  // while
  3145.     /* sauver position derniΦre anticipation */
  3146.     cache->ptr_ant=p;
  3147.     cache->ptr_last=ptr;
  3148.   }
  3149.   return 0;
  3150. }
  3151. // ---
  3152.  
  3153.  
  3154.  
  3155.  
  3156.  
  3157.  
  3158.  
  3159.  
  3160.  
  3161.  
  3162.  
  3163.  
  3164.  
  3165.  
  3166.  
  3167.  
  3168.  
  3169.  
  3170. // routines de dΘtournement de SIGHUP & co (Unix)
  3171. void sig_finish( int code ) {       // finir et quitter
  3172.   signal(code,sig_term);  // quitter si encore
  3173.   exit_xh=1;
  3174.   printf("\nExit requested to engine (signal %d)\n",code);
  3175. }
  3176. void sig_term( int code ) {       // quitter brutalement
  3177.   printf("\nProgram terminated (signal %d)\n",code);
  3178.   exit(0);
  3179. }
  3180. #if HTS_WIN
  3181. void sig_ask( int code ) {        // demander
  3182.   static char s[256];
  3183.   signal(code,sig_term);  // quitter si encore
  3184.   printf("\nQuit program/Cancel? (Q/C) ");
  3185.   fflush(stdout);
  3186.   scanf("%s",s);
  3187.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  3188.     exit(0);     // quitter
  3189.   signal(code,sig_ask);  // remettre signal
  3190. }
  3191. #else
  3192. void sig_back( int code ) {       // ignorer et mettre en backing 
  3193.   signal(code,sig_ignore);
  3194.   sig_doback(0);
  3195. }
  3196. void sig_ask( int code ) {        // demander
  3197.   static char s[256];
  3198.   signal(code,sig_term);  // quitter si encore
  3199.   printf("\nQuit program/Background/bLind background/Cancel? (Q/B/L/C) ");
  3200.   fflush(stdout);
  3201.   scanf("%s",s);
  3202.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  3203.     exit(0);     // quitter
  3204.   else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') )
  3205.     sig_doback(0);  // arriΦre plan
  3206.   else if ( (s[0]=='l') || (s[0]=='L') )
  3207.     sig_doback(1);  // arriΦre plan
  3208.   else {
  3209.     printf("cancel..\n");
  3210.     signal(code,sig_ask);  // remettre signal
  3211.   }
  3212. }
  3213. void sig_ignore( int code ) {     // ignorer signal
  3214.   // // signal(code,sig_ignore);
  3215. }
  3216. void sig_doback(int blind) {       // mettre en backing 
  3217.   int out=-1;
  3218.   //
  3219.   printf("\nMoving to background to complete the mirror...\n"); fflush(stdout);
  3220.   if (!blind)
  3221.     out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR);
  3222.   if (out == -1)
  3223.     out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR);
  3224.   close(0);
  3225.   close(1);
  3226.   dup(out);
  3227.   close(2);
  3228.   dup(out);
  3229.   //
  3230.   switch (fork()) {
  3231.   case 0: 
  3232.     break;
  3233.   case -1:
  3234.     printf("Error: can not fork process\n");
  3235.     break;
  3236.   default:            // pere
  3237.     usleep(100000);   // pause 1/10s "A  microsecond  is  .000001s"
  3238.     _exit(0);
  3239.     break;  
  3240.   }
  3241. }
  3242. #endif
  3243. // fin routines de dΘtournement de SIGHUP & co
  3244.  
  3245. // Poll stdin.. si besoin
  3246. #if HTS_POLL
  3247. // lecture stdin des caractΦres disponibles
  3248. int read_stdin(char* s,int max) {
  3249.   int i=0;
  3250.   while((check_stdin()) && (i<(max-1)) )
  3251.     s[i++]=fgetc(stdin);
  3252.   s[i]='\0';
  3253.   return i;
  3254. }
  3255. #ifdef _WIN32
  3256. HTS_INLINE int check_stdin() {
  3257.   return (_kbhit());
  3258. }
  3259. #else
  3260. HTS_INLINE int check_flot(T_SOC s) {
  3261.   fd_set fds;
  3262.   struct timeval tv;
  3263.   FD_ZERO(&fds);
  3264.   FD_SET((T_SOC) s,&fds);
  3265.   tv.tv_sec=0;
  3266.   tv.tv_usec=0;
  3267.   select(s+1,&fds,NULL,NULL,&tv);
  3268.   return FD_ISSET(s,&fds);
  3269. }
  3270. HTS_INLINE int check_stdin() {
  3271.   fflush(stdout); fflush(stdin);
  3272.   if (check_flot(0))
  3273.     return 1;
  3274.   return 0;
  3275. }
  3276. #endif
  3277. #endif
  3278.  
  3279.  
  3280. // Attente de touche
  3281. #if HTS_ANALYSTE!=2
  3282. int ask_continue() {
  3283.   char s[12]="";
  3284.   printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n");
  3285.   io_flush; linput(stdin,s,4);
  3286.   if (strnotempty(s)) {
  3287.     if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3288.       return 0;
  3289.   }
  3290.   return 1;
  3291. }
  3292. #else
  3293. int ask_continue() {
  3294.   char* s;
  3295.   s=hts_htmlcheck_query2(HTbuff);
  3296.   if (s) {
  3297.     if (strnotempty(s)) {
  3298.       if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3299.         return 0;
  3300.     }
  3301.     return 1;
  3302.   }
  3303.   return 1;
  3304. }
  3305. #endif
  3306.  
  3307. // nombre de digits dans un nombre
  3308. int nombre_digit(int n) {
  3309.   register int i=1;
  3310.   while(n >= 10) { n/=10; i++; }
  3311.   return i;
  3312. }
  3313.  
  3314.  
  3315. // renvoi adresse de la fin du token dans p
  3316. // renvoi NULL si la chaine est un token unique
  3317. // (PATCHE Θgalement la chaine)
  3318. // ex: "test" "test2" renvoi adresse sur espace
  3319. // flag==1 si chaine comporte des echappements comme \"
  3320. char* next_token(char* p,int flag) {
  3321.   int detect=0;
  3322.   int quote=0;
  3323.   p--;
  3324.   do {
  3325.     p++;
  3326.     if (flag && (*p=='\\')) {   // sauter \x ou \"
  3327.       if (quote) {
  3328.         char c='\0';
  3329.         if (*(p+1)=='\\')
  3330.           c='\\';
  3331.         else if (*(p+1)=='"')
  3332.           c='"';
  3333.         if (c) {
  3334.           char tempo[8192];
  3335.           tempo[0]=c; tempo[1]='\0';
  3336.           strcat(tempo,p+2);
  3337.           strcpy(p,tempo);
  3338.         }
  3339.       }
  3340.     }
  3341.     else if (*p==34) {  // guillemets (de fin)
  3342.       quote=!quote;
  3343.     }
  3344.     else if (*p==32) {
  3345.       if (!quote)
  3346.         detect=1;
  3347.     }
  3348.     else if (*p=='\0') {
  3349.       p=NULL;
  3350.       detect=1;
  3351.     }
  3352.   } while(!detect);
  3353.   return p;
  3354. }
  3355.  
  3356. // routines annexes 
  3357. #if HTS_ANALYSTE==2
  3358. // canceller un fichier (noter comme cancellable)
  3359. char* hts_cancel_file(char * s) {
  3360.   static char sav[HTS_URLMAXSIZE*2]="";
  3361.   if (s[0]!='\0')
  3362.   if (sav[0]=='\0')
  3363.     strcpy(sav,s);
  3364.   return sav;
  3365. }
  3366. void hts_cancel_test() {
  3367.   if (_hts_in_html_parsing==2)
  3368.     _hts_cancel=2;
  3369. }
  3370. void hts_cancel_parsing() {
  3371.   if (_hts_in_html_parsing)
  3372.    _hts_cancel=1;
  3373. }
  3374. #endif
  3375. //        for(_i=0;(_i<back_max) && (index<NFICH);_i++) {
  3376. //          i=(back_index+_i)%back_max;    // commencer par le "premier" (l'actuel)
  3377. //          if (back[i].status>=0) {     // signifie "lien actif"
  3378.  
  3379.  
  3380. /*  
  3381. hts_add_file, add/get elements in the add chain for java parsing
  3382. if file_position >= 0
  3383.   push 'file/file_position'
  3384.   return 1 (return 0 if exists)
  3385. else
  3386.   pop file -> 'file'
  3387.   return 'file_position'
  3388. else if empty/error
  3389.   return -1;
  3390. */
  3391. typedef struct addfile_chain {
  3392.   char name[1024];
  3393.   int pos;
  3394.   struct addfile_chain* next;
  3395. } addfile_chain;
  3396. int hts_add_file(char* file,int file_position) {
  3397.   static struct addfile_chain* chain=NULL;
  3398.  
  3399.   if (file_position>=0) {         /* copy file to the chain */
  3400.     struct addfile_chain** current;
  3401.     current=&chain;                     /* start from */
  3402.     while(*current) {
  3403.       if (strcmp((*current)->name,file)==0)
  3404.         return 0;                       /* already exists */
  3405.       current=&( (*current)->next );    /* 'next' address */
  3406.     }
  3407.     *current=calloc(1,sizeof(addfile_chain));
  3408.     if (*current) {
  3409.       (*current)->next=NULL;
  3410.       (*current)->pos=-1;
  3411.       (*current)->name[0]='\0';
  3412.     }
  3413.     if (*current) {
  3414.       strcpy((*current)->name,file);
  3415.       (*current)->pos=file_position;
  3416.       return 1;
  3417.     } else {
  3418.       printf("PANIC! Too many Java files during parsing [1]\n");
  3419.       return -1;
  3420.     }
  3421.   } else {                      /* copy last element in file and delete it */
  3422.     if (file)
  3423.       file[0]='\0';
  3424.     if (chain) {
  3425.       struct addfile_chain** current;
  3426.       int pos=-1;
  3427.       current=&chain;                     /* start from */
  3428.       while( (*current)->next ) {
  3429.         current=&( (*current)->next );    /* 'next' address */
  3430.       }
  3431.       if (file)
  3432.         strcpy(file,(*current)->name);
  3433.       pos=(*current)->pos;
  3434.       free(*current);
  3435.       *current=NULL;
  3436.       return pos;
  3437.     }
  3438.     return -1;                            /* no more elements */
  3439.   }
  3440.  
  3441.     /*
  3442.   static char* buffer;
  3443.   if (strlen(file)==8) {
  3444.     if (file[0]=='$') { // commande
  3445.       if (strcmp(file,"$BUFFER$")==0) {  // indiquer adresse buffer!
  3446.         buffer=file;    // le buffer
  3447.         buffer[0]='\0';
  3448.         return 1;
  3449.       }
  3450.     }
  3451.   }
  3452.   
  3453.   if (strlen(buffer)<32000) {   // vΘrifier..
  3454.     strcat(buffer,file);
  3455.     strcat(buffer,"&");  // sΘparateur
  3456.   } else {
  3457.     printf("PANIC! Too many Java files during parsing [1]\n");  // **
  3458.     buffer[32000]='\0';    // couper
  3459.   }
  3460.   */
  3461.  
  3462.   return 0;
  3463. }
  3464.  
  3465. #if HTS_ANALYSTE==2
  3466. // en train de parser un fichier html? rΘponse: % effectuΘs
  3467. // flag>0 : refresh demandΘ
  3468. int hts_is_parsing(int flag) {
  3469.   if (_hts_in_html_parsing) {  // parsing?
  3470.     if (flag>=0) _hts_in_html_poll=1;  // faudrait un tit refresh
  3471.     return max(_hts_in_html_done,1); // % effectuΘs
  3472.   } else {
  3473.     return 0;                 // non
  3474.   }
  3475. }
  3476. int hts_is_testing() {            // 0 non 1 test 2 purge
  3477.   if (_hts_in_html_parsing==2)
  3478.     return 1;
  3479.   else if (_hts_in_html_parsing==3)
  3480.     return 2;
  3481.   return 0;
  3482. }
  3483. // message d'erreur?
  3484. char* hts_errmsg() {
  3485.   return _hts_errmsg;
  3486. }
  3487. // mode pause transfer
  3488. int hts_setpause(int p) {
  3489.   if (p>=0) _hts_setpause=p;
  3490.   return _hts_setpause;
  3491. }
  3492. // rΘgler en cours de route les paramΦtres rΘglables..
  3493. // -1 : erreur
  3494. int hts_setopt(httrackp* opt) {
  3495.   if (opt) _hts_setopt=opt;
  3496.   return 0;
  3497. }
  3498. // ajout d'URL
  3499. // -1 : erreur
  3500. int hts_addurl(char** url) {
  3501.   if (url) _hts_addurl=url;
  3502.   return (_hts_addurl!=NULL);
  3503. }
  3504. int hts_resetaddurl() {
  3505.   _hts_addurl=NULL;
  3506.   return (_hts_addurl!=NULL);
  3507. }
  3508. // copier nouveaux paramΦtres si besoin
  3509. int copy_htsopt(httrackp* from,httrackp* to) {
  3510.   if (from->maxsite > -1) 
  3511.     to->maxsite = from->maxsite;
  3512.   
  3513.   if (from->maxfile_nonhtml > -1) 
  3514.     to->maxfile_nonhtml = from->maxfile_nonhtml;
  3515.   
  3516.   if (from->maxfile_html > -1) 
  3517.     to->maxfile_html = from->maxfile_html;
  3518.   
  3519.   if (from->maxsoc > 0) 
  3520.     to->maxsoc = from->maxsoc;
  3521.   
  3522.   if (from->nearlink > -1) 
  3523.     to->nearlink = from->nearlink;
  3524.   
  3525.   if (from->timeout > -1) 
  3526.     to->timeout = from->timeout;
  3527.   
  3528.   if (from->rateout > -1)
  3529.     to->rateout = from->rateout;
  3530.   
  3531.   if (from->maxtime > -1) 
  3532.     to->maxtime = from->maxtime;
  3533.   
  3534.   if (from->maxrate > -1)
  3535.     to->maxrate = from->maxrate;
  3536.   
  3537.   if (strnotempty(from->user_agent)) 
  3538.     strcpy(to->user_agent , from->user_agent);
  3539.   
  3540.   if (from->retry > -1) 
  3541.     to->retry = from->retry;
  3542.   
  3543.   if (from->hostcontrol > -1) 
  3544.     to->hostcontrol = from->hostcontrol;
  3545.   
  3546.   if (from->errpage > -1) 
  3547.     to->errpage = from->errpage;
  3548.  
  3549.   if (from->parseall > -1) 
  3550.     to->parseall = from->parseall;
  3551.  
  3552.  
  3553.   // test all: bit 8 de travel
  3554.   if (from->travel > -1)  {
  3555.     if (from->travel & 256)
  3556.       to->travel|=256;
  3557.     else
  3558.       to->travel&=255;
  3559.   }
  3560.  
  3561.  
  3562.   return 0;
  3563. }
  3564.  
  3565. #endif
  3566. //
  3567.  
  3568. // message copyright interne
  3569. void voidf(void) {
  3570.   char* a;
  3571.   a=""CRLF""CRLF;
  3572.   a="+-----------------------------------------------+"CRLF;
  3573.   a="|HyperTextTRACKer, Offline Browser Utility      |"CRLF;
  3574.   a="|                      HTTrack Website Copier   |"CRLF;
  3575.   a="|Code:         Windows Interface Xavier Roche   |"CRLF;
  3576.   a="|                    HTS/HTTrack Xavier Roche   |"CRLF;
  3577.   a="|                .class Parser Yann Philippot   |"CRLF;
  3578.   a="|                                               |"CRLF;
  3579.   a="|Tested on:                 Windows95,98,NT,2K  |"CRLF;
  3580.   a="|                           Linux PC            |"CRLF;
  3581.   a="|                           Sun-Solaris 5.6     |"CRLF;
  3582.   a="|                           AIX 4               |"CRLF;
  3583.   a="|                                               |"CRLF;
  3584.   a="|Copyright (C) Xavier Roche,                    |"CRLF;
  3585.   a="|Yann Philippot and other contributors          |"CRLF;
  3586.   a="|Brought to you by Serianet, Caen, France       |"CRLF;
  3587.   a="|                                               |"CRLF;
  3588.   a="|Use this program at your own risks!            |"CRLF;    
  3589.   a="+-----------------------------------------------+"CRLF;
  3590.   a=""CRLF;
  3591. }
  3592.  
  3593.  
  3594. // HTTrack Website Copier Copyright (C) Xavier Roche, Yann Philippot and other contributors
  3595. //
  3596.  
  3597.