home *** CD-ROM | disk | FTP | other *** search
/ .net 2002 March / DotNetMagazine-Issue107-Coverdisc-NET107-02-03-PCMac.bin / pc / PC Software / picks / HTTrack / httrack-3.22-3.exe / {app} / src / htscore.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-17  |  137.0 KB  |  4,048 lines

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