summaryrefslogtreecommitdiff
path: root/src/htscore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/htscore.c')
-rw-r--r--src/htscore.c4158
1 files changed, 4158 insertions, 0 deletions
diff --git a/src/htscore.c b/src/htscore.c
new file mode 100644
index 0000000..1b9db7a
--- /dev/null
+++ b/src/htscore.c
@@ -0,0 +1,4158 @@
+/* ------------------------------------------------------------ */
+/*
+HTTrack Website Copier, Offline Browser for Windows and Unix
+Copyright (C) Xavier Roche and other contributors
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+Important notes:
+
+- We hereby ask people using this source NOT to use it in purpose of grabbing
+emails addresses, or collecting any other private information on persons.
+This would disgrace our work, and spoil the many hours we spent on it.
+
+
+Please visit our Website: http://www.httrack.com
+*/
+
+
+/* ------------------------------------------------------------ */
+/* File: Main source */
+/* Author: Xavier Roche */
+/* ------------------------------------------------------------ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+/* File defs */
+#include "htscore.h"
+
+/* specific definitions */
+#include "htsbase.h"
+#include "htsnet.h"
+#include "htsbauth.h"
+#include "htsmd5.h"
+#include "htsindex.h"
+
+// htswrap_add
+#include "htswrap.h"
+/* END specific definitions */
+
+
+/* HTML parsing */
+#if HTS_ANALYSTE
+
+t_hts_htmlcheck_init hts_htmlcheck_init;
+t_hts_htmlcheck_uninit hts_htmlcheck_uninit;
+t_hts_htmlcheck_start hts_htmlcheck_start;
+t_hts_htmlcheck_end hts_htmlcheck_end;
+t_hts_htmlcheck_chopt hts_htmlcheck_chopt;
+t_hts_htmlcheck hts_htmlcheck;
+t_hts_htmlcheck_query hts_htmlcheck_query;
+t_hts_htmlcheck_query2 hts_htmlcheck_query2;
+t_hts_htmlcheck_query3 hts_htmlcheck_query3;
+t_hts_htmlcheck_loop hts_htmlcheck_loop;
+t_hts_htmlcheck_check hts_htmlcheck_check;
+t_hts_htmlcheck_pause hts_htmlcheck_pause;
+t_hts_htmlcheck_filesave hts_htmlcheck_filesave;
+t_hts_htmlcheck_linkdetected hts_htmlcheck_linkdetected;
+t_hts_htmlcheck_xfrstatus hts_htmlcheck_xfrstatus;
+t_hts_htmlcheck_savename hts_htmlcheck_savename;
+
+char _hts_errmsg[1100]="";
+int _hts_in_html_parsing=0;
+int _hts_in_html_done=0; // % done
+int _hts_in_html_poll=0; // parsing
+int _hts_setpause=0;
+//httrackp* _hts_setopt=NULL;
+char** _hts_addurl=NULL;
+
+//
+int _hts_cancel=0;
+#endif
+
+
+
+int exit_xh; /* quick exit (fatal error or interrupt) */
+
+/* debug */
+#if DEBUG_SHOWTYPES
+char REG[32768]="\n";
+#endif
+#if NSDEBUG
+int nsocDEBUG=0;
+#endif
+
+//
+#define _CLRSCR printf("\33[m\33[2J");
+#define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
+
+#if DEBUG_CHECKINT
+ #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
+ #define _CHECKINT(obj_ptr,message) \
+ if (obj_ptr) {\
+ if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
+ char msg[1100];\
+ if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
+ sprintf(msg,"* PANIC: Integrity error (structure crushed) in: %s",message);\
+ else if ( * ((char*) (obj_ptr)) != 0)\
+ sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
+ else\
+ sprintf(msg,"* PANIC: Integrity error (end of structure) in: %s",message);\
+ _CHECKINT_FAIL(msg);\
+ }\
+ } else {\
+ char msg[1100];\
+ sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
+ _CHECKINT_FAIL(msg);\
+ }
+#endif
+
+#if DEBUG_HASH
+ // longest hash chain?
+ int longest_hash[3]={0,0,0},hashnumber=0;
+#endif
+
+// demande d'interaction avec le shell
+#if HTS_ANALYSTE
+char HTbuff[2048];
+#endif
+
+
+
+// Début de httpmirror, routines annexes
+
+// version 1 pour httpmirror
+// flusher si on doit lire peu à peu le fichier
+#define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); }
+
+// pour alléger la syntaxe, des raccourcis sont créés
+#define urladr (liens[ptr]->adr)
+#define urlfil (liens[ptr]->fil)
+#define savename (liens[ptr]->sav)
+//#define level (liens[ptr]->depth)
+
+// au cas où nous devons quitter rapidement xhttpmirror (plus de mémoire, etc)
+// note: partir de liens_max.. vers 0.. sinon erreur de violation de mémoire: les liens suivants
+// ne sont plus à nous.. agh! [dur celui-là]
+#if HTS_ANALYSTE
+#define HTMLCHECK_UNINIT { \
+if ( (opt.debug>0) && (opt.log!=NULL) ) { \
+fspc(opt.log,"info"); fprintf(opt.log,"engine: end"LF); \
+} \
+hts_htmlcheck_end(); \
+}
+#else
+ #define HTMLCHECK_UNINIT
+#endif
+
+#define XH_extuninit { \
+ int i; \
+ HTMLCHECK_UNINIT \
+ if (liens!=NULL) { \
+ for(i=lien_max-1;i>=0;i--) { \
+ if (liens[i]) { \
+ if (liens[i]->firstblock==1) { \
+ freet(liens[i]); \
+ liens[i]=NULL; \
+ } \
+ } \
+ } \
+ freet(liens); \
+ liens=NULL; \
+ } \
+ if (filters && filters[0]) { \
+ freet(filters[0]); filters[0]=NULL; \
+ } \
+ if (filters) { \
+ freet(filters); filters=NULL; \
+ } \
+ if (back) { \
+ int i; \
+ for(i=0;i<back_max;i++) { \
+ back_delete(back,i); \
+ } \
+ freet(back); back=NULL; \
+ } \
+ checkrobots_free(&robots);\
+ if (cache.use) { freet(cache.use); cache.use=NULL; } \
+ if (cache.dat) { fclose(cache.dat); cache.dat=NULL; } \
+ if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
+ if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
+ if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
+ if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
+ if (opt.log) fflush(opt.log); \
+ if (opt.errlog) fflush(opt.errlog);\
+ if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
+ if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
+ if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \
+ if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
+ if (cache_hashtable) { inthash_delete(&cache_hashtable); } \
+ if (template_header) { freet(template_header); template_header=NULL; } \
+ if (template_body) { freet(template_body); template_body=NULL; } \
+ if (template_footer) { freet(template_footer); template_footer=NULL; } \
+ structcheck_init(-1); \
+}
+#define XH_uninit XH_extuninit if (r.adr) { freet(r.adr); r.adr=NULL; }
+
+// Enregistrement d'un lien:
+// on calcule la taille nécessaire: taille des 3 chaînes à stocker (taille forcée paire, plus 2 octets de sécurité)
+// puis on vérifie qu'on a assez de marge dans le buffer - sinon on en réalloue un autre
+// enfin on écrit à l'adresse courante du buffer, qu'on incrémente. on décrémente la taille dispo d'autant ensuite
+// codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
+// FA,FS: former_adr et former_fil, lien original
+#define REALLOC_SIZE 8192
+#if HTS_HASH
+#define liens_record_sav_len(A)
+#else
+#define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav)
+#endif
+
+#define liens_record(A,F,S,FA,FF) { \
+int notecode=0; \
+int lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
+ adr_len=strlen(A),\
+ fil_len=strlen(F),\
+ sav_len=strlen(S),\
+ cod_len=0,\
+ former_adr_len=strlen(FA),\
+ former_fil_len=strlen(FF); \
+if (former_adr_len>0) {\
+ former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
+ former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
+} else former_adr_len=former_fil_len=0;\
+if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
+cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
+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; \
+if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
+lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
+lien_size=add_tab_alloc; \
+if (lien_buffer!=NULL) { \
+liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
+liens[lien_tot]->firstblock=1; \
+} \
+} else { \
+liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
+liens[lien_tot]->firstblock=0; \
+} \
+if (liens[lien_tot]!=NULL) { \
+liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
+liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
+liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
+liens[lien_tot]->cod=NULL; \
+if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpy(liens[lien_tot]->cod,codebase); } \
+if (former_adr_len>0) {\
+liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
+liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
+strcpy(liens[lien_tot]->former_adr,FA); \
+strcpy(liens[lien_tot]->former_fil,FF); \
+}\
+strcpy(liens[lien_tot]->adr,A); \
+strcpy(liens[lien_tot]->fil,F); \
+strcpy(liens[lien_tot]->sav,S); \
+liens_record_sav_len(liens[lien_tot]); \
+hash_write(&hash,lien_tot); \
+} \
+}
+
+/* - abandonné (simplifie) -
+// Ajouter à un lien EXISTANT deux champs former_adr et former_fil pour indiquer le nom d'un fichier avant un "move"
+// NOTE: si un alloc est fait ici il n'y aura pas de freet() à la fin, tant pis (firstbloc)
+#define liens_add_former(index,A,F) { \
+int adr_len=strlen(A),fil_len=strlen(F); \
+adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN+4; \
+if ((int) lien_size < (int) (adr_len+fil_len)) { \
+lien_buffer=(char*) calloct(add_tab_alloc,1); \
+lien_size=add_tab_alloc; \
+} \
+if (lien_buffer!=NULL) { \
+if (liens[lien_tot]!=NULL) { \
+liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
+liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
+strcpy(liens[lien_tot]->former_adr,A); \
+strcpy(liens[lien_tot]->former_fil,F); \
+} \
+} \
+}
+*/
+
+#if 0
+#define HT_ADD_ADR { \
+ fwrite(lastsaved,1,((int) (adr - lastsaved)),fp); \
+ lastsaved=adr; }
+#define HT_ADD(A) fwrite(A,1,(int) strlen(A),fp);
+#define HT_ADD_START
+#define HT_ADD_END if (fp) { fclose(fp); fp=NULL; }
+#define HT_ADD_FOP { \
+ fp=filecreate(savename); \
+ if (fp==NULL) { \
+ if (opt.errlog) { \
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to create %s for %s%s"LF,savename,urladr,urlfil); \
+ test_flush; \
+ } \
+ freet(r.adr); r.adr=NULL; \
+ error=1; \
+ } \
+ }
+#else
+// version optimisée, qui permet de ne pas toucher aux html non modifiés (update)
+#define HT_ADD_CHK(A) if (((int) (A)+ht_len+1) >= ht_size) { \
+ ht_size=(A)+ht_len+REALLOC_SIZE; \
+ ht_buff=(char*) realloct(ht_buff,ht_size); \
+ if (ht_buff==NULL) { \
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__); \
+ XH_uninit; \
+ exit(1); \
+ } \
+ } \
+ ht_len+=A;
+/*
+(Optimized)
+#define HT_ADD_ADR { int i,j=ht_len; HT_ADD_CHK(((int) adr)- ((int) lastsaved)) \
+ for(i=0;i<((int) adr)- ((int) lastsaved);i++) \
+ ht_buff[j+i]=lastsaved[i]; \
+ ht_buff[j+((int) adr)- ((int) lastsaved)]='\0'; \
+ lastsaved=adr; }
+*/
+#define HT_ADD_ADR \
+ if ((opt.getmode & 1) && (ptr>0)) { \
+ int i=((int) (adr - lastsaved)),j=ht_len; HT_ADD_CHK(i) \
+ memcpy(ht_buff+j, lastsaved, i); \
+ ht_buff[j+i]='\0'; \
+ lastsaved=adr; \
+ }
+/*
+(Optimized)
+#define HT_ADD(A) { HT_ADD_CHK(strlen(A)) strcat(ht_buff,A); }
+*/
+#define HT_ADD(A) \
+ if ((opt.getmode & 1) && (ptr>0)) { \
+ int i=strlen(A),j=ht_len; \
+ if (i) { \
+ HT_ADD_CHK(i) \
+ memcpy(ht_buff+j, A, i); \
+ ht_buff[j+i]='\0'; \
+ } }
+#define HT_ADD_START \
+ int ht_size=(int)(r.size*5)/4+REALLOC_SIZE; \
+ int ht_len=0; \
+ char* ht_buff=NULL; \
+ if ((opt.getmode & 1) && (ptr>0)) { \
+ ht_buff=(char*) malloct(ht_size); \
+ if (ht_buff==NULL) { \
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__); \
+ XH_uninit; \
+ exit(1); \
+ } \
+ ht_buff[0]='\0'; \
+ }
+#define HT_ADD_END { \
+ int ok=0;\
+ if (ht_buff) { \
+ int file_len=(int) strlen(ht_buff);\
+ char digest[32+2];\
+ digest[0]='\0';\
+ domd5mem(ht_buff,file_len,digest,1);\
+ if (fsize(antislash(savename))==file_len) { \
+ int mlen;\
+ char* mbuff;\
+ cache_readdata(&cache,"//[HTML-MD5]//",savename,&mbuff,&mlen);\
+ if (mlen) mbuff[mlen]='\0';\
+ if ((mlen == 32) && (strcmp(((mbuff!=NULL)?mbuff:""),digest)==0)) {\
+ ok=1;\
+ if ( (opt.debug>1) && (opt.log!=NULL) ) {\
+ fspc(opt.log,"debug"); fprintf(opt.log,"File not re-written (md5): %s"LF,savename);\
+ test_flush;\
+ }\
+ } else {\
+ ok=0;\
+ } \
+ }\
+ if (!ok) { \
+ fp=filecreate(savename); \
+ if (fp) { \
+ if (file_len>0) {\
+ if ((int)fwrite(ht_buff,1,file_len,fp) != file_len) { \
+ if (opt.errlog) { \
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to write HTML file %s"LF,savename);\
+ test_flush;\
+ }\
+ }\
+ }\
+ fclose(fp); fp=NULL; \
+ if (strnotempty(r.lastmodified)) \
+ set_filetime_rfc822(savename,r.lastmodified); \
+ usercommand(0,NULL,antislash(savename)); \
+ } else {\
+ if (opt.errlog) { \
+ fspc(opt.errlog,"error");\
+ fprintf(opt.errlog,"Unable to save file %s"LF,savename);\
+ test_flush;\
+ }\
+ }\
+ } else {\
+ filenote(savename,NULL); \
+ }\
+ if (cache.ndx)\
+ cache_writedata(cache.ndx,cache.dat,"//[HTML-MD5]//",savename,digest,(int)strlen(digest));\
+ } \
+ freet(ht_buff); ht_buff=NULL; \
+ }
+#define HT_ADD_FOP
+#endif
+
+// libérer filters[0] pour insérer un élément dans filters[0]
+#define HT_INSERT_FILTERS0 {\
+ int i;\
+ if (filptr>0) {\
+ for(i=filptr-1;i>=0;i--) {\
+ strcpy(filters[i+1],filters[i]);\
+ }\
+ }\
+ strcpy(filters[0],"");\
+ filptr++;\
+ filptr=minimum(filptr,filter_max);\
+}
+
+#define HT_INDEX_END do { \
+if (!makeindex_done) { \
+if (makeindex_fp) { \
+ char tempo[1024]; \
+ if (makeindex_links == 1) { \
+ sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
+ } else \
+ tempo[0]='\0'; \
+ fprintf(makeindex_fp,template_footer, \
+ "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
+ tempo \
+ ); \
+ fflush(makeindex_fp); \
+ fclose(makeindex_fp); /* à ne pas oublier sinon on passe une nuit blanche */ \
+ makeindex_fp=NULL; \
+ usercommand(0,NULL,fconcat(opt.path_html,"index.html")); \
+} \
+} \
+makeindex_done=1; /* ok c'est fait */ \
+} while(0)
+
+
+
+
+// Début de httpmirror, robot
+// url1 peut être multiple
+int httpmirror(char* url1,httrackp* ptropt) {
+ httrackp opt = *ptropt; // structure d'options
+ char* primary=NULL; // première page, contenant les liens à scanner
+ int lien_tot=0; // nombre de liens pour le moment
+ lien_url** liens=NULL; // les pointeurs sur les liens
+ hash_struct hash; // système de hachage, accélère la recherche dans les liens
+ t_cookie cookie; // gestion des cookies
+ int lien_max=0;
+ int lien_size=0; // octets restants dans buffer liens dispo
+ char* lien_buffer=NULL; // buffer liens actuel
+ int add_tab_alloc=256000; // +256K de liens à chaque fois
+ //char* tab_alloc=NULL;
+ int ptr; // pointeur actuel sur les liens
+ //
+ int numero_passe=0; // deux passes pour html puis images
+ int back_max=0; // fichiers qui peuvent être en local
+ lien_back* back=NULL; // backing en local
+ htsblk r; // retour de certaines fonctions
+ TStamp lastime=0; // pour affichage infos de tmp en tmp
+ // pour les stats, nombre de fichiers & octets écrits
+ LLint stat_fragment=0; // pour la fragmentation
+ //TStamp istat_timestart; // départ pour calcul instantanné
+ //
+ TStamp last_info_shell=0;
+ int info_shell=0;
+ // filtres
+ char** filters = NULL;
+ //int filter_max=0;
+ int filptr=0;
+ //
+ int makeindex_done=0; // lorsque l'index sera fait
+ FILE* makeindex_fp=NULL;
+ int makeindex_links=0;
+ char makeindex_firstlink[HTS_URLMAXSIZE*2];
+ // statistiques (mode #Z)
+ FILE* makestat_fp=NULL; // fichier de stats taux transfert
+ FILE* maketrack_fp=NULL; // idem pour le tracking
+ TStamp makestat_time=0; // attente (secondes)
+ LLint makestat_total=0; // repère du nombre d'octets transférés depuis denrière stat
+ int makestat_lnk=0; // idem, pour le nombre de liens
+ //
+ char codebase[HTS_URLMAXSIZE*2]; // base pour applet java
+ char base[HTS_URLMAXSIZE*2]; // base pour les autres fichiers
+ //
+ cache_back cache;
+ robots_wizard robots; // gestion robots.txt
+ inthash cache_hashtable=NULL;
+ int cache_hash_size=0;
+ //
+ char *template_header=NULL,*template_body=NULL,*template_footer=NULL;
+ //
+ codebase[0]='\0'; base[0]='\0';
+ //
+ cookie.auth.next=NULL;
+ cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
+ //
+
+ // noter heure actuelle de départ en secondes
+ memset(&HTS_STAT, 0, sizeof(HTS_STAT));
+ HTS_STAT.stat_timestart=time_local();
+ //istat_timestart=stat_timestart;
+ HTS_STAT.istat_timestart[0]=HTS_STAT.istat_timestart[1]=mtime_local();
+ /* reset stats */
+ HTS_STAT.HTS_TOTAL_RECV=0;
+ HTS_STAT.istat_bytes[0]=HTS_STAT.istat_bytes[1]=0;
+ if (opt.aff_progress)
+ lastime=HTS_STAT.stat_timestart;
+ if (opt.shell) {
+ last_info_shell=HTS_STAT.stat_timestart;
+ }
+ if ((opt.makestat) || (opt.maketrack)){
+ makestat_time=HTS_STAT.stat_timestart;
+ }
+ // initialiser compteur erreurs
+ fspc(NULL,NULL);
+
+ // initialiser cookie
+ if (opt.accept_cookie) {
+ opt.cookie=&cookie;
+ cookie.max_len=30000; // max len
+ strcpy(cookie.data,"");
+ // Charger cookies.txt par défaut ou cookies.txt du miroir
+ if (fexist(fconcat(opt.path_log,"cookies.txt")))
+ cookie_load(opt.cookie,opt.path_log,"cookies.txt");
+ else if (fexist("cookies.txt"))
+ cookie_load(opt.cookie,"","cookies.txt");
+ } else
+ opt.cookie=NULL;
+
+ // initialiser exit_xh
+ exit_xh=0; // sortir prématurément (var globale)
+
+ // initialiser usercommand
+ usercommand(opt.sys_com_exec,opt.sys_com,"");
+
+ // initialiser structcheck
+ structcheck_init(1);
+
+ // initialiser tableau options accessible par d'autres fonctions (signal)
+ hts_declareoptbuffer(&opt);
+
+ // initialiser verif_backblue
+ verif_backblue(NULL);
+ verif_external(0,0);
+ verif_external(1,0);
+
+ // et templates html
+ template_header=readfile_or(fconcat(opt.path_bin,"templates/index-header.html"),HTS_INDEX_HEADER);
+ template_body=readfile_or(fconcat(opt.path_bin,"templates/index-body.html"),HTS_INDEX_BODY);
+ template_footer=readfile_or(fconcat(opt.path_bin,"templates/index-footer.html"),HTS_INDEX_FOOTER);
+
+ // initialiser mimedefs
+ get_userhttptype(1,opt.mimedefs,NULL);
+
+ // Initialiser indexation
+ if (opt.kindex)
+ index_init(opt.path_html);
+
+ // effacer bloc cache
+ memset(&cache, 0, sizeof(cache_back));
+ cache.type=opt.cache; // cache?
+ cache.errlog=opt.errlog; // err log?
+ cache.ptr_ant=cache.ptr_last=0; // pointeur pour anticiper
+
+ // initialiser hash cache
+ if (!cache_hash_size)
+ cache_hash_size=HTS_HASH_SIZE;
+ cache_hashtable=inthash_new(cache_hash_size);
+ if (cache_hashtable==NULL) {
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ filters[0]=NULL; back_max=0; // uniquement a cause du warning de XH_extuninit
+ XH_extuninit;
+ return 0;
+ }
+ cache.hashtable=(void*)cache_hashtable; /* copy backcache hash */
+
+ // initialiser cache DNS
+ _hts_lockdns(-999);
+
+ // robots.txt
+ strcpy(robots.adr,"!"); // dummy
+ robots.token[0]='\0';
+ robots.next=NULL; // suivant
+ opt.robotsptr = &robots;
+
+ // effacer filters
+ opt.maxfilter = maximum(opt.maxfilter, 128);
+ if (filters_init(&filters, opt.maxfilter, 0) == 0) {
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ back_max=0; // uniquement a cause du warning de XH_extuninit
+ XH_extuninit;
+ return 0;
+ }
+ opt.filters.filters=&filters;
+ //
+ opt.filters.filptr=&filptr;
+ //opt.filters.filter_max=&filter_max;
+
+ // tableau de pointeurs sur les liens
+ lien_max=maximum(opt.maxlink,32);
+ liens=(lien_url**) malloct(lien_max*sizeof(lien_url*)); // tableau de pointeurs sur les liens
+ if (liens==NULL) {
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ //XH_uninit;
+ return 0;
+ } else {
+ int i;
+ for(i=0;i<lien_max;i++) {
+ liens[i]=NULL;
+ }
+ }
+ // initialiser ptr et lien_tot
+ ptr=0;
+ lien_tot=0;
+#if HTS_HASH
+ // initialiser hachage
+ {
+ int i;
+ for(i=0;i<HTS_HASH_SIZE;i++)
+ hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1; // pas d'entrées
+ hash.liens = liens;
+ hash.max_lien=0;
+ }
+#endif
+
+
+ // copier adresse(s) dans liste des adresses
+ {
+ char *a=url1;
+ int primary_len=8192;
+ if (strnotempty(opt.filelist)) {
+ primary_len+=max(0,fsize(opt.filelist)*2);
+ }
+ primary_len+=strlen(url1)*2;
+
+ // création de la première page, qui contient les liens de base à scanner
+ // c'est plus propre et plus logique que d'entrer à la main les liens dans la pile
+ // on bénéficie ainsi des vérifications et des tests du robot pour les liens "primaires"
+ primary=(char*) malloct(primary_len);
+ if (primary) {
+ primary[0]='\0';
+ } else {
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ back_max=0; // uniquement a cause du warning de XH_extuninit
+ XH_extuninit;
+ return 0;
+ }
+
+ while(*a) {
+ int i;
+ int joker=0;
+
+ // vérifier qu'il n'y a pas de * dans l'url
+ if (*a=='+')
+ joker=1;
+ else if (*a=='-')
+ joker=1;
+ /* NON, certaines URL ont des * (!)
+ else {
+ int i=0;
+ while((a[i]!=0) && (a[i]!=' ')) if (a[i++]=='*') joker=1;
+ }
+ */
+
+ if (joker) { // joker ou filters
+ //char* p;
+ char tempo[HTS_URLMAXSIZE*2];
+ int type; int plus=0;
+
+ // noter joker (dans b)
+ if (*a=='+') { // champ +
+ type=1; plus=1; a++;
+ } else if (*a=='-') { // champ forbidden[]
+ type=0; a++;
+ } else { // champ + avec joker sans doute
+ type=1;
+ }
+
+ // recopier prochaine chaine (+ ou -)
+ i=0;
+ while((*a!=0) && (*a!=' ')) { tempo[i++]=*a; a++; }
+ tempo[i++]='\0';
+ while(*a==' ') { a++; }
+
+ // sauter les + sans rien après..
+ if (strnotempty(tempo)) {
+ if ((plus==0) && (type==1)) { // implicite: *www.edf.fr par exemple
+ if (tempo[strlen(tempo)-1]!='*') {
+ strcat(tempo,"*"); // ajouter un *
+ }
+ }
+ if (type)
+ strcpy(filters[filptr],"+");
+ else
+ strcpy(filters[filptr],"-");
+ /*
+ if (strfield(tempo,"http://"))
+ strcat(filters[filptr],tempo+7); // ignorer http://
+ else if (strfield(tempo,"ftp://"))
+ strcat(filters[filptr],tempo+6); // ignorer ftp://
+ else
+ */
+ strcat(filters[filptr],tempo);
+ filptr++;
+
+ /* sanity check */
+ if (filptr + 1 >= opt.maxfilter) {
+ opt.maxfilter += HTS_FILTERSINC;
+ if (filters_init(&filters, opt.maxfilter, HTS_FILTERSINC) == 0) {
+ printf("PANIC! : Too many filters : >%d [%d]\n",filptr,__LINE__);
+ if (opt.errlog) {
+ fprintf(opt.errlog,LF"Too many filters, giving up..(>%d)"LF,filptr);
+ fprintf(opt.errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
+ test_flush;
+ }
+ back_max=0; // uniquement a cause du warning de XH_extuninit
+ XH_extuninit;
+ return 0;
+ }
+ //opt.filters.filters=filters;
+ }
+
+ }
+
+ } else { // adresse normale
+ char url[HTS_URLMAXSIZE*2];
+ // prochaine adresse
+ i=0;
+ while((*a!=0) && (*a!=' ')) { url[i++]=*a; a++; }
+ while(*a==' ') { a++; }
+ url[i++]='\0';
+
+ //strcat(primary,"<PRIMARY=\"");
+ if (strstr(url,":/")==NULL)
+ strcat(primary,"http://");
+ strcat(primary,url);
+ //strcat(primary,"\">");
+ strcat(primary,"\n");
+ }
+ } // while
+
+ /* load URL file list */
+ /* OPTIMIZED for fast load */
+ if (strnotempty(opt.filelist)) {
+ char* filelist_buff=NULL;
+ int filelist_sz=fsize(opt.filelist);
+ if (filelist_sz>0) {
+ FILE* fp=fopen(opt.filelist,"rb");
+ if (fp) {
+ filelist_buff=malloct(filelist_sz + 2);
+ if (filelist_buff) {
+ if ((int)fread(filelist_buff,1,filelist_sz,fp) != filelist_sz) {
+ freet(filelist_buff);
+ filelist_buff=NULL;
+ } else {
+ *(filelist_buff + filelist_sz) = '\0';
+ }
+ }
+ fclose(fp);
+ }
+ }
+
+ if (filelist_buff) {
+ int filelist_ptr=0;
+ int n=0;
+ char line[HTS_URLMAXSIZE*2];
+ char* primary_ptr = primary + strlen(primary);
+ while( filelist_ptr < filelist_sz ) {
+ int count=binput(filelist_buff+filelist_ptr,line,HTS_URLMAXSIZE);
+ filelist_ptr+=count;
+ if (count && line[0]) {
+ n++;
+ if (strstr(line,":/")==NULL) {
+ strcpy(primary_ptr, "http://");
+ primary_ptr += strlen(primary_ptr);
+ }
+ strcpy(primary_ptr, line);
+ primary_ptr += strlen(primary_ptr);
+ strcpy(primary_ptr, "\n");
+ primary_ptr += 1;
+ }
+ }
+ // fclose(fp);
+ if (opt.log!=NULL) {
+ fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush;
+ }
+
+ // Free buffer
+ freet(filelist_buff);
+ } else {
+ if (opt.errlog!=NULL) {
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush;
+ }
+ }
+ }
+
+
+ // lien primaire
+ liens_record("primary","/primary","primary.html","","");
+ if (liens[lien_tot]==NULL) { // erreur, pas de place réservée
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
+ test_flush;
+ }
+ back_max=0; // uniquement a cause du warning de XH_extuninit
+ XH_extuninit; // désallocation mémoire & buffers
+ return 0;
+ }
+ liens[lien_tot]->testmode=0; // pas mode test
+ liens[lien_tot]->link_import=0; // pas mode import
+ liens[lien_tot]->depth=opt.depth+1; // lien de priorité maximale
+ liens[lien_tot]->pass2=0; // 1ère passe
+ liens[lien_tot]->retry=opt.retry; // lien de priorité maximale
+ liens[lien_tot]->premier=lien_tot; // premier lien, objet-père=objet
+ liens[lien_tot]->precedent=lien_tot; // lien précédent
+ lien_tot++;
+
+ // Initialiser cache
+ cache_init(&cache,&opt);
+ }
+
+#if BDEBUG==3
+ {
+ int i;
+ for(i=0;i<lien_tot;i++) {
+ printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
+ }
+ for(i=0;i<filptr;i++) {
+ printf("%d>filters=%s\n",i,filters[i]);
+ }
+ }
+#endif
+
+ // backing
+ //soc_max=opt.maxsoc;
+ if (opt.maxsoc>0) {
+#if BDEBUG==2
+ _CLRSCR;
+#endif
+ // Nombre de fichiers HTML pouvant être présents en mémoire de manière simultannée
+ // On prévoit large: les fichiers HTML ne prennent que peu de place en mémoire, et les
+ // fichiers non html sont sauvés en direct sur disque.
+ // --> 1024 entrées + 32 entrées par socket en supplément
+ back_max=opt.maxsoc*32+1024;
+ //back_max=opt.maxsoc*8+32;
+ back=(lien_back*) calloct((back_max+1),sizeof(lien_back));
+ if (back==NULL) {
+ if (opt.errlog)
+ fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(int)((opt.maxsoc+1)*sizeof(lien_back)));
+ return 0;
+ } else { // copier buffer-location & effacer
+ int i;
+ for(i=0;i<back_max;i++){
+ back[i].r.location=back[i].location_buffer;
+ back[i].status=-1;
+ back[i].r.soc=INVALID_SOCKET;
+ }
+ }
+ }
+
+
+ // flush
+ test_flush;
+
+ // statistiques
+ if (opt.makestat) {
+ makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb");
+ if (makestat_fp != NULL) {
+ fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
+ }
+ }
+
+ // tracking -- débuggage
+ if (opt.maketrack) {
+ maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb");
+ if (maketrack_fp != NULL) {
+ fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
+ }
+ }
+
+ // on n'a pas de liens!! (exemple: httrack www.* impossible sans départ..)
+ if (lien_tot<=0) {
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
+ }
+ }
+
+
+ // attendre une certaine heure..
+ if (opt.waittime>0) {
+ int rollover=0;
+ int ok=0;
+ {
+ TStamp tl=0;
+ time_t tt;
+ struct tm* A;
+ tt=time(NULL);
+ A=localtime(&tt);
+ tl+=A->tm_sec;
+ tl+=A->tm_min*60;
+ tl+=A->tm_hour*60*60;
+ if (tl>opt.waittime) // attendre minuit
+ rollover=1;
+ }
+
+ // attendre..
+ do {
+ TStamp tl=0;
+ time_t tt;
+ struct tm* A;
+ tt=time(NULL);
+ A=localtime(&tt);
+ tl+=A->tm_sec;
+ tl+=A->tm_min*60;
+ tl+=A->tm_hour*60*60;
+
+ if (rollover) {
+ if (tl<=opt.waittime)
+ rollover=0; // attendre heure
+ } else {
+ if (tl>opt.waittime)
+ ok=1; // ok!
+ }
+
+#if HTS_ANALYSTE
+ {
+ int r;
+ if (rollover)
+ r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl+24*3600),NULL);
+ else
+ r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl),NULL);
+ if (!r) {
+ exit_xh=1; // exit requested
+ ok=1;
+ } else
+ Sleep(100);
+ }
+#endif
+ } while(!ok);
+
+ // note: recopie de plus haut
+ // noter heure actuelle de départ en secondes
+ HTS_STAT.stat_timestart=time_local();
+ if (opt.aff_progress)
+ lastime=HTS_STAT.stat_timestart;
+ if (opt.shell) {
+ last_info_shell=HTS_STAT.stat_timestart;
+ }
+ if ((opt.makestat) || (opt.maketrack)){
+ makestat_time=HTS_STAT.stat_timestart;
+ }
+
+
+ }
+ /* Info for wrappers */
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"engine: start"LF);
+ }
+#if HTS_ANALYSTE
+ if (!hts_htmlcheck_start(&opt)) {
+ XH_extuninit;
+ return 1;
+ }
+#endif
+
+
+ // ------------------------------------------------------------
+
+ // ------------------------------------------------------------
+ // Boucle générale de parcours des liens
+ // ------------------------------------------------------------
+ do {
+ int error=0; // si error alors sauter
+ int store_errpage=0; // c'est une erreur mais on enregistre le html
+ char loc[HTS_URLMAXSIZE*2]; // adresse de relocation
+
+ // Ici on charge le fichier (html, gif..) en mémoire
+ // Les HTMLs sont traités (si leur priorité est suffisante)
+
+ // effacer r
+ memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
+ r.location=loc; // en cas d'erreur 3xx (moved)
+ // recopier proxy
+ memcpy(&(r.req.proxy), &opt.proxy, sizeof(opt.proxy));
+ // et user-agent
+ strcpy(r.req.user_agent,opt.user_agent);
+ r.req.user_agent_send=opt.user_agent_send;
+
+ if (!error) {
+
+ // Skip empty/invalid/done in background
+ if (liens[ptr]) {
+ while ( (liens[ptr]) && (
+ ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
+ ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
+ ( (liens[ptr]->pass2 == -1) )
+ )
+ ) { // sauter si lien annulé (ou fil vide)
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
+ test_flush;
+ }
+ ptr++;
+ }
+ }
+ if (liens[ptr]) { // on a qq chose à récupérer?
+
+ if ( (opt.debug>1) && (opt.log!=NULL) ) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil);
+ test_flush;
+#if DEBUG_ROBOTS
+ if (strcmp(urlfil,"/robots.txt") == 0) {
+ printf("robots.txt detected\n");
+ }
+#endif
+ }
+ // ------------------------------------------------------------
+ // DEBUT --RECUPERATION LIEN---
+ if (ptr==0) { // premier lien à parcourir: lien primaire construit avant
+ r.adr=primary; primary=NULL;
+ r.statuscode=200;
+ r.size=strlen(r.adr);
+ r.soc=INVALID_SOCKET;
+ strcpy(r.contenttype,"text/html");
+ /*} else if (opt.maxsoc<=0) { // fichiers 1 à 1 en attente (pas de backing)
+ // charger le fichier en mémoire tout bêtement
+ r=xhttpget(urladr,urlfil);
+ //
+ */
+ } else { // backing, multiples sockets
+ //
+ int b;
+ int n;
+
+#if BDEBUG==1
+ printf("\nBack test..\n");
+#endif
+
+ // pause/lock files
+ {
+ int do_pause=0;
+
+ // user pause lockfile : create hts-paused.lock --> HTTrack will be paused
+ if (fexist(fconcat(opt.path_log,"hts-stop.lock"))) {
+ // remove lockfile
+ remove(fconcat(opt.path_log,"hts-stop.lock"));
+ if (!fexist(fconcat(opt.path_log,"hts-stop.lock"))) {
+ do_pause=1;
+ }
+ }
+
+ // after receving N bytes, pause
+ if (opt.fragment>0) {
+ if ((HTS_STAT.stat_bytes-stat_fragment) > opt.fragment) {
+ do_pause=1;
+ }
+ }
+
+ // pause?
+ if (do_pause) {
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"engine: pause requested.."LF);
+ }
+ while (back_nsoc(back,back_max)>0) { // attendre fin des transferts
+ back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
+ Sleep(200);
+#if HTS_ANALYSTE
+ {
+ back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
+
+ // Transfer rate
+ engine_stats();
+
+ // Refresh various stats
+ HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
+ HTS_STAT.stat_errors=fspc(NULL,"error");
+ HTS_STAT.stat_warnings=fspc(NULL,"warning");
+ HTS_STAT.stat_infos=fspc(NULL,"info");
+ HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
+ HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
+
+ b=0;
+ if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
+ if (opt.errlog) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
+ test_flush;
+ }
+ exit_xh=1; // exit requested
+ XH_uninit;
+ return 0;
+ }
+ }
+#endif
+ }
+ // On désalloue le buffer d'enregistrement des chemins créée, au cas où pendant la pause
+ // l'utilisateur ferait un rm -r après avoir effectué un tar
+ structcheck_init(1);
+ {
+ FILE* fp = fopen(fconcat(opt.path_log,"hts-paused.lock"),"wb");
+ if (fp) {
+ fspc(fp,"info"); // dater
+ fprintf(fp,"Pause"LF"HTTrack is paused after retreiving "LLintP" bytes"LF"Delete this file to continue the mirror..."LF""LF"",HTS_STAT.stat_bytes);
+ fclose(fp);
+ }
+ }
+ stat_fragment=HTS_STAT.stat_bytes;
+ /* Info for wrappers */
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"engine: pause: %s"LF,fconcat(opt.path_log,"hts-paused.lock"));
+ }
+#if HTS_ANALYSTE
+ hts_htmlcheck_pause(fconcat(opt.path_log,"hts-paused.lock"));
+#else
+ while (fexist(fconcat(opt.path_log,"hts-paused.lock"))) {
+ //back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart); inutile!! (plus de sockets actives)
+ Sleep(1000);
+ }
+#endif
+ }
+ //
+ }
+ // end of pause/lock files
+
+#if HTS_ANALYSTE
+ // changement dans les préférences
+/*
+ if (_hts_setopt) {
+ copy_htsopt(_hts_setopt,&opt); // copier au besoin
+ _hts_setopt=NULL; // effacer callback
+ }
+*/
+ if (_hts_addurl) {
+ char add_adr[HTS_URLMAXSIZE*2];
+ char add_fil[HTS_URLMAXSIZE*2];
+ while(*_hts_addurl) {
+ char add_url[HTS_URLMAXSIZE*2];
+ add_adr[0]=add_fil[0]=add_url[0]='\0';
+ if (!link_has_authority(*_hts_addurl))
+ strcpy(add_url,"http://"); // ajouter http://
+ strcat(add_url,*_hts_addurl);
+ if (ident_url_absolute(add_url,add_adr,add_fil)>=0) {
+ // ----Ajout----
+ // noter NOUVEAU lien
+ char add_sav[HTS_URLMAXSIZE*2];
+ // calculer lien et éventuellement modifier addresse/fichier
+ 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) {
+ if (hash_read(&hash,add_sav,"",0)<0) { // n'existe pas déja
+ // enregistrer lien (MACRO)
+ liens_record(add_adr,add_fil,add_sav,"","");
+ if (liens[lien_tot]!=NULL) { // OK, pas d'erreur
+ liens[lien_tot]->testmode=0; // mode test?
+ liens[lien_tot]->link_import=0; // mode normal
+ liens[lien_tot]->depth=opt.depth;
+ liens[lien_tot]->pass2=max(0,numero_passe);
+ liens[lien_tot]->retry=opt.retry;
+ liens[lien_tot]->premier=lien_tot;
+ liens[lien_tot]->precedent=lien_tot;
+ lien_tot++;
+ //
+ if ((opt.debug>0) && (opt.log!=NULL)) {
+ fspc(opt.log,"info"); fprintf(opt.log,"Link added by user: %s%s"LF,add_adr,add_fil); test_flush;
+ }
+ //
+ } else { // oups erreur, plus de mémoire!!
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
+ test_flush;
+ }
+ //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
+ XH_uninit; // désallocation mémoire & buffers
+ return 0;
+ }
+ } else {
+ if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Existing link %s%s not added after user request"LF,add_adr,add_fil);
+ test_flush;
+ }
+ }
+
+ }
+ } else {
+ if (opt.errlog) {
+ fspc(opt.errlog,"error");
+ fprintf(opt.errlog,"Error during URL decoding for %s"LF,add_url);
+ test_flush;
+ }
+ }
+ // ----Fin Ajout----
+ _hts_addurl++; // suivante
+ }
+ _hts_addurl=NULL; // libérer _hts_addurl
+ }
+ // si une pause a été demandée
+ if (_hts_setpause) {
+ // index du lien actuel
+ int b=back_index(back,back_max,urladr,urlfil,savename);
+ if (b<0) b=0; // forcer pour les stats
+ while(_hts_setpause) { // on fait la pause..
+ back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
+
+ // Transfer rate
+ engine_stats();
+
+ // Refresh various stats
+ HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
+ HTS_STAT.stat_errors=fspc(NULL,"error");
+ HTS_STAT.stat_warnings=fspc(NULL,"warning");
+ HTS_STAT.stat_infos=fspc(NULL,"info");
+ HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
+ HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
+
+ if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
+ if (opt.errlog) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
+ test_flush;
+ }
+ exit_xh=1; // exit requested
+ XH_uninit;
+ return 0;
+ }
+ if (back_nsoc(back,back_max)==0)
+ Sleep(250); // tite pause
+ }
+ }
+#endif
+
+ // si le fichier n'est pas en backing, le mettre..
+ if (!back_exist(back,back_max,urladr,urlfil,savename)) {
+#if BDEBUG==1
+ printf("crash backing: %s%s\n",liens[ptr]->adr,liens[ptr]->fil);
+#endif
+ 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) {
+ printf("PANIC! : Crash adding error, unexpected error found.. [%d]\n",__LINE__);
+#if BDEBUG==1
+ printf("error while crash adding\n");
+#endif
+ if (opt.errlog) {
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unexpected backing error for %s%s"LF,urladr,urlfil);
+ test_flush;
+ }
+
+ }
+ }
+
+#if BDEBUG==1
+ printf("test number of socks\n");
+#endif
+
+ // ajouter autant de socket qu'on peut ajouter
+ n=opt.maxsoc-back_nsoc(back,back_max);
+#if BDEBUG==1
+ printf("%d sockets available for backing\n",n);
+#endif
+
+#if HTS_ANALYSTE
+ if ((n>0) && (!_hts_setpause)) { // si sockets libre et pas en pause, ajouter
+#else
+ if (n>0) { // si sockets libre
+#endif
+ // remplir autant que l'on peut le cache (backing)
+ back_fillmax(back,back_max,&opt,&cache,liens,ptr,numero_passe,lien_tot);
+ }
+
+ // index du lien actuel
+/*
+ b=back_index(back,back_max,urladr,urlfil,savename);
+
+ if (b>=0)
+*/
+ {
+ // ------------------------------------------------------------
+ // attendre que le fichier actuel soit prêt - BOUCLE D'ATTENTE
+ do {
+
+ // index du lien actuel
+ b=back_index(back,back_max,urladr,urlfil,savename);
+#if BDEBUG==1
+ printf("back index %d, waiting\n",b);
+#endif
+ // Continue to the loop if link still present
+ if (b<0)
+ continue;
+
+ // Receive data
+ if (back[b].status>0)
+ back_wait(back,back_max,&opt,&cache,HTS_STAT.stat_timestart);
+
+ // Continue to the loop if link still present
+ b=back_index(back,back_max,urladr,urlfil,savename);
+ if (b<0)
+ continue;
+
+ // And fill the backing stack
+ if (back[b].status>0)
+ back_fillmax(back,back_max,&opt,&cache,liens,ptr,numero_passe,lien_tot);
+
+ // Continue to the loop if link still present
+ b=back_index(back,back_max,urladr,urlfil,savename);
+ if (b<0)
+ continue;
+
+ // autres occupations de HTTrack: statistiques, boucle d'attente, etc.
+ if ((opt.makestat) || (opt.maketrack)) {
+ TStamp l=time_local();
+ if ((int) (l-makestat_time) >= 60) {
+ if (makestat_fp != NULL) {
+ fspc(makestat_fp,"info");
+ fprintf(makestat_fp,"Rate= %d (/"LLintP") \11NewLinks= %d (/%d)"LF,(int) ((HTS_STAT.HTS_TOTAL_RECV-makestat_total)/(l-makestat_time)), HTS_STAT.HTS_TOTAL_RECV,(int) lien_tot-makestat_lnk,(int) lien_tot);
+ fflush(makestat_fp);
+ makestat_total=HTS_STAT.HTS_TOTAL_RECV;
+ makestat_lnk=lien_tot;
+ }
+ if (maketrack_fp!=NULL) {
+ int i;
+ fspc(maketrack_fp,"info"); fprintf(maketrack_fp,LF);
+ for(i=0;i<back_max;i++) {
+ back_info(back,i,3,maketrack_fp);
+ }
+ fprintf(maketrack_fp,LF);
+
+ }
+ makestat_time=l;
+ }
+ }
+#if HTS_ANALYSTE
+ {
+ int i;
+ {
+ char* s=hts_cancel_file("");
+ if (strnotempty(s)) { // fichier à canceller
+ for(i=0;i<back_max;i++) {
+ if ((back[i].status>0)) {
+ if (strcmp(back[i].url_sav,s)==0) { // ok trouvé
+ if (back[i].status != 1000) {
+#if HTS_DEBUG_CLOSESOCK
+ DEBUG_W("user cancel: deletehttp\n");
+#endif
+ if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
+ back[i].r.soc=INVALID_SOCKET;
+ back[i].r.statuscode=-1;
+ strcpy(back[i].r.msg,"Cancelled by User");
+ back[i].status=0; // terminé
+ } else // cancel ftp.. flag à 1
+ back[i].stop_ftp = 1;
+ }
+ }
+ }
+ s[0]='\0';
+ }
+ }
+
+ // Transfer rate
+ engine_stats();
+
+ // Refresh various stats
+ HTS_STAT.stat_nsocket=back_nsoc(back,back_max);
+ HTS_STAT.stat_errors=fspc(NULL,"error");
+ HTS_STAT.stat_warnings=fspc(NULL,"warning");
+ HTS_STAT.stat_infos=fspc(NULL,"info");
+ HTS_STAT.nbk=backlinks_done(liens,lien_tot,ptr);
+ HTS_STAT.nb=back_transfered(HTS_STAT.stat_bytes,back,back_max);
+
+ if (!hts_htmlcheck_loop(back,back_max,b,ptr,lien_tot,(int) (time_local()-HTS_STAT.stat_timestart),&HTS_STAT)) {
+ if (opt.errlog) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
+ test_flush;
+ }
+ exit_xh=1; // exit requested
+ XH_uninit;
+ return 0;
+ }
+ }
+
+#endif
+#if HTS_POLL
+ if ((opt.shell) || (opt.keyboard) || (opt.verbosedisplay) || (!opt.quiet)) {
+ TStamp tl;
+ info_shell=1;
+
+ /* Toggle with ENTER */
+ if (!opt.quiet) {
+ if (check_stdin()) {
+ char com[256];
+ linput(stdin,com,200);
+ if (opt.verbosedisplay==2)
+ opt.verbosedisplay=1;
+ else
+ opt.verbosedisplay=2;
+ /* Info for wrappers */
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"engine: change-options"LF);
+ }
+#if HTS_ANALYSTE
+ hts_htmlcheck_chopt(&opt);
+#endif
+ }
+ }
+
+ /*
+ ..useless..
+ while (check_stdin()) { // données disponibles
+ char com[256];
+ com[0]='\0';
+
+ if (!rcvd) rcvd=1;
+ linput(stdin,com,256);
+
+ if (strnotempty(com)) {
+ if (strlen(com)<=2) {
+ switch(*com) {
+ case '?': { // Status?
+ if (back[b].status>0) printf("WAIT\n");
+ else printf("READY\n");
+ }
+ break;
+ case 'f': { // Fichier en attente?
+ if (back[b].status>0) printf("WAIT %s\n",back[b].url_fil);
+ else printf("READY %s\n",back[b].url_fil);
+ }
+ break;
+ case 'A': case 'F': { // filters
+ int i;
+ for(i=0;i<filptr;i++) {
+ printf("%s ",filters[i]);
+ }
+ printf("\n");
+ }
+ break;
+ case '#': { // Afficher statistique sur le nombre de liens, etc
+ switch(*(com+1)) {
+ case 'l': printf("%d\n",lien_tot); break; // nombre de liens enregistrés
+ case 's': printf("%d\n",back_nsoc(back,back_max)); break; // nombre de sockets
+ case 'r': printf("%d\n",(int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-HTS_STAT.stat_timestart))); break; // taux de transfert
+ }
+ }
+ break;
+ case 'K': if (*(com+1)=='!') { // Kill
+ XH_uninit;
+ return -1;
+ }
+ break;
+ case 'X': if (*(com+1)=='!') { // exit
+ exit_xh=1;
+ }
+ break;
+ case 'I': if (*(com+1)=='+') info_shell=1; else info_shell=0;
+ break;
+ }
+ io_flush;
+ } else if (*com=='@') {
+ printf("%s\n",com+1);
+ io_flush;
+ }
+ }
+
+ } // while
+ */
+ tl=time_local();
+
+ // générer un message d'infos sur l'état actuel
+ if (opt.shell) { // si shell
+ if ((tl-last_info_shell)>0) { // toute les 1 sec
+ FILE* fp=stdout;
+ int a=0;
+ last_info_shell=tl;
+ if (fexist(fconcat(opt.path_log,"hts-autopsy"))) { // débuggage: teste si le robot est vivant
+ // (oui je sais un robot vivant.. mais bon.. il a le droit de vivre lui aussi)
+ // (libérons les robots esclaves de l'internet!)
+ remove(fconcat(opt.path_log,"hts-autopsy"));
+ fp=fopen(fconcat(opt.path_log,"hts-isalive"),"wb");
+ a=1;
+ }
+ if ((info_shell) || a) {
+ int i,j;
+
+ fprintf(fp,"TIME %d"LF,(int) (tl-HTS_STAT.stat_timestart));
+ fprintf(fp,"TOTAL %d"LF,(int) HTS_STAT.stat_bytes);
+ fprintf(fp,"RATE %d"LF,(int) (HTS_STAT.HTS_TOTAL_RECV/(tl-HTS_STAT.stat_timestart)));
+ fprintf(fp,"SOCKET %d"LF,back_nsoc(back,back_max));
+ fprintf(fp,"LINK %d"LF,lien_tot);
+ {
+ LLint mem=0;
+ for(i=0;i<back_max;i++)
+ if (back[i].r.adr!=NULL)
+ mem+=back[i].r.size;
+ fprintf(fp,"INMEM "LLintP""LF,mem);
+ }
+ for(j=0;j<2;j++) { // passes pour ready et wait
+ for(i=0;i<back_max;i++) {
+ back_info(back,i,j+1,stdout); // maketrack_fp a la place de stdout ?? // **
+ }
+ }
+ fprintf(fp,LF);
+ if (a)
+ fclose(fp);
+ io_flush;
+ }
+ }
+ } // si shell
+
+ } // si shell ou keyboard (option)
+ //
+#endif
+ } while((b>=0) && (back[max(b,0)].status>0));
+
+
+ // If link not found on the stack, it's because it has already been downloaded
+ // in background
+ // Then, skip it and go to the next one
+ if (b<0) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"link #%d is ready, no more on the stack, skipping: %s%s.."LF,ptr,urladr,urlfil);
+ test_flush;
+ }
+
+ // prochain lien
+ // ptr++;
+
+ // Jump to 'continue'
+ // This is one of the very very rare cases where goto
+ // is acceptable
+ // A supplemental flag and if( ) { } would be really messy
+ goto jump_if_done;
+ }
+
+
+#if HTS_ANALYSTE==2
+#else
+ //if (!opt.quiet) { // petite animation
+ if (!opt.verbosedisplay) {
+ if (!opt.quiet) {
+ static int roll=0; /* static: ok */
+ roll=(roll+1)%4;
+ printf("%c\x0d",("/-\\|")[roll]);
+ fflush(stdout);
+ }
+ } else if (opt.verbosedisplay==1) {
+ if (back[b].r.statuscode==200)
+ printf("%d/%d: %s%s ("LLintP" bytes) - OK\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,back[b].r.size);
+ else
+ printf("%d/%d: %s%s ("LLintP" bytes) - %d\33[K\r",ptr,lien_tot,back[b].url_adr,back[b].url_fil,back[b].r.size,back[b].r.statuscode);
+ fflush(stdout);
+ }
+ //}
+#endif
+ // ------------------------------------------------------------
+ // Vérificateur d'intégrité
+#if DEBUG_CHECKINT
+ _CHECKINT(&back[b],"Retour de back_wait, après le while")
+ {
+ int i;
+ for(i=0;i<back_max;i++) {
+ char si[256];
+ sprintf(si,"Test global après back_wait, index %d",i);
+ _CHECKINT(&back[i],si)
+ }
+ }
+#endif
+
+ // copier structure réponse htsblk
+ memcpy(&r, &(back[b].r), sizeof(htsblk));
+ r.location=loc; // ne PAS copier location!! adresse, pas de buffer
+ if (back[b].r.location)
+ strcpy(r.location,back[b].r.location);
+ back[b].r.adr=NULL; // ne pas faire de desalloc ensuite
+
+ // libérer emplacement backing
+ back_delete(back,b);
+
+ // progression
+ if (opt.aff_progress) {
+ TStamp tl=time_local();
+ if ((tl-HTS_STAT.stat_timestart)>0) {
+ char s[32];
+ int i=0;
+ lastime=tl;
+ _CLRSCR; _GOTOXY("1","1");
+ printf("Rate=%d B/sec\n",(int) (HTS_STAT.HTS_TOTAL_RECV/(tl-HTS_STAT.stat_timestart)));
+ while(i<minimum(back_max,99)) { // **
+ if (back[i].status>=0) { // loading..
+ s[0]='\0';
+ if (strlen(back[i].url_fil)>16)
+ strcat(s,back[i].url_fil+strlen(back[i].url_fil)-16);
+ else
+ strncat(s,back[i].url_fil,16);
+ printf("%s : ",s);
+
+ printf("[");
+ if (back[i].r.totalsize>0) {
+ int p;
+ int j;
+ p=(int)((back[i].r.size*10)/back[i].r.totalsize);
+ p=minimum(10,p);
+ for(j=0;j<p;j++) printf("*");
+ for(j=0;j<(10-p);j++) printf("-");
+ } else {
+ printf(LLintP,back[i].r.size);
+ }
+ printf("]");
+
+ //} else if (back[i].status==0) {
+ // strcpy(s,"ENDED");
+ }
+ printf("\n");
+ i++;
+ }
+ io_flush;
+ }
+ }
+
+ // débug graphique
+#if BDEBUG==2
+ {
+ char s[12];
+ int i=0;
+ _GOTOXY(1,1);
+ printf("Rate=%d B/sec\n",(int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-HTS_STAT.stat_timestart)));
+ while(i<minimum(back_max,160)) {
+ if (back[i].status>0) {
+ sprintf(s,"%d",back[i].r.size);
+ } else if (back[i].status==0) {
+ strcpy(s,"ENDED");
+ } else
+ strcpy(s," - ");
+ while(strlen(s)<8) strcat(s," ");
+ printf("%s",s); io_flush;
+ i++;
+ }
+ }
+#endif
+
+
+#if BDEBUG==1
+ printf("statuscode=%d with %s / msg=%s\n",r.statuscode,r.contenttype,r.msg);
+#endif
+
+ }
+ /*else {
+#if BDEBUG==1
+ printf("back index error\n");
+#endif
+ }
+ */
+
+ }
+ // FIN --RECUPERATION LIEN---
+ // ------------------------------------------------------------
+
+
+
+ } else { // lien vide..
+ if (opt.errlog) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning, link #%d empty"LF,ptr); test_flush;
+ error=1;
+ }
+ } // test si url existe (non vide!)
+
+
+
+ // ---tester taille a posteriori---
+ // tester r.adr
+ if (!error) {
+ // erreur, pas de fichier chargé:
+ if ((!r.adr) && (r.is_write==0)
+ && (r.statuscode!=301)
+ && (r.statuscode!=302)
+ && (r.statuscode!=303)
+ && (r.statuscode!=307)
+ && (r.statuscode!=412)
+ && (r.statuscode!=416)
+ ) {
+ // error=1;
+
+ // peut être que le fichier était trop gros?
+ if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))
+ || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) {
+ error=0;
+ if (opt.errlog) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
+ test_flush;
+ }
+ }
+ // // // error=1; // ne pas traiter la suite -- euhh si finalement..
+ }
+ }
+ // ---fin tester taille a posteriori---
+
+
+ // --------------------
+ // BOGUS MIME TYPE HACK
+ // Check if we have a bogus MIME type
+ // example:
+ // Content-type="text/html"
+ // and
+ // Content-disposition="foo.jpg"
+ // --------------------
+ if (!error) {
+ if (r.statuscode == 200) { // OK (ou 304 en backing)
+ if (r.adr) { // Written file
+ if ( (is_hypertext_mime(r.contenttype)) /* Is HTML or Js, .. */
+ || (may_be_hypertext_mime(r.contenttype) && (r.adr) ) /* Is real media, .. */
+ ) {
+ if (strnotempty(r.cdispo)) { // Content-disposition set!
+ if (ishtml(savename) == 0) { // Non HTML!!
+ // patch it!
+ strcpy(r.contenttype,"application/octet-stream");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // ------------------------------------
+ // BOGUS MIME TYPE HACK II (the revenge)
+ // Check if we have a bogus MIME type
+ if ( (is_hypertext_mime(r.contenttype)) /* Is HTML or Js, .. */
+ || (may_be_hypertext_mime(r.contenttype)) /* Is real media, .. */
+ ) {
+ if ((r.adr) && (r.size)) {
+ unsigned int map[256];
+ int i;
+ unsigned int nspec = 0;
+ map_characters((unsigned char*)r.adr, (unsigned int)r.size, (unsigned int*)map);
+ for(i = 1 ; i < 32 ; i++) { // null chars ignored..
+ if (!is_realspace(i)
+ && i != 27 /* Damn you ISO2022-xx! */
+ ) {
+ nspec += map[i];
+ }
+ }
+ if ((nspec > r.size / 100) && (nspec > 10)) { // too many special characters
+ strcpy(r.contenttype,"application/octet-stream");
+ if (opt.errlog) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File not parsed, looks like binary: %s%s"LF,urladr,urlfil);
+ test_flush;
+ }
+ }
+ }
+ }
+
+ // --------------------
+ // REAL MEDIA HACK
+ // Check if we have to load locally the file
+ // --------------------
+ if (!error) {
+ if (r.statuscode == 200) { // OK (ou 304 en backing)
+ if (r.adr==NULL) { // Written file
+ if (may_be_hypertext_mime(r.contenttype)) { // to parse!
+ LLint sz;
+ sz=fsize(savename);
+ if (sz>0) { // ok, exists!
+ if (sz < 1024) { // ok, small file --> to parse!
+ FILE* fp=fopen(savename,"rb");
+ if (fp) {
+ r.adr=malloct((int)sz + 2);
+ if (r.adr) {
+ fread(r.adr,(int)sz,1,fp);
+ r.size=sz;
+ fclose(fp);
+ fp=NULL;
+ // remove (temporary) file!
+ remove(savename);
+ }
+ if (fp)
+ fclose(fp);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ // EN OF REAL MEDIA HACK
+
+
+ // ---stockage en cache---
+ // stocker dans le cache?
+ /*
+ if (!error) {
+ if (ptr>0) {
+ if (liens[ptr]) {
+ cache_mayadd(&opt,&cache,&r,urladr,urlfil,savename);
+ } else
+ error=1;
+ }
+ }
+ */
+ // ---fin stockage en cache---
+
+
+
+ // DEBUT rattrapage des 301,302,307..
+ // ------------------------------------------------------------
+ if (!error) {
+ ////////{
+ // on a chargé un fichier en plus
+ // if (!error) stat_loaded+=r.size;
+
+ // ------------------------------------------------------------
+ // Rattrapage des 301,302,307 (moved) et 412,416 - les 304 le sont dans le backing
+ // ------------------------------------------------------------
+ if ( (r.statuscode==301)
+ || (r.statuscode==302)
+ || (r.statuscode==303)
+ || (r.statuscode==307)
+ ) {
+ //if (r.adr!=NULL) { // adr==null si fichier direct. [catch: davename normalement si cgi]
+ //int i=0;
+ char *rn=NULL;
+ // char* p;
+
+ if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
+ //if (opt.errlog) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"%s for %s%s"LF,r.msg,urladr,urlfil);
+ test_flush;
+ }
+
+
+ {
+ char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2];
+ int get_it=0; // ne pas prendre le fichier à la même adresse par défaut
+ int reponse=0;
+ mov_url[0]='\0'; mov_adr[0]='\0'; mov_fil[0]='\0';
+ //
+
+ strcpy(mov_url,r.location);
+
+ // url qque -> adresse+fichier
+ if ((reponse=ident_url_relatif(mov_url,urladr,urlfil,mov_adr,mov_fil))>=0) {
+ int set_prio_to=0; // pas de priotité fixéd par wizard
+
+ //if (ident_url_absolute(mov_url,mov_adr,mov_fil)!=-1) { // ok URL reconnue
+ // c'est (en gros) la même URL..
+ // si c'est un problème de casse dans le host c'est que le serveur est buggé
+ // ("RFC says.." : host name IS case insensitive)
+ if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) { // identique à casse près
+ // on tourne en rond
+ if (strcmp(mov_fil,urlfil)==0) {
+ error=1;
+ get_it=-1; // ne rien faire
+ if (opt.errlog) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Can not bear crazy server (%s) for %s%s"LF,r.msg,urladr,urlfil);
+ test_flush;
+ }
+ } else { // mauvaise casse, effacer entrée dans la pile et rejouer une fois
+ get_it=1;
+ }
+ } else { // adresse différente
+ if (ishtml(mov_url)==0) { // pas même adresse MAIS c'est un fichier non html (pas de page moved possible)
+ // -> on prend à cette adresse, le lien sera enregistré avec lien_record() (hash)
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"wizard link test for moved file at %s%s.."LF,mov_adr,mov_fil);
+ test_flush;
+ }
+ // accepté?
+ if (hts_acceptlink(&opt,ptr,lien_tot,liens,
+ mov_adr,mov_fil,
+ &filters,&filptr,opt.maxfilter,
+ &robots,
+ &set_prio_to,
+ NULL) != 1) { /* nouvelle adresse non refusée ? */
+ get_it=1;
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"moved link accepted: %s%s"LF,mov_adr,mov_fil);
+ test_flush;
+ }
+ }
+ } /* sinon traité normalement */
+ }
+
+ //if ((strfield2(mov_adr,urladr)!=0) && (strfield2(mov_fil,urlfil)!=0)) { // identique à casse près
+ if (get_it==1) {
+ // court-circuiter le reste du traitement
+ // et reculer pour mieux sauter
+ if (opt.errlog) {
+ 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);
+ test_flush;
+ }
+ // canceller lien actuel
+ error=1;
+ strcpy(liens[ptr]->adr,"!"); // caractère bidon (invalide hash)
+#if HTS_HASH
+#else
+ liens[ptr]->sav_len=-1; // taille invalide
+#endif
+ // noter NOUVEAU lien
+ {
+ char mov_sav[HTS_URLMAXSIZE*2];
+ // calculer lien et éventuellement modifier addresse/fichier
+ 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) {
+ if (hash_read(&hash,mov_sav,"",0)<0) { // n'existe pas déja
+ // enregistrer lien (MACRO) avec SAV IDENTIQUE
+ liens_record(mov_adr,mov_fil,liens[ptr]->sav,"","");
+ //liens_record(mov_adr,mov_fil,mov_sav,"","");
+ if (liens[lien_tot]!=NULL) { // OK, pas d'erreur
+ // mode test?
+ liens[lien_tot]->testmode=liens[ptr]->testmode;
+ liens[lien_tot]->link_import=0; // mode normal
+ if (!set_prio_to)
+ liens[lien_tot]->depth=liens[ptr]->depth;
+ else
+ liens[lien_tot]->depth=max(0,min(set_prio_to-1,liens[ptr]->depth)); // PRIORITE NULLE (catch page)
+ liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
+ liens[lien_tot]->retry=liens[ptr]->retry;
+ liens[lien_tot]->premier=liens[ptr]->premier;
+ liens[lien_tot]->precedent=liens[ptr]->precedent;
+ lien_tot++;
+ } else { // oups erreur, plus de mémoire!!
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
+ test_flush;
+ }
+ //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
+ XH_uninit; // désallocation mémoire & buffers
+ return 0;
+ }
+ } else {
+ if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"moving %s to an existing file %s"LF,liens[ptr]->fil,urlfil);
+ test_flush;
+ }
+ }
+
+ }
+ }
+
+ //printf("-> %s %s %s\n",liens[lien_tot-1]->adr,liens[lien_tot-1]->fil,liens[lien_tot-1]->sav);
+
+ // note métaphysique: il se peut qu'il y ait un index.html et un INDEX.HTML
+ // sous DOS ca marche pas très bien... mais comme je suis génial url_savename()
+ // est à même de régler ce problème
+ }
+ } // ident_url_xx
+
+ 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)
+ rn=(char*) calloct(8192,1);
+ if (rn!=NULL) {
+ if (opt.errlog) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File has moved from %s%s to %s"LF,urladr,urlfil,mov_url);
+ test_flush;
+ }
+ escape_uri(mov_url);
+ // On prépare une page qui sautera immédiatement sur la bonne URL
+ // Le scanner re-changera, ensuite, cette URL, pour la mirrorer!
+ strcpy(rn,"<HTML>"CRLF);
+ strcat(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF);
+ strcat(rn,"<HEAD>"CRLF"<TITLE>Page has moved</TITLE>"CRLF"</HEAD>"CRLF"<BODY>"CRLF);
+ strcat(rn,"<META HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=");
+ strcat(rn,mov_url); // URL
+ strcat(rn,"\">"CRLF);
+ strcat(rn,"<A HREF=\"");
+ strcat(rn,mov_url);
+ strcat(rn,"\">");
+ strcat(rn,"<B>Click here...</B></A>"CRLF);
+ strcat(rn,"</BODY>"CRLF);
+ strcat(rn,"<!-- Created by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->"CRLF);
+ strcat(rn,"</HTML>"CRLF);
+
+ // changer la page
+ if (r.adr) { freet(r.adr); r.adr=NULL; }
+ r.adr=rn;
+ r.size=strlen(r.adr);
+ strcpy(r.contenttype,"text/html");
+ }
+ } // get_it==0
+
+ } // bloc
+ // erreur HTTP (ex: 404, not found)
+ } else if (
+ (r.statuscode==412)
+ || (r.statuscode==416)
+ ) { // Precondition Failed, c'est à dire pour nous redemander TOUT le fichier
+ if (fexist(liens[ptr]->sav)) {
+ remove(liens[ptr]->sav); // Eliminer
+ if (!fexist(liens[ptr]->sav)) { // Bien éliminé? (sinon on boucle..)
+#if HDEBUG
+ printf("Partial content NOT up-to-date, reget all file for %s\n",liens[ptr]->sav);
+#endif
+ if ( (opt.debug>1) && (opt.errlog!=NULL) ) {
+ //if (opt.errlog) {
+ fspc(opt.errlog,"debug"); fprintf(opt.errlog,"Partial file reget (%s) for %s%s"LF,r.msg,urladr,urlfil);
+ test_flush;
+ }
+ // enregistrer le MEME lien (MACRO)
+ liens_record(liens[ptr]->adr,liens[ptr]->fil,liens[ptr]->sav,"","");
+ if (liens[lien_tot]!=NULL) { // OK, pas d'erreur
+ liens[lien_tot]->testmode=liens[ptr]->testmode; // mode test?
+ liens[lien_tot]->link_import=0; // pas mode import
+ liens[lien_tot]->depth=liens[ptr]->depth;
+ liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
+ liens[lien_tot]->retry=liens[ptr]->retry;
+ liens[lien_tot]->premier=liens[ptr]->premier;
+ liens[lien_tot]->precedent=ptr;
+ lien_tot++;
+ //
+ // canceller lien actuel
+ error=1;
+ strcpy(liens[ptr]->adr,"!"); // caractère bidon (invalide hash)
+#if HTS_HASH
+#else
+ liens[ptr]->sav_len=-1; // taille invalide
+#endif
+ //
+ } else { // oups erreur, plus de mémoire!!
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
+ test_flush;
+ }
+ //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
+ XH_uninit; // désallocation mémoire & buffers
+ return 0;
+ }
+ } else {
+ if (opt.errlog!=NULL) {
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Can not remove old file %s"LF,urlfil);
+ test_flush;
+ }
+ }
+ } else {
+ if (opt.errlog!=NULL) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Unexpected 412/416 error (%s) for %s%s"LF,r.msg,urladr,urlfil);
+ test_flush;
+ }
+ }
+ } else if (r.statuscode!=200) {
+ int can_retry=0;
+
+ // cas où l'on peut reessayer
+ // -2=timeout -3=rateout (interne à httrack)
+ switch(r.statuscode) {
+ //case -1: can_retry=1; break;
+ case -2: if (opt.hostcontrol) { // timeout et retry épuisés
+ if ((opt.hostcontrol & 1) && (liens[ptr]->retry<=0)) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"Link banned: %s%s"LF,urladr,urlfil); test_flush;
+ }
+ host_ban(&opt,liens,ptr,lien_tot,back,back_max,filters,opt.maxfilter,&filptr,jump_identification(urladr));
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush;
+ }
+ } else can_retry=1;
+ } else can_retry=1;
+ break;
+ case -3: if ((opt.hostcontrol) && (liens[ptr]->retry<=0)) { // too slow
+ if (opt.hostcontrol & 2) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"Link banned: %s%s"LF,urladr,urlfil); test_flush;
+ }
+ host_ban(&opt,liens,ptr,lien_tot,back,back_max,filters,opt.maxfilter,&filptr,jump_identification(urladr));
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"Info: previous log - link banned: %s%s"LF,urladr,urlfil); test_flush;
+ }
+ } else can_retry=1;
+ } else can_retry=1;
+ break;
+ case -4: // connect closed
+ can_retry=1;
+ break;
+ case -5: // other (non fatal) error
+ can_retry=1;
+ break;
+ case -6: // bad SSL handskake
+ can_retry=1;
+ break;
+ case 408: case 409: case 500: case 502: case 504: can_retry=1;
+ break;
+ }
+
+ if ( strcmp(liens[ptr]->fil,"/primary") != 0 ) { // no primary (internal page 0)
+ if ((liens[ptr]->retry<=0) || (!can_retry) ) { // retry épuisés (ou retry impossible)
+ if (opt.errlog) {
+ if ((opt.retry>0) && (can_retry)){
+ fspc(opt.errlog,"error");
+ 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);
+ } else {
+ if (r.statuscode==-10) { // test OK
+ if ((opt.debug>0) && (opt.errlog!=NULL)) {
+ fspc(opt.errlog,"info");
+ 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);
+ }
+ } else {
+ if (strcmp(urlfil,"/robots.txt")) { // ne pas afficher d'infos sur robots.txt par défaut
+ fspc(opt.errlog,"error");
+ 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);
+ } else {
+ if (opt.debug>1) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"No robots.txt rules at %s"LF,urladr);
+ test_flush;
+ }
+ }
+ }
+ }
+ test_flush;
+ }
+
+ // NO error in trop level
+ // due to the "no connection -> previous restored" hack
+ // This prevent the engine from wiping all data if the website has been deleted (or moved)
+ // since last time (which is quite annoying)
+ if (liens[ptr]->precedent != 0) {
+ // ici on teste si on doit enregistrer la page tout de même
+ if (opt.errpage) {
+ store_errpage=1;
+ }
+ } else {
+ if (strcmp(urlfil,"/robots.txt") != 0) {
+ /*
+ This is an error caused by a link entered by the user
+ That is, link(s) entered by user are invalid (404, 500, connect error, proxy error..)
+ If all links entered are invalid, the session failed and we will attempt to restore
+ the previous one
+ Example: Try to update a website which has been deleted remotely: this may delete
+ the website locally, which is really not desired (especially if the website disappeared!)
+ With this hack, the engine won't wipe local files (how clever)
+ */
+ HTS_STAT.stat_errors_front++;
+ }
+ }
+
+ } else { // retry!!
+ if (opt.debug>0 && opt.errlog != NULL) { // on fera un alert si le retry échoue
+ 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);
+ test_flush;
+ }
+ // redemander fichier
+ liens_record(urladr,urlfil,savename,"","");
+ if (liens[lien_tot]!=NULL) { // OK, pas d'erreur
+ liens[lien_tot]->testmode=liens[ptr]->testmode; // mode test?
+ liens[lien_tot]->link_import=0; // pas mode import
+ liens[lien_tot]->depth=liens[ptr]->depth;
+ liens[lien_tot]->pass2=max(liens[ptr]->pass2,numero_passe);
+ liens[lien_tot]->retry=liens[ptr]->retry-1; // moins 1 retry!
+ liens[lien_tot]->premier=liens[ptr]->premier;
+ liens[lien_tot]->precedent=liens[ptr]->precedent;
+ lien_tot++;
+ } else { // oups erreur, plus de mémoire!!
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ if (opt.errlog) {
+ fspc(opt.errlog,"panic");
+ fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
+ test_flush;
+ }
+ //if (opt.getmode & 1) { if (fp) { fclose(fp); fp=NULL; } }
+ XH_uninit; // désallocation mémoire & buffers
+ return 0;
+ }
+ }
+ } else {
+ if (opt.errlog) {
+ if (opt.debug>1) {
+ fspc(opt.errlog,"info");
+ fprintf(opt.errlog,"Info: no robots.txt at %s%s"LF,urladr,urlfil);
+ }
+ }
+ }
+ if (!store_errpage) {
+ if (r.adr) { freet(r.adr); r.adr=NULL; } // désalloc
+ error=1; // erreur!
+ }
+ }
+ // FIN rattrapage des 301,302,307..
+ // ------------------------------------------------------------
+
+
+
+ } // if !error
+ } // if !error
+
+ if (!error) {
+#if DEBUG_SHOWTYPES
+ if (strstr(REG,r.contenttype)==NULL) {
+ strcat(REG,r.contenttype);
+ strcat(REG,"\n");
+ printf("%s\n",r.contenttype);
+ io_flush;
+ }
+#endif
+
+
+ // ------------------------------------------------------
+ // ok, fichier chargé localement
+ // ------------------------------------------------------
+
+ // Vérificateur d'intégrité
+ #if DEBUG_CHECKINT
+ {
+ int i;
+ for(i=0;i<back_max;i++) {
+ char si[256];
+ sprintf(si,"Test global après back_wait, index %d",i);
+ _CHECKINT(&back[i],si)
+ }
+ }
+ #endif
+
+
+ /* info: updated */
+ /*
+ if (ptr>0) {
+ // "mis à jour"
+ if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) { // page modifiée
+ if (strnotempty(savename)) {
+ HTS_STAT.stat_updated_files++;
+ if (opt.log!=NULL) {
+ //if ((opt.debug>0) && (opt.log!=NULL)) {
+ fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil);
+ test_flush;
+ }
+ }
+ } else {
+ if (!store_errpage) {
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil);
+ test_flush;
+ }
+ }
+ }
+ }
+ */
+
+ // ------------------------------------------------------
+ // traitement (parsing)
+ // ------------------------------------------------------
+
+ // traiter
+ if (
+ ( (is_hypertext_mime(r.contenttype)) /* Is HTML or Js, .. */
+ || (may_be_hypertext_mime(r.contenttype) && (r.adr) ) /* Is real media, .. */
+ )
+ && (liens[ptr]->depth>0) /* Depth > 0 (recurse depth) */
+ && (r.adr!=NULL) /* HTML Data exists */
+ && (r.size>0) /* And not empty */
+ && (!store_errpage) /* Not an html error page */
+ && (savename[0]!='\0') /* Output filename exists */
+ ) { // ne traiter que le html si autorisé
+ // -- -- -- --
+ // Parsing HTML
+ if (!error) {
+ /* Info for wrappers */
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"engine: check-html: %s%s"LF,urladr,urlfil);
+ }
+ {
+ // I'll have to segment this part
+#include "htsparse.c"
+ }
+ }
+ // Fin parsing HTML
+ // -- -- -- --
+
+
+ } // si text/html
+ // -- -- --
+ else { // sauver fichier quelconque
+ // -- -- --
+ // sauver fichier
+
+
+ /* En cas d'erreur, vérifier que fichier d'erreur existe */
+ if (strnotempty(savename) == 0) { // chemin de sauvegarde existant
+ if (strcmp(urlfil,"/robots.txt")==0) { // pas robots.txt
+ if (store_errpage) { // c'est une page d'erreur
+ int create_html_warning=0;
+ int create_gif_warning=0;
+ switch (ishtml(urlfil)) { /* pas fichier html */
+ case 0: /* non html */
+ {
+ char buff[256];
+ guess_httptype(buff,urlfil);
+ if (strcmp(buff,"image/gif")==0)
+ create_gif_warning=1;
+ }
+ break;
+ case 1: /* html */
+ if (!r.adr) {
+ }
+ break;
+ default: /* don't know.. */
+ break;
+ }
+ /* Créer message d'erreur ? */
+ if (create_html_warning) {
+ char* adr=(char*)malloct(strlen(HTS_DATA_ERROR_HTML)+1100);
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg);
+ test_flush;
+ }
+ if (adr) {
+ if (r.adr) {
+ freet(r.adr);
+ r.adr=NULL;
+ }
+ sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
+ r.adr=adr;
+ }
+ } else if (create_gif_warning) {
+ char* adr=(char*)malloct(HTS_DATA_UNKNOWN_GIF_LEN);
+ if ( (opt.debug>0) && (opt.log!=NULL) ) {
+ fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg);
+ test_flush;
+ }
+ if (r.adr) {
+ freet(r.adr);
+ r.adr=NULL;
+ }
+ memcpy(adr, HTS_DATA_UNKNOWN_GIF, HTS_DATA_UNKNOWN_GIF_LEN);
+ r.adr=adr;
+ }
+ }
+ }
+ }
+
+ if (strnotempty(savename) == 0) { // pas de chemin de sauvegarde
+ if (strcmp(urlfil,"/robots.txt")==0) { // robots.txt
+ if (r.adr) {
+ int bptr=0;
+ char line[1024];
+ char buff[8192];
+ char infobuff[8192];
+ int record=0;
+ line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
+ //
+#if DEBUG_ROBOTS
+ printf("robots.txt dump:\n%s\n",r.adr);
+#endif
+ do {
+ bptr+=binput(r.adr+bptr, line, sizeof(line) - 2);
+ if (strfield(line,"user-agent:")) {
+ char* a;
+ a=line+11;
+ while(*a==' ') a++; // sauter espace(s)
+ if (*a == '*') {
+ if (record != 2)
+ record=1; // c pour nous
+ } else if (strfield(a,"httrack")) {
+ buff[0]='\0'; // re-enregistrer
+ infobuff[0]='\0';
+ record=2; // locked
+#if DEBUG_ROBOTS
+ printf("explicit disallow for httrack\n");
+#endif
+ }
+ else record=0;
+ } else if (record) {
+ if (strfield(line,"disallow:")) {
+ char* a;
+ a=strchr(line,'#');
+ if (a) *a='\0';
+ while((line[strlen(line)-1]==' ')
+ || (line[strlen(line)-1]==10)
+ || (line[strlen(line)-1]==13))
+ line[strlen(line)-1]='\0'; // supprimer espaces
+ a=line+9;
+ while((*a==' ') || (*a==10) || (*a==13))
+ a++; // sauter espace(s)
+ if (strnotempty(a)) {
+ if (strcmp(a,"/") != 0) { /* ignoring disallow: / */
+ if ( (strlen(buff) + strlen(a) + 8) < sizeof(buff)) {
+ strcat(buff,a);
+ strcat(buff,"\n");
+ if (strnotempty(infobuff)) strcat(infobuff,", ");
+ strcat(infobuff,a);
+ }
+ } else {
+ if (opt.errlog!=NULL) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
+ test_flush;
+ }
+ }
+ }
+ }
+ }
+ } while( (bptr<r.size) && (strlen(buff) < (sizeof(buff) - 32) ) );
+ if (strnotempty(buff)) {
+ checkrobots_set(&robots,urladr,buff);
+ if (opt.log!=NULL) {
+ if (opt.log != opt.errlog) {
+ fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
+ test_flush;
+ }
+ }
+ if (opt.errlog!=NULL) {
+ 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);
+ test_flush;
+ }
+ }
+ }
+ }
+ } else if (r.is_write) { // déja sauvé sur disque
+ /*
+ if (!ishttperror(r.statuscode))
+ HTS_STAT.stat_files++;
+ HTS_STAT.stat_bytes+=r.size;
+ */
+ //printf("ok......\n");
+ } else {
+ // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
+ // récursion nous en empêche
+ // Dans ce cas on met un fichier indiquant ce fait
+ // Si par la suite on doit retraiter ce fichier avec un niveau de récursion plus
+ // fort, on supprimera le readme, et on scannera le fichier html!
+ // note: sauté si store_errpage (càd si page d'erreur, non à scanner!)
+ if ( (is_hypertext_mime(r.contenttype)) && (!store_errpage) && (r.size>0)) { // c'est du html!!
+ char tempo[HTS_URLMAXSIZE*2];
+ FILE* fp;
+ tempo[0]='\0';
+ strcpy(tempo,savename);
+ strcat(tempo,".readme");
+
+#if HTS_DOSNAME
+ // remplacer / par des slash arrière
+ {
+ int i=0;
+ while(tempo[i]) {
+ if (tempo[i]=='/')
+ tempo[i]='\\';
+ i++;
+ }
+ }
+ // a partir d'ici le slash devient antislash
+#endif
+
+ if ((fp=fopen(tempo,"wb"))!=NULL) {
+ fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION""CRLF""CRLF);
+ fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
+ fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
+ fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
+ fprintf(fp,"and to rescan the URL."CRLF);
+ fclose(fp);
+#if HTS_WIN==0
+ chmod(tempo,HTS_ACCESS_FILE);
+#endif
+ usercommand(0,NULL,antislash(tempo));
+ }
+
+
+ if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
+ fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
+ test_flush;
+ }
+ } else {
+ if ((opt.getmode & 2)!=0) { // ok autorisé
+ if ( (opt.debug>1) && (opt.log!=NULL) ) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename);
+ test_flush;
+ }
+ } else { // lien non autorisé! (ex: cgi-bin en html)
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
+ test_flush;
+ }
+ freet(r.adr); r.adr=NULL;
+ }
+ }
+
+ //printf("extern=%s\n",r.contenttype);
+
+ // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!
+ if (r.adr) {
+ if (filesave(r.adr,(int)r.size,savename)!=0) {
+ if (opt.errlog) {
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to save file %s"LF,savename);
+ test_flush;
+ }
+ } else {
+ /*
+ if (!ishttperror(r.statuscode))
+ HTS_STAT.stat_files++;
+ HTS_STAT.stat_bytes+=r.size;
+ */
+ }
+ }
+
+ }
+
+
+ /* Parsing of other media types (java, ram..) */
+ /*
+ if (strfield2(r.contenttype,"audio/x-pn-realaudio")) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): parsing %s"LF,savename); test_flush;
+ }
+ if (fexist(savename)) { // ok, existe bien!
+ FILE* fp=fopen(savename,"r+b");
+ if (fp) {
+ if (!fseek(fp,0,SEEK_SET)) {
+ char line[HTS_URLMAXSIZE*2];
+ linput(fp,line,HTS_URLMAXSIZE);
+ if (strnotempty(line)) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): detected %s"LF,line); test_flush;
+ }
+ }
+ }
+ fclose(fp);
+ }
+ }
+ } else */
+ if (opt.parsejava) {
+ if (strlen(savename)>6) { // fichier.class
+ if (strfield(savename+strlen(savename)-6,".class")) { // ok c'est une classe
+ if (fexist(savename)) { // ok, existe bien!
+ char err_msg[1100];
+ int r;
+ err_msg[0]='\0';
+
+ //##char* buffer;
+ // JavaParsing f34R!
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): parsing %s"LF,savename); test_flush;
+ }
+
+ //##buffer=(char*) malloct(32768);
+ //##if (buffer) {
+ //
+ //##strcpy(buffer,"$BUFFER$");
+ //##hts_add_file(buffer); // déclarer buffer
+ while(hts_add_file(NULL,-1) >= 0); // clear chain
+
+ r=hts_parse_java(savename,(char*) &err_msg); // parsing
+ if (!r) { // error
+ if (opt.errlog) {
+ fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to parse java file %s : %s"LF,savename,err_msg);
+ test_flush;
+ }
+ } else { // ok
+ char adr[HTS_URLMAXSIZE*2],fil[HTS_URLMAXSIZE*2],save[HTS_URLMAXSIZE*2]; // nom du fichier à sauver dans la boucle
+ char codebase[HTS_URLMAXSIZE*2]; // codebase classe java
+ char lien[HTS_URLMAXSIZE*2];
+ //##char* a;
+ int file_position;
+ int pass_fix,prio_fix;
+ codebase[0]='\0';
+ //
+
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): parsing finished, now copying links.."LF); test_flush;
+ }
+ // recopie de "creer le lien"
+ //
+
+ // adr = c'est la même
+ // fil et save: save2 et fil2
+ prio_fix=maximum(liens[ptr]->depth-1,0);
+ pass_fix=max(liens[ptr]->pass2,numero_passe);
+ if (liens[ptr]->cod) strcpy(codebase,liens[ptr]->cod); // codebase valable pour tt les classes descendantes
+ if (strnotempty(codebase)==0) { // pas de codebase, construire
+ char* a;
+ strcpy(codebase,liens[ptr]->fil);
+ a=codebase+strlen(codebase)-1;
+ while((*a) && (*a!='/') && ( a > codebase)) a--;
+ if (*a=='/')
+ *(a+1)='\0'; // couper
+ } else { // couper http:// éventuel
+ if (strfield(codebase,"http://")) {
+ char tempo[HTS_URLMAXSIZE*2];
+ char* a=codebase+7;
+ a=strchr(a,'/'); // après host
+ if (a) { // ** msg erreur et vérifier?
+ strcpy(tempo,a);
+ strcpy(codebase,tempo); // couper host
+ } else {
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Unexpected strstr error in base %s"LF,codebase);
+ test_flush;
+ }
+ }
+ }
+ }
+ //##a=buffer;
+ //##strcat(buffer,"&"); // fin du buffer
+ if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) { // trop long
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Codebase too long, parsing skipped (%s)"LF,codebase);
+ test_flush;
+ }
+ //##a=NULL;
+ while(hts_add_file(NULL,-1) >= 0); // clear chain
+ }
+ while ( (file_position=hts_add_file(lien,-1)) >= 0 ) {
+ int dejafait=0;
+ /* //##
+ char* b;
+
+ // prochain fichier à noter!
+ lien[0]='\0';
+ b=strchr(a,'&'); // marqueur de fin de chaine (voir hts_add_file)
+ if (b) {
+ if ( ( ((int) b-(int) a) + strlen(codebase)) < HTS_URLMAXSIZE)
+ strncat(lien,a,(int) b-(int) a); // nom du fichier
+ else {
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Error: Java-Parser generated link that exceeds %d bytes"LF,HTS_URLMAXSIZE);
+ test_flush;
+ }
+ }
+ } else a=NULL;
+
+ if (strnotempty(lien)==0) a=NULL; // fin
+ if (a)
+ a=b+1;
+ */
+
+ if (strnotempty(lien)) {
+
+ // calculer les chemins et noms de sauvegarde
+ if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
+ int r;
+
+ // patcher opt pour garder structure originale!! (on ne patche pas les noms dans la classe java!)
+ //##if (!strstr(lien,"://")) { // PAS tester les http://.. inutile (on ne va pas patcher le binaire :-( )
+ if (1) {
+ char tempo[HTS_URLMAXSIZE*2];
+ int a,b;
+ tempo[0]='\0';
+ a=opt.savename_type;
+ b=opt.savename_83;
+ opt.savename_type=0;
+ opt.savename_83=0;
+ // note: adr,fil peuvent être patchés
+ r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,&opt,liens,lien_tot,back,back_max,&cache,&hash,ptr,numero_passe);
+ opt.savename_type=a;
+ opt.savename_83=b;
+ if (r != -1) {
+ if (savename) {
+ if (lienrelatif(tempo,save,savename)==0) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
+ test_flush;
+ }
+ //
+ // xxc xxc xxc xxc TODO java:
+ // rebuild the java class with patched strings...
+ //
+ if (strlen(tempo)<=strlen(lien)) {
+ FILE* fp=fopen(savename,"r+b");
+ if (fp) {
+ if (!fseek(fp,file_position,SEEK_SET)) {
+ //unsigned short int string_length=strlen(tempo);
+ //fwrite(&valint,sizeof(string_length),1,fp);
+ // xxc xxc ARGH! SI la taille est <, décaler le code ?!
+ } else {
+ if (opt.log!=NULL) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): unable to patch: %s"LF,savename);
+ test_flush;
+ }
+ }
+ fclose(fp);
+ } else {
+ if (opt.log!=NULL) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): unable to open: %s"LF,savename);
+ test_flush;
+ }
+ }
+ } else {
+ if (opt.log!=NULL) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): link too long, unable to write it: %s"LF,tempo);
+ test_flush;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): file not caught: %s"LF,lien); test_flush;
+ }
+ r=-1;
+ }
+ //
+ if (r != -1) {
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
+ }
+
+ // modifié par rapport à l'autre version (cf prio_fix notamment et save2)
+
+ // vérifier que le lien n'a pas déja été noté
+ // si c'est le cas, alors il faut s'assurer que la priorité associée
+ // au fichier est la plus grande des deux priorités
+ //
+ // On part de la fin et on essaye de se presser (économise temps machine)
+#if HTS_HASH
+ {
+ int i=hash_read(&hash,save,"",0); // lecture type 0 (sav)
+ if (i>=0) {
+ liens[i]->depth=maximum(liens[i]->depth,prio_fix);
+ dejafait=1;
+ }
+ }
+#else
+ {
+ int l;
+ int i;
+ l=strlen(save);
+ for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) {
+ if (liens[i]->sav_len==l) { // même taille de chaîne
+ if (strcmp(liens[i]->sav,save)==0) { // existe déja
+ liens[i]->depth=maximum(liens[i]->depth,prio_fix);
+ dejafait=1;
+ }
+ }
+ }
+ }
+#endif
+
+
+ if (!dejafait) {
+ //
+ // >>>> CREER LE LIEN JAVA <<<<
+
+ // enregistrer fichier de java (MACRO)
+ liens_record(adr,fil,save,"","");
+ if (liens[lien_tot]==NULL) { // erreur, pas de place réservée
+ printf("PANIC! : Not enough memory [%d]\n",__LINE__);
+ if (opt.errlog) {
+ fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
+ test_flush;
+ }
+ // if ((opt.getmode & 1) && (ptr>0)) { if (fp) { fclose(fp); fp=NULL; } }
+ XH_extuninit; // désallocation mémoire & buffers
+ return 0;
+ }
+
+ // mode test?
+ liens[lien_tot]->testmode=0; // pas mode test
+
+ liens[lien_tot]->link_import=0; // pas mode import
+
+ // écrire autres paramètres de la structure-lien
+ //if (meme_adresse)
+ liens[lien_tot]->premier=liens[ptr]->premier;
+ //else // sinon l'objet père est le précédent lui même
+ // liens[lien_tot]->premier=ptr;
+
+ liens[lien_tot]->precedent=ptr;
+ // noter la priorité
+ liens[lien_tot]->depth=prio_fix;
+ liens[lien_tot]->pass2=max(pass_fix,numero_passe);
+ liens[lien_tot]->retry=opt.retry;
+
+ //strcpy(liens[lien_tot]->adr,adr);
+ //strcpy(liens[lien_tot]->fil,fil);
+ //strcpy(liens[lien_tot]->sav,save);
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fspc(opt.log,"debug"); fprintf(opt.log,"(JavaClass catch file): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
+ test_flush;
+ }
+
+ lien_tot++; // UN LIEN DE PLUS
+ }
+ }
+ }
+
+ }
+ }
+
+ }
+ //##// effacer buffer temporaire
+ //##if (buffer) freet(buffer); buffer=NULL;
+ //##} // if buffer
+ } // if exist
+ } // if .class
+ } // if strlen-savename
+ } // if opt.parsejava
+
+
+
+ } // text/html ou autre
+
+ } // if !error
+
+
+jump_if_done:
+ // libérer les liens
+ if (r.adr) { freet(r.adr); r.adr=NULL; } // libérer la mémoire!
+
+ // prochain lien
+ ptr++;
+
+ // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images à passer après les html)
+ if (opt.getmode & 4) { // sauver les non html après
+ // sauter les fichiers selon la passe
+ if (!numero_passe) {
+ while((ptr<lien_tot)?( liens[ptr]->pass2):0) ptr++;
+ } else {
+ while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
+ }
+ if (ptr>=lien_tot) { // fin de boucle
+ if (!numero_passe) { // première boucle
+ if ((opt.debug>1) && (opt.log!=NULL)) {
+ fprintf(opt.log,LF"Now getting non-html files..."LF);
+ test_flush;
+ }
+ numero_passe=1; // seconde boucle
+ ptr=0;
+ // prochain pass2
+ while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
+
+ //printf("first link==%d\n");
+
+ }
+ }
+ }
+
+ // a-t-on dépassé le quota?
+ if ((opt.maxsite>0) && (HTS_STAT.stat_bytes>=opt.maxsite)) {
+ if (opt.errlog) {
+ fprintf(opt.errlog,"More than "LLintP" bytes have been transfered.. giving up"LF,opt.maxsite);
+ test_flush;
+ }
+ ptr=lien_tot;
+ } else if ((opt.maxtime>0) && ((time_local()-HTS_STAT.stat_timestart)>opt.maxtime)) {
+ if (opt.errlog) {
+ fprintf(opt.errlog,"More than %d seconds passed.. giving up"LF,opt.maxtime);
+ test_flush;
+ }
+ ptr=lien_tot;
+ } else if (exit_xh) { // sortir
+ if (opt.errlog) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"Exit requested by shell or user"LF);
+ test_flush;
+ }
+ ptr=lien_tot;
+ }
+ } while(ptr<lien_tot);
+ //
+ //
+ //
+
+ /*
+ Ensure the index is being closed
+ */
+ HT_INDEX_END;
+
+ /*
+ updating-a-remotely-deteted-website hack
+ no much data transfered, no data saved
+ <no files successfulyl saved>
+ we assume that something was bad (no connection)
+ just backup old cache and restore everything
+ */
+ if (
+ (HTS_STAT.stat_files <= 0)
+ &&
+ (HTS_STAT.HTS_TOTAL_RECV < 32768) /* should be fine */
+ ) {
+ if (opt.errlog) {
+ fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF);
+ test_flush;
+ }
+ XH_uninit;
+ if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) {
+ remove(fconcat(opt.path_log,"hts-cache/new.dat"));
+ remove(fconcat(opt.path_log,"hts-cache/new.ndx"));
+ remove(fconcat(opt.path_log,"hts-cache/new.lst"));
+ remove(fconcat(opt.path_log,"hts-cache/new.txt"));
+ rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat"));
+ rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx"));
+ rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst"));
+ rename(fconcat(opt.path_log,"hts-cache/old.txt"),fconcat(opt.path_log,"hts-cache/new.txt"));
+ }
+ exit_xh=2; /* interrupted (no connection detected) */
+ return 1;
+ }
+
+ // info text
+ if (cache.txt) {
+ fclose(cache.txt); cache.txt=NULL;
+ }
+
+ // purger!
+ if (cache.lst) {
+ fclose(cache.lst); cache.lst=NULL;
+ if (opt.delete_old) {
+ FILE *old_lst,*new_lst;
+ //
+#if HTS_ANALYSTE
+ _hts_in_html_parsing=3;
+#endif
+ //
+ old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb");
+ if (old_lst) {
+ LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst"));
+ new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb");
+ if ((new_lst) && (sz>0)) {
+ char* adr=(char*) malloct((INTsys)sz);
+ if (adr) {
+ if ((int) fread(adr,1,(INTsys)sz,new_lst) == sz) {
+ char line[1100];
+ int purge=0;
+ while(!feof(old_lst)) {
+ linput(old_lst,line,1000);
+ if (!strstr(adr,line)) { // fichier non trouvé dans le nouveau?
+ char file[HTS_URLMAXSIZE*2];
+ strcpy(file,opt.path_html);
+ strcat(file,line+1);
+ file[strlen(file)-1]='\0';
+ if (fexist(file)) { // toujours sur disque: virer
+ if (opt.log) {
+ fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file);
+ }
+ remove(file); purge=1;
+ }
+ }
+ }
+ {
+ fseek(old_lst,0,SEEK_SET);
+ while(!feof(old_lst)) {
+ linput(old_lst,line,1000);
+ while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
+ line[strlen(line)-1]='\0';
+ }
+ if (strnotempty(line))
+ line[strlen(line)-1]='\0';
+ if (strnotempty(line))
+ if (!strstr(adr,line)) { // non trouvé?
+ char file[HTS_URLMAXSIZE*2];
+ strcpy(file,opt.path_html);
+ strcat(file,line+1);
+ while ((strnotempty(file)) && (rmdir(file)==0)) { // ok, éliminé (existait)
+ purge=1;
+ if (opt.log) {
+ fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file);
+ while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
+ file[strlen(file)-1]='\0';
+ }
+ if (strnotempty(file))
+ file[strlen(file)-1]='\0';
+ }
+ }
+ }
+ }
+ }
+ //
+ if (!purge) {
+ if (opt.log) {
+ fprintf(opt.log,"No files purged"LF);
+ }
+ }
+ }
+ freet(adr);
+ }
+ fclose(new_lst);
+ }
+ fclose(old_lst);
+ }
+ //
+#if HTS_ANALYSTE
+ _hts_in_html_parsing=0;
+#endif
+ }
+ }
+ // fin purge!
+
+ // Indexation
+ if (opt.kindex)
+ index_finish(opt.path_html,opt.kindex);
+
+ // afficher résumé dans log
+ if (opt.log!=NULL) {
+ int error = fspc(NULL,"error");
+ int warning = fspc(NULL,"warning");
+ int info = fspc(NULL,"info");
+ char htstime[256];
+ // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
+ int n=(int) (HTS_STAT.HTS_TOTAL_RECV/(max(1,time_local()-HTS_STAT.stat_timestart)));
+
+ sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
+ //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);
+ 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);
+ if (HTS_STAT.total_packed) {
+ int packed_ratio=(int)((LLint)(HTS_STAT.total_packed*100)/HTS_STAT.total_unpacked);
+ fprintf(opt.log,", "LLintP" bytes transfered using HTTP compression in %d files, ratio %d%%",HTS_STAT.total_unpacked,HTS_STAT.total_packedfiles,packed_ratio);
+ }
+ fprintf(opt.log,LF);
+ if (error)
+ fprintf(opt.log,"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
+ else
+ fprintf(opt.log,"(No errors, %d warnings, %d messages)"LF,warning,info);
+ test_flush;
+ }
+#if DEBUG_HASH
+ // noter les collisions
+ {
+ int i;
+ int empty1=0,empty2=0,empty3=0;
+ for(i=0;i<HTS_HASH_SIZE;i++) {
+ if (hash.hash[0][i] == -1)
+ empty1++;
+ if (hash.hash[1][i] == -1)
+ empty2++;
+ if (hash.hash[2][i] == -1)
+ empty3++;
+ }
+ printf("\n");
+ printf("Debug info: Hash-table report\n");
+ printf("Number of files entered: %d\n",hashnumber);
+ printf("Table size: %d\n",HTS_HASH_SIZE);
+ printf("\n");
+ printf("Longest chain sav: %d, empty: %d\n",longest_hash[0],empty1);
+ printf("Longest chain adr,fil: %d, empty: %d\n",longest_hash[1],empty2);
+ printf("Longest chain former_adr/fil: %d, empty: %d\n",longest_hash[2],empty3);
+ printf("\n");
+ }
+#endif
+ // fin afficher résumé dans log
+
+ // désallocation mémoire & buffers
+
+ XH_uninit
+
+ return 1; // OK
+}
+// version 2 pour le reste
+// flusher si on doit lire peu à peu le fichier
+#undef test_flush
+#define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
+
+
+// Estimate transfer rate
+// a little bit complex, but not too much
+/*
+ .. : idle
+ ^ : event
+
+ ----|----|----|----|----|----|----|----|---->
+ 1 2 3 4 5 6 7 8 9 time (seconds)
+ ----|----|----|----|----|----|----|----|---->
+ ^........^.........^.........^.........^.... timer 0
+ ----^.........^.........^.........^......... timer 1
+ 0 1 0 1 0 1 0 timer N sets its statistics
+ * * * * timer 0 resync timer 1
+
+ Therefore, each seconds, we resync the transfer rate with 2-seconds
+
+*/
+int engine_stats(void) {
+#if 0
+ static FILE* debug_fp=NULL; /* ok */
+ if (!debug_fp)
+ debug_fp=fopen("esstat.txt","wb");
+#endif
+ HTS_STAT.stat_nsocket=HTS_STAT.stat_errors=HTS_STAT.nbk==0;
+ HTS_STAT.nb=0;
+ if (HTS_STAT.HTS_TOTAL_RECV>2048) {
+ TStamp cdif=mtime_local();
+ int i;
+
+ for(i=0;i<2;i++) {
+ if ( (cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
+ TStamp dif;
+#if 0
+fprintf(debug_fp,"set timer %d\n",i); fflush(debug_fp);
+#endif
+ dif=cdif - HTS_STAT.istat_timestart[i];
+ if ((TStamp)(dif/1000)>0) {
+ LLint byt=(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
+ HTS_STAT.rate=(LLint)((TStamp) ((TStamp)byt/(dif/1000)));
+ HTS_STAT.istat_idlasttimer=i; // this timer recently sets the stats
+ //
+ HTS_STAT.istat_bytes[i]=HTS_STAT.HTS_TOTAL_RECV;
+ HTS_STAT.istat_timestart[i]=cdif;
+ }
+ return 1; /* refreshed */
+ }
+ }
+
+ // resynchronization between timer 0 (master) and 1 (slave)
+ // timer #0 resync timer #1 when reaching 1 second limit
+ if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
+ if ( (cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
+#if 0
+fprintf(debug_fp,"resync timer 1\n"); fflush(debug_fp);
+#endif
+ HTS_STAT.istat_bytes[1]=HTS_STAT.HTS_TOTAL_RECV;
+ HTS_STAT.istat_timestart[1]=cdif;
+ HTS_STAT.istat_reference01=HTS_STAT.istat_timestart[0];
+ }
+ }
+
+ }
+ return 0;
+}
+
+
+// bannir host (trop lent etc)
+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) {
+ //int l;
+ int i;
+
+ if (host[0]=='!')
+ return; // erreur.. déja cancellé.. bizarre.. devrait pas arriver
+
+ /* sanity check */
+ if (*filptr + 1 >= opt->maxfilter) {
+ opt->maxfilter += HTS_FILTERSINC;
+ if (filters_init(&filters, opt->maxfilter, HTS_FILTERSINC) == 0) {
+ printf("PANIC! : Too many filters : >%d [%d]\n",*filptr,__LINE__);
+ if (opt->errlog) {
+ fprintf(opt->errlog,LF"Too many filters, giving up..(>%d)"LF,*filptr);
+ fprintf(opt->errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
+ fflush(opt->errlog);
+ }
+ abort();
+ }
+ //opt->filters.filters=&filters;
+ }
+
+ // interdire host
+ if (*filptr < filter_max) {
+ strcpy(filters[*filptr],"-");
+ strcat(filters[*filptr],host);
+ strcat(filters[*filptr],"/*"); // host/ * interdit
+ (*filptr)++; *filptr=minimum(*filptr,filter_max);
+ }
+
+ // oups
+ if (strlen(host)<=1) { // euhh?? longueur <= 1
+ if (strcmp(host,"file://")) {
+ //## if (host[0]!=lOCAL_CHAR) { // pas local
+ if (opt->log!=NULL) {
+ fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
+ }
+ return; // purée
+ }
+ }
+
+ // couper connexion
+ for(i=0;i<back_max;i++) {
+ if (back[i].status>=0) // réception OU prêt
+ if (strfield2(back[i].url_adr,host)) {
+#if HTS_DEBUG_CLOSESOCK
+ DEBUG_W("host control: deletehttp\n");
+#endif
+ back[i].status=0; // terminé
+ if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
+ back[i].r.soc=INVALID_SOCKET;
+ back[i].r.statuscode=-2; // timeout (peu importe si c'est un traffic jam)
+ strcpy(back[i].r.msg,"Link Cancelled by host control");
+
+ if ((opt->debug>1) && (opt->log!=NULL)) {
+ fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
+ }
+ }
+ }
+
+ // effacer liens
+ //l=strlen(host);
+ for(i=0;i<lien_tot;i++) {
+ //if (liens[i]->adr_len==l) { // même taille de chaîne
+ // Calcul de taille sécurisée
+ if (liens[i]) {
+ if (liens[i]->adr) {
+ int l = 0;
+ while((liens[i]->adr[l]) && (l<1020)) l++;
+ if ((l > 0) && (l<1020)) { // sécurité
+ if (strfield2(jump_identification(liens[i]->adr),host)) { // host
+ if ((opt->debug>1) && (opt->log!=NULL)) {
+ fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
+ }
+ strcpy(liens[i]->adr,"!"); // cancel (invalide hash)
+#if HTS_HASH
+#else
+ liens[i]->sav_len=-1; // taille invalide
+#endif
+ // on efface pas le hash, because si on rencontre le lien, reverif sav..
+ }
+ } else {
+ if (opt->log!=NULL) {
+ char dmp[1040];
+ dmp[0]='\0';
+ strncat(dmp,liens[i]->adr,1024);
+ fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
+ fprintf(opt->log,"dump 1024 bytes (address %p): "LF"%s"LF,liens[i]->adr,dmp); test_flush;
+ }
+ }
+ } else {
+ if (opt->log!=NULL) {
+ fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
+ }
+ }
+ } else {
+ if (opt->log!=NULL) {
+ fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
+ }
+ }
+ //}
+ }
+}
+
+
+/* Init structure */
+/* 1 : init */
+/* -1 : off */
+char* structcheck_init(int init) {
+ char** structcheck_buff;
+ int* structcheck_buff_size;
+ NOSTATIC_RESERVE(structcheck_buff, char*, 1);
+ NOSTATIC_RESERVE(structcheck_buff_size, int, 1);
+ if (init < 2) {
+ if (init) {
+ if (*structcheck_buff)
+ freet(*structcheck_buff);
+ *structcheck_buff=NULL;
+ }
+ if (init != -1) {
+ if (*structcheck_buff==NULL) {
+ *structcheck_buff_size = 65536;
+ *structcheck_buff=(char*) malloct(*structcheck_buff_size); // désalloué xh_xx
+ if (*structcheck_buff)
+ strcpy(*structcheck_buff,"#");
+ }
+ }
+ } else { /* Ensure enough room */
+ if (*structcheck_buff_size < init) {
+ *structcheck_buff_size = init + 65536;
+ *structcheck_buff=(char*) realloct(*structcheck_buff, *structcheck_buff_size);
+ if (*structcheck_buff == NULL) { /* Reset :( */
+ *structcheck_buff_size = 65536;
+ *structcheck_buff=(char*) malloct(*structcheck_buff_size); // désalloué xh_xx
+ if (*structcheck_buff)
+ strcpy(*structcheck_buff,"#");
+ }
+ }
+ }
+ return *structcheck_buff;
+}
+
+int filters_init(char*** ptrfilters, int maxfilter, int filterinc) {
+ char** filters = *ptrfilters;
+ int filter_max=maximum(maxfilter, 128);
+ if (filters == NULL) {
+ filters=(char**) malloct( sizeof(char*) * (filter_max+2) );
+ memset(filters, 0, sizeof(char*) * (filter_max+2)); // filters[0] == 0
+ } else {
+ filters=(char**) realloct(filters, sizeof(char*) * (filter_max+2) );
+ }
+ if (filters) {
+ if (filters[0] == NULL) {
+ filters[0]=(char*) malloct( sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
+ memset(filters[0], 0, sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
+ } else {
+ filters[0]=(char*) realloct(filters[0], sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
+ }
+ if (filters[0] == NULL) {
+ freet(filters);
+ filters = NULL;
+ }
+ }
+ if (filters != NULL) {
+ int i;
+ int from;
+ if (filterinc == 0)
+ from = 0;
+ else
+ from = filter_max - filterinc;
+ for(i=0 ; i<=filter_max ; i++) { // PLUS UN (sécurité)
+ filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
+ }
+ for(i=from ; i<=filter_max ; i++) { // PLUS UN (sécurité)
+ filters[i][0]='\0'; // clear
+ }
+ }
+ *ptrfilters = filters;
+ return (filters != NULL) ? filter_max : 0;
+}
+
+// vérifier présence de l'arbo
+int structcheck(char* s) {
+ // vérifier la présence des dossier(s)
+ char *a=s;
+ char nom[HTS_URLMAXSIZE*2];
+ char *b;
+ char* structcheck_buff=NULL;
+ if (strnotempty(s)==0) return 0;
+ if (strlen(s)>HTS_URLMAXSIZE) return 0;
+
+ // Get buffer address
+ structcheck_buff=structcheck_init(0);
+ if (!structcheck_buff)
+ return -1;
+
+ if (strlen(structcheck_buff) > 65000) {
+ strcpy(structcheck_buff,"#"); // réinit.. c'est idiot ** **
+ }
+
+ if (structcheck_buff) {
+ b=nom;
+ do {
+ if (*a) *b++=*a++;
+ while((*a!='/') && (*a!='\0')) *b++=*a++;
+ *b='\0'; // pas de ++ pour boucler
+ if (*a=='/') { // toujours dossier
+ if (strnotempty(nom)) {
+ char tempo[HTS_URLMAXSIZE*2];
+
+ strcpy(tempo,"#"); strcat(tempo,nom); strcat(tempo,"#");
+ if (strstr(structcheck_buff,tempo)==NULL) { // non encore créé
+
+ /* Check room */
+ structcheck_init(strlen(structcheck_buff) + strlen(nom) + 8192);
+ if (!structcheck_buff)
+ return -1;
+
+ strcat(structcheck_buff,"#"); strcat(structcheck_buff,nom); strcat(structcheck_buff,"#"); // ajouter à la liste
+
+#if HTS_WIN
+ if (mkdir(fconv(nom))!=0)
+#else
+ if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0)
+#endif
+ {
+#if HTS_REMOVE_ANNOYING_INDEX
+ // might be a filename with same name than this folder
+ // then, remove it to allow folder creation
+ // it happends when servers gives a folder index while
+ // requesting / page
+ // -> if the file can be opened (not a folder) then rename it
+ FILE* fp=fopen(fconv(nom),"ab");
+ if (fp) {
+ fclose(fp);
+ rename(fconv(nom),fconcat(fconv(nom),".txt"));
+ }
+ // if it fails, that's too bad
+#if HTS_WIN
+ mkdir(fconv(nom));
+#else
+ mkdir(fconv(nom),HTS_ACCESS_FOLDER);
+#endif
+#endif
+ // Si existe déja renvoie une erreur.. tant pis
+ }
+#if HTS_WIN==0
+ chmod(fconv(nom),HTS_ACCESS_FOLDER);
+#endif
+ }
+ }
+ *b++=*a++; // slash
+ }
+ } while(*a);
+ }
+ return 0;
+}
+
+
+// sauver un fichier
+int filesave(char* adr,int len,char* s) {
+ FILE* fp;
+ // écrire le fichier
+ if ((fp=filecreate(s))!=NULL) {
+ int nl=0;
+ if (len>0) {
+ nl=(int) fwrite(adr,1,len,fp);
+ }
+ fclose(fp);
+ usercommand(0,NULL,antislash(s));
+ if (nl!=len) // erreur
+ return -1;
+ } else
+ return -1;
+
+ return 0;
+}
+
+
+// ouvrir un fichier (avec chemin Un*x)
+FILE* filecreate(char* s) {
+ char fname[HTS_URLMAXSIZE*2];
+ FILE* fp;
+ fname[0]='\0';
+
+ // noter lst
+ filenote(s,NULL);
+
+ // if (*s=='/') strcpy(fname,s+1); else strcpy(fname,s); // pas de / (root!!) // ** SIIIIIII!!! à cause de -O <path>
+ strcpy(fname,s);
+
+#if HTS_DOSNAME
+ // remplacer / par des slash arrière
+ {
+ int i=0;
+ while(fname[i]) {
+ if (fname[i]=='/')
+ fname[i]='\\';
+ i++;
+ }
+ }
+ // a partir d'ici le slash devient antislash
+#endif
+
+ // construite le chemin si besoin est
+ if (structcheck(s)!=0) {
+ return NULL;
+ }
+
+ // ouvrir
+ fp=fopen(fname,"wb");
+#if HTS_WIN==0
+ if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
+#endif
+
+ return fp;
+}
+
+// create an empty file
+int filecreateempty(char* filename) {
+ FILE* fp;
+ fp=filecreate(filename); // filenote & co
+ if (fp) {
+ fclose(fp);
+ return 1;
+ } else
+ return 0;
+}
+
+// noter fichier
+typedef struct {
+ FILE* lst;
+ char path[HTS_URLMAXSIZE*2];
+} filenote_strc;
+int filenote(char* s,filecreate_params* params) {
+ filenote_strc* strc;
+ NOSTATIC_RESERVE(strc, filenote_strc, 1);
+
+ // gestion du fichier liste liste
+ if (params) {
+ //filecreate_params* p = (filecreate_params*) params;
+ strcpy(strc->path,params->path);
+ strc->lst=params->lst;
+ return 0;
+ } else if (strc->lst) {
+ char savelst[HTS_URLMAXSIZE*2];
+ strcpy(savelst,fslash(s));
+ // couper chemin?
+ if (strnotempty(strc->path)) {
+ if (strncmp(fslash(strc->path),savelst,strlen(strc->path))==0) { // couper
+ strcpy(savelst,s+strlen(strc->path));
+ }
+ }
+ fprintf(strc->lst,"[%s]"LF,savelst);
+ fflush(strc->lst);
+ }
+ return 1;
+}
+
+// executer commande utilisateur
+typedef struct {
+ int exe;
+ char cmd[2048];
+} usercommand_strc;
+HTS_INLINE void usercommand(int _exe,char* _cmd,char* file) {
+ usercommand_strc* strc;
+ NOSTATIC_RESERVE(strc, usercommand_strc, 1);
+
+ if (_exe) {
+ strcpy(strc->cmd,_cmd);
+ if (strnotempty(strc->cmd))
+ strc->exe=_exe;
+ else
+ strc->exe=0;
+ }
+
+#if HTS_ANALYSTE
+ if (hts_htmlcheck_filesave)
+ if (strnotempty(file))
+ hts_htmlcheck_filesave(file);
+#endif
+
+ if (strc->exe) {
+ if (strnotempty(file)) {
+ if (strnotempty(strc->cmd)) {
+ usercommand_exe(strc->cmd,file);
+ }
+ }
+ }
+}
+void usercommand_exe(char* cmd,char* file) {
+ char temp[8192];
+ char c[2]="";
+ int i;
+ temp[0]='\0';
+ //
+ for(i=0;i<(int) strlen(cmd);i++) {
+ if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
+ strcat(temp,file);
+ i++;
+ } else {
+ c[0]=cmd[i]; c[1]='\0';
+ strcat(temp,c);
+ }
+ }
+ system(temp);
+}
+
+// écrire n espaces dans fp
+typedef struct {
+ int error;
+ int warning;
+ int info;
+} fspc_strc;
+HTS_INLINE int fspc(FILE* fp,char* type) {
+ fspc_strc* strc;
+ NOSTATIC_RESERVE(strc, fspc_strc, 1); // log..
+
+ //
+ if (fp) {
+ char s[256];
+ time_t tt;
+ struct tm* A;
+ tt=time(NULL);
+ A=localtime(&tt);
+ strftime(s,250,"%H:%M:%S",A);
+ if (strnotempty(type))
+ fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
+ else
+ fprintf(fp,"%s\t \t",s);
+ if (strcmp(type,"warning")==0)
+ strc->warning++;
+ else if (strcmp(type,"error")==0)
+ strc->error++;
+ else if (strcmp(type,"info")==0)
+ strc->info++;
+ }
+ else if (!type)
+ strc->error=strc->warning=strc->info=0; // reset
+ else if (strcmp(type,"warning")==0)
+ return strc->warning;
+ else if (strcmp(type,"error")==0)
+ return strc->error;
+ else if (strcmp(type,"info")==0)
+ return strc->info;
+ return 0;
+}
+
+
+// vérifier taux de transfert
+#if 0
+void check_rate(TStamp stat_timestart,int maxrate) {
+ // vérifier taux de transfert (pas trop grand?)
+ /*
+ if (maxrate>0) {
+ int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart)); // taux actuel de transfert
+ HTS_STAT.HTS_TOTAL_RECV_STATE=0;
+ if (r>maxrate) { // taux>taux autorisé
+ int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
+ if (taux<15)
+ HTS_STAT.HTS_TOTAL_RECV_STATE=1; // ralentir un peu (<15% dépassement)
+ else if (taux<50)
+ HTS_STAT.HTS_TOTAL_RECV_STATE=2; // beaucoup (<50% dépassement)
+ else
+ HTS_STAT.HTS_TOTAL_RECV_STATE=3; // énormément (>50% dépassement)
+ }
+ }
+ */
+}
+#endif
+
+// ---
+// sous routines liées au moteur et au backing
+
+// supplemental links ready (done) after ptr
+int backlinks_done(lien_url** liens,int lien_tot,int ptr) {
+ int n=0;
+ int i;
+ //Links done and stored in cache
+ for(i=ptr+1;i<lien_tot;i++) {
+ if (liens[i]) {
+ if (liens[i]->pass2 == -1) {
+ n++;
+ }
+ }
+ }
+ return n;
+}
+
+// remplir backing si moins de max_bytes en mémoire
+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) {
+ if (!opt->state.stop) {
+ if (back_incache(back,back_max)<opt->maxcache) { // pas trop en mémoire?
+ return back_fill(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
+ }
+ }
+ return -1; /* plus de place */
+}
+
+// remplir backing
+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) {
+ int n;
+
+ // ajouter autant de socket qu'on peut ajouter
+ n=opt->maxsoc-back_nsoc(back,back_max);
+
+ // vérifier qu'il restera assez de place pour les tests ensuite (en théorie, 1 entrée libre restante suffirait)
+ n=min( n, back_available(back,back_max) - 8 );
+
+ // no space left on backing stack - do not back anymore
+ if (back_stack_available(back,back_max) <= 2)
+ n=0;
+
+ if (n>0) {
+ int p;
+
+ if (ptr<cache->ptr_last) { /* restart (2 scans: first html, then non html) */
+ cache->ptr_ant=0;
+ }
+
+ p=ptr+1;
+ /* on a déja parcouru */
+ if (p<cache->ptr_ant)
+ p=cache->ptr_ant;
+ while( (p<lien_tot) && (n>0) ) {
+ //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
+ int ok=1;
+
+ // on ne met pas le fichier en backing si il doit être traité après
+ if (liens[p]->pass2) { // 2è passe
+ if (numero_passe!=1)
+ ok=0;
+ } else {
+ if (numero_passe!=0)
+ ok=0;
+ }
+
+ // note: si un backing est fini, il reste en mémoire jusqu'à ce que
+ // le ptr l'atteigne
+ if (ok) {
+ if (!back_exist(back,back_max,liens[p]->adr,liens[p]->fil,liens[p]->sav)) {
+ 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) {
+ if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
+ fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF);
+ test_flush;
+ }
+#if BDEBUG==1
+ printf("error while adding\n");
+#endif
+ n=0; // sortir
+ } else {
+ n--;
+#if BDEBUG==1
+ printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);
+#endif
+ }
+ }
+ }
+ p++;
+ } // while
+ /* sauver position dernière anticipation */
+ cache->ptr_ant=p;
+ cache->ptr_last=ptr;
+ }
+ return 0;
+}
+// ---
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// routines de détournement de SIGHUP & co (Unix)
+//
+httrackp* hts_declareoptbuffer(httrackp* optdecl) {
+ static httrackp* opt=NULL; /* OK */
+ if (optdecl) opt=optdecl;
+ return opt;
+}
+//
+void sig_finish( int code ) { // finir et quitter
+ signal(code,sig_term); // quitter si encore
+ exit_xh=1;
+ fprintf(stderr,"\nExit requested to engine (signal %d)\n",code);
+}
+void sig_term( int code ) { // quitter brutalement
+ fprintf(stderr,"\nProgram terminated (signal %d)\n",code);
+ exit(0);
+}
+#if HTS_WIN
+void sig_ask( int code ) { // demander
+ char s[256];
+ signal(code,sig_term); // quitter si encore
+ printf("\nQuit program/Interrupt/Cancel? (Q/I/C) ");
+ fflush(stdout);
+ scanf("%s",s);
+ if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
+ exit(0); // quitter
+ else if ( (s[0]=='i') || (s[0]=='I') ) {
+ httrackp* opt=hts_declareoptbuffer(NULL);
+ if (opt) {
+ // ask for stop
+ opt->state.stop=1;
+ }
+ }
+ signal(code,sig_ask); // remettre signal
+}
+#else
+void sig_back( int code ) { // ignorer et mettre en backing
+ signal(code,sig_ignore);
+ sig_doback(0);
+}
+void sig_ask( int code ) { // demander
+ char s[256];
+ signal(code,sig_term); // quitter si encore
+ printf("\nQuit program/Interrupt/Background/bLind background/Cancel? (Q/I/B/L/C) ");
+ fflush(stdout);
+ scanf("%s",s);
+ if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
+ exit(0); // quitter
+ else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') )
+ sig_doback(0); // arrière plan
+ else if ( (s[0]=='l') || (s[0]=='L') )
+ sig_doback(1); // arrière plan
+ else if ( (s[0]=='i') || (s[0]=='I') ) {
+ httrackp* opt=hts_declareoptbuffer(NULL);
+ if (opt) {
+ // ask for stop
+ opt->state.stop=1;
+ }
+ signal(code,sig_ask); // remettre signal
+ }
+ else {
+ printf("cancel..\n");
+ signal(code,sig_ask); // remettre signal
+ }
+}
+void sig_ignore( int code ) { // ignorer signal
+}
+void sig_brpipe( int code ) { // treat if necessary
+ if (!sig_ignore_flag(-1)) {
+ sig_term(code);
+ }
+}
+void sig_doback(int blind) { // mettre en backing
+ int out=-1;
+ //
+ printf("\nMoving to background to complete the mirror...\n"); fflush(stdout);
+
+ {
+ httrackp* opt=hts_declareoptbuffer(NULL);
+ if (opt) {
+ // suppress logging and asking lousy questions
+ opt->quiet=1;
+ opt->verbosedisplay=0;
+ }
+ }
+
+ if (!blind)
+ out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR);
+ if (out == -1)
+ out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR);
+ close(0);
+ close(1);
+ dup(out);
+ close(2);
+ dup(out);
+ //
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ fprintf(stderr,"Error: can not fork process\n");
+ break;
+ default: // pere
+ usleep(100000); // pause 1/10s "A microsecond is .000001s"
+ _exit(0);
+ break;
+ }
+}
+#endif
+// fin routines de détournement de SIGHUP & co
+
+// Poll stdin.. si besoin
+#if HTS_POLL
+// lecture stdin des caractères disponibles
+int read_stdin(char* s,int max) {
+ int i=0;
+ while((check_stdin()) && (i<(max-1)) )
+ s[i++]=fgetc(stdin);
+ s[i]='\0';
+ return i;
+}
+#ifdef _WIN32
+HTS_INLINE int check_stdin(void) {
+ return (_kbhit());
+}
+#else
+HTS_INLINE int check_flot(T_SOC s) {
+ fd_set fds;
+ struct timeval tv;
+ FD_ZERO(&fds);
+ FD_SET((T_SOC) s,&fds);
+ tv.tv_sec=0;
+ tv.tv_usec=0;
+ select(s+1,&fds,NULL,NULL,&tv);
+ return FD_ISSET(s,&fds);
+}
+HTS_INLINE int check_stdin(void) {
+ fflush(stdout); fflush(stdin);
+ if (check_flot(0))
+ return 1;
+ return 0;
+}
+#endif
+#endif
+
+// Attente de touche
+#if HTS_ANALYSTE
+int ask_continue(void) {
+ char* s;
+ s=hts_htmlcheck_query2(HTbuff);
+ if (s) {
+ if (strnotempty(s)) {
+ if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
+ return 0;
+ }
+ return 1;
+ }
+ return 1;
+}
+#else
+int ask_continue(void) {
+ char s[12];
+ s[0]='\0';
+ printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n");
+ io_flush; linput(stdin,s,4);
+ if (strnotempty(s)) {
+ if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+// nombre de digits dans un nombre
+int nombre_digit(int n) {
+ int i=1;
+ while(n >= 10) { n/=10; i++; }
+ return i;
+}
+
+
+// renvoi adresse de la fin du token dans p
+// renvoi NULL si la chaine est un token unique
+// (PATCHE également la chaine)
+// ex: "test" "test2" renvoi adresse sur espace
+// flag==1 si chaine comporte des echappements comme \"
+char* next_token(char* p,int flag) {
+ int detect=0;
+ int quote=0;
+ p--;
+ do {
+ p++;
+ if (flag && (*p=='\\')) { // sauter \x ou \"
+ if (quote) {
+ char c='\0';
+ if (*(p+1)=='\\')
+ c='\\';
+ else if (*(p+1)=='"')
+ c='"';
+ if (c) {
+ char tempo[8192];
+ tempo[0]=c; tempo[1]='\0';
+ strcat(tempo,p+2);
+ strcpy(p,tempo);
+ }
+ }
+ }
+ else if (*p==34) { // guillemets (de fin)
+ quote=!quote;
+ }
+ else if (*p==32) {
+ if (!quote)
+ detect=1;
+ }
+ else if (*p=='\0') {
+ p=NULL;
+ detect=1;
+ }
+ } while(!detect);
+ return p;
+}
+
+// routines annexes
+#if HTS_ANALYSTE
+// canceller un fichier (noter comme cancellable)
+// !!NOT THREAD SAFE!!
+char* hts_cancel_file(char * s) {
+ static char sav[HTS_URLMAXSIZE*2]="";
+ if (s[0]!='\0')
+ if (sav[0]=='\0')
+ strcpy(sav,s);
+ return sav;
+}
+void hts_cancel_test(void) {
+ if (_hts_in_html_parsing==2)
+ _hts_cancel=2;
+}
+void hts_cancel_parsing(void) {
+ if (_hts_in_html_parsing)
+ _hts_cancel=1;
+}
+#endif
+// for(_i=0;(_i<back_max) && (index<NStatsBuffer);_i++) {
+// i=(back_index+_i)%back_max; // commencer par le "premier" (l'actuel)
+// if (back[i].status>=0) { // signifie "lien actif"
+
+
+/*
+hts_add_file, add/get elements in the add chain for java parsing
+if file_position >= 0
+ push 'file/file_position'
+ return 1 (return 0 if exists)
+else
+ pop file -> 'file'
+ return 'file_position'
+else if empty/error
+ return -1;
+*/
+typedef struct addfile_chain {
+ char name[1024];
+ int pos;
+ struct addfile_chain* next;
+} addfile_chain;
+typedef addfile_chain* addfile_chain_ptr;
+int hts_add_file(char* file,int file_position) {
+ addfile_chain** chain;
+ NOSTATIC_RESERVE(chain, addfile_chain_ptr, 1);
+
+ if (file_position>=0) { /* copy file to the chain */
+ struct addfile_chain** current;
+ current=chain; /* start from */
+ while(*current) {
+ if (strcmp((*current)->name,file)==0)
+ return 0; /* already exists */
+ current=&( (*current)->next ); /* 'next' address */
+ }
+ *current=calloct(1,sizeof(addfile_chain));
+ if (*current) {
+ (*current)->next=NULL;
+ (*current)->pos=-1;
+ (*current)->name[0]='\0';
+ }
+ if (*current) {
+ strcpy((*current)->name,file);
+ (*current)->pos=file_position;
+ return 1;
+ } else {
+ printf("PANIC! Too many Java files during parsing [1]\n");
+ return -1;
+ }
+ } else { /* copy last element in file and delete it */
+ if (file)
+ file[0]='\0';
+ if (*chain) {
+ struct addfile_chain** current;
+ int pos=-1;
+ current=chain; /* start from */
+ while( (*current)->next ) {
+ current=&( (*current)->next ); /* 'next' address */
+ }
+ if (file)
+ strcpy(file,(*current)->name);
+ pos=(*current)->pos;
+ freet(*current);
+ *current=NULL;
+ return pos;
+ }
+ return -1; /* no more elements */
+ }
+
+ return 0;
+}
+
+#if HTS_ANALYSTE
+// en train de parser un fichier html? réponse: % effectués
+// flag>0 : refresh demandé
+int hts_is_parsing(int flag) {
+ if (_hts_in_html_parsing) { // parsing?
+ if (flag>=0) _hts_in_html_poll=1; // faudrait un tit refresh
+ return max(_hts_in_html_done,1); // % effectués
+ } else {
+ return 0; // non
+ }
+}
+int hts_is_testing(void) { // 0 non 1 test 2 purge
+ if (_hts_in_html_parsing==2)
+ return 1;
+ else if (_hts_in_html_parsing==3)
+ return 2;
+ return 0;
+}
+// message d'erreur?
+char* hts_errmsg(void) {
+ return _hts_errmsg;
+}
+// mode pause transfer
+int hts_setpause(int p) {
+ if (p>=0) _hts_setpause=p;
+ return _hts_setpause;
+}
+// ask for termination
+int hts_request_stop(int force) {
+ httrackp* opt=hts_declareoptbuffer(NULL);
+ if (opt) {
+ opt->state.stop=1;
+ }
+ return 0;
+}
+// régler en cours de route les paramètres réglables..
+// -1 : erreur
+int hts_setopt(httrackp* set_opt) {
+ if (set_opt) {
+ httrackp* engine_opt=hts_declareoptbuffer(NULL);
+ if (engine_opt) {
+ //_hts_setopt=opt;
+ copy_htsopt(set_opt,engine_opt);
+ }
+ }
+ return 0;
+}
+// ajout d'URL
+// -1 : erreur
+int hts_addurl(char** url) {
+ if (url) _hts_addurl=url;
+ return (_hts_addurl!=NULL);
+}
+int hts_resetaddurl(void) {
+ _hts_addurl=NULL;
+ return (_hts_addurl!=NULL);
+}
+// copier nouveaux paramètres si besoin
+int copy_htsopt(httrackp* from,httrackp* to) {
+ if (from->maxsite > -1)
+ to->maxsite = from->maxsite;
+
+ if (from->maxfile_nonhtml > -1)
+ to->maxfile_nonhtml = from->maxfile_nonhtml;
+
+ if (from->maxfile_html > -1)
+ to->maxfile_html = from->maxfile_html;
+
+ if (from->maxsoc > 0)
+ to->maxsoc = from->maxsoc;
+
+ if (from->nearlink > -1)
+ to->nearlink = from->nearlink;
+
+ if (from->timeout > -1)
+ to->timeout = from->timeout;
+
+ if (from->rateout > -1)
+ to->rateout = from->rateout;
+
+ if (from->maxtime > -1)
+ to->maxtime = from->maxtime;
+
+ if (from->maxrate > -1)
+ to->maxrate = from->maxrate;
+
+ if (strnotempty(from->user_agent))
+ strcpy(to->user_agent , from->user_agent);
+
+ if (from->retry > -1)
+ to->retry = from->retry;
+
+ if (from->hostcontrol > -1)
+ to->hostcontrol = from->hostcontrol;
+
+ if (from->errpage > -1)
+ to->errpage = from->errpage;
+
+ if (from->parseall > -1)
+ to->parseall = from->parseall;
+
+
+ // test all: bit 8 de travel
+ if (from->travel > -1) {
+ if (from->travel & 256)
+ to->travel|=256;
+ else
+ to->travel&=255;
+ }
+
+
+ return 0;
+}
+
+#endif
+//
+
+
+
+
+
+// message copyright interne
+void voidf(void) {
+ char* a;
+ a=""CRLF""CRLF;
+ a="+-----------------------------------------------+"CRLF;
+ a="|HyperTextTRACKer, Offline Browser Utility |"CRLF;
+ a="| HTTrack Website Copier |"CRLF;
+ a="|Code: Windows Interface Xavier Roche |"CRLF;
+ a="| HTS/HTTrack Xavier Roche |"CRLF;
+ a="| .class Parser Yann Philippot |"CRLF;
+ a="| |"CRLF;
+ a="|Tested on: Windows95,98,NT,2K |"CRLF;
+ a="| Linux PC |"CRLF;
+ a="| Sun-Solaris 5.6 |"CRLF;
+ a="| AIX 4 |"CRLF;
+ a="| |"CRLF;
+ a="|Copyright (C) Xavier Roche and other |"CRLF;
+ a="|contributors |"CRLF;
+ a="| |"CRLF;
+ a="|Use this program at your own risks! |"CRLF;
+ a="+-----------------------------------------------+"CRLF;
+ a=""CRLF;
+}
+
+
+// HTTrack Website Copier Copyright (C) Xavier Roche and other contributors
+//
+