diff options
Diffstat (limited to 'src/htsname.c')
-rw-r--r-- | src/htsname.c | 1266 |
1 files changed, 1266 insertions, 0 deletions
diff --git a/src/htsname.c b/src/htsname.c new file mode 100644 index 0000000..2df0c98 --- /dev/null +++ b/src/htsname.c @@ -0,0 +1,1266 @@ +/* ------------------------------------------------------------ */ +/* +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: httrack.c subroutines: */ +/* savename routine (compute output filename) */ +/* Author: Xavier Roche */ +/* ------------------------------------------------------------ */ + +#include "htsname.h" + +/* specific definitions */ +#include "htsbase.h" +#include "htstools.h" +#include "htsmd5.h" +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +/* END specific definitions */ + +#undef test_flush +#define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); } + +#define ADD_STANDARD_PATH \ + { /* ajout nom */\ + char buff[HTS_URLMAXSIZE*2];\ + buff[0]='\0';\ + strncat(buff,start_pos,(int) (nom_pos - start_pos));\ + url_savename_addstr(save,buff);\ + } + +#define ADD_STANDARD_NAME(shortname) \ + { /* ajout nom */\ + char buff[HTS_URLMAXSIZE*2];\ + standard_name(buff,dot_pos,nom_pos,fil_complete,(shortname));\ + url_savename_addstr(save,buff);\ + } + + +/* Avoid stupid DOS system folders/file such as 'nul' */ +/* Based on linux/fs/umsdos/mangle.c */ +static const char *hts_tbdev[] = +{ + "/prn", "/con", "/aux", "/nul", + "/lpt1", "/lpt2", "/lpt3", "/lpt4", + "/com1", "/com2", "/com3", "/com4", + "/clock$", + "/emmxxxx0", "/xmsxxxx0", "/setverxx", + "" +}; + + + +// forme le nom du fichier à sauver (save) à partir de fil et adr +// système intelligent, qui renomme en cas de besoin (exemple: deux INDEX.HTML et index.html) +int url_savename(char* adr_complete,char* fil_complete,char* save,char* former_adr,char* former_fil,char* referer_adr,char* referer_fil,httrackp* opt,lien_url** liens,int lien_tot,lien_back* back,int back_max,cache_back* cache,hash_struct* hash,int ptr,int numero_passe) { + char newfil[HTS_URLMAXSIZE*2]; /* ="" */ + char* fil; + char* adr; + char* print_adr; + char *start_pos=NULL,*nom_pos=NULL,*dot_pos=NULL; // Position nom et point + // pour changement d'extension ou de nom (content-disposition) + int ext_chg=0; + char ext[256]; + int max_char=0; + //CLEAR + newfil[0]=ext[0]='\0'; + + /* 8-3 ? */ + switch(opt->savename_83) { + case 1: + max_char=8; + break; + case 2: + max_char=30; + break; + default: + max_char=8; + break; + } + + // effacer save + save[0]='\0'; + // fil + fil = fil_complete; + // et adr (sauter user/pass) + // on prend le parti de mettre les fichiers avec login/pass au même endroit que si ils + // étaient capturés sans ces paramètres + // c'est pour cette raison qu'on ignore totalement adr_complete (même pour la recherche en table de hachage) + adr=jump_identification(adr_complete); + + // à afficher sans ftp:// + print_adr=jump_protocol(adr); + + // court-circuit pour lien primaire + if (strnotempty(adr)==0) { + if (strcmp(fil,"primary")==0) { + strcat(save,"primary.html"); + return 0; + } + } + + + // vérifier que le nom n'a pas déja été calculé (si oui le renvoyer tel que) + // vérifier que le nom n'est pas déja pris... + // NOTE: si on cherche /toto/ et que /toto est trouvé on le prend (et réciproquqment) ** // ** + if (liens!=NULL) { + int i; + +#if HTS_HASH + i=hash_read(hash,adr,fil_complete,1); // recherche table 1 (adr+fil) + if (i>=0) { // ok, trouvé + strcpy(save,liens[i]->sav); + return 0; + } + i=hash_read(hash,adr,fil_complete,2); // recherche table 2 (former_adr+former_fil) + if (i>=0) { // ok, trouvé + // copier location moved! + strcpy(adr_complete,liens[i]->adr); + strcpy(fil_complete,liens[i]->fil); + // et save + strcpy(save,liens[i]->sav); // copier (formé à partir du nouveau lien!) + return 0; + } +#else + for(i=lien_tot-1;i>=0;i--) { +#if HTS_CASSE + if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0)) +#else + if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete))) +#endif + { // ok c'est le même lien, adresse déja définie + strcpy(save,liens[i]->sav); + return 0; + } + if (liens[i]->former_adr) { // tester ancienne loc? +#if HTS_CASSE + if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete)==0)) +#else + if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete))) +#endif + { + // copier location moved! + strcpy(adr_complete,liens[i]->adr); + strcpy(fil_complete,liens[i]->fil); + // et save + strcpy(save,liens[i]->sav); // copier (formé à partir du nouveau lien!) + return 0; + } + } + } +#endif + + // chercher sans / ou avec / dans former + { + char fil_complete_patche[HTS_URLMAXSIZE*2]; + strcpy(fil_complete_patche,fil_complete); + // Version avec ou sans / + if (fil_complete_patche[strlen(fil_complete_patche)-1]=='/') + fil_complete_patche[strlen(fil_complete_patche)-1]='\0'; + else + strcat(fil_complete_patche,"/"); +#if HTS_HASH + i=hash_read(hash,adr,fil_complete_patche,2); // recherche table 2 (former_adr+former_fil) + if (i>=0) { + // écraser fil et adr (pas former_fil?????) + strcpy(adr_complete,liens[i]->adr); + strcpy(fil_complete,liens[i]->fil); + // écrire save + strcpy(save,liens[i]->sav); + return 0; + } +#else + // même boucle en gros + for(i=lien_tot-1;i>=0;i--) { + if (liens[i]->former_adr) { // former-adr? +#if HTS_CASSE + if ((strcmp(liens[i]->former_adr,adr)==0) && (strcmp(liens[i]->former_fil,fil_complete_patche)==0)) +#else + if ((strfield2(liens[i]->former_adr,adr)) && (strfield2(liens[i]->former_fil,fil_complete_patche))) +#endif + { // ok c'est le même lien, adresse déja définie + // écraser fil et adr (pas former_fil?????) + strcpy(adr_complete,liens[i]->adr); + strcpy(fil_complete,liens[i]->fil); + // écrire save + strcpy(save,liens[i]->sav); + return 0; + } + } + } +#endif + } + } + + // vérifier la non présence de paramètres dans le nom de fichier + // si il y en a, les supprimer (ex: truc.cgi?subj=aspirateur) + // néanmoins, gardé pour vérifier la non duplication (voir après) + { + char* a; + a=strchr(fil,'?'); + if (a!=NULL) { + strncat(newfil,fil,(int) (a - fil)); + } else { + strcpy(newfil,fil); + } + fil=newfil; + } + // décoder % + strcpy(fil,unescape_http(fil)); + /* + { + char tempo[HTS_URLMAXSIZE*2]; + int i,j=0; + for (i=0;i<(int) strlen(fil);i++) { + if (fil[i]=='%') { + i++; + tempo[j++]=(char) ehex(fil+i); + i++; // sauter 2 caractères finalement + } else + tempo[j++]=fil[i]; + } + tempo[j++]='\0'; + strcpy(fil,tempo); + } + */ + + + /* replace shtml to html.. */ + switch (ishtml(fil)) { /* .html,.shtml,.. */ + case 1: + if ( + (strcmp(get_ext(fil),"html") != 0) + && (strcmp(get_ext(fil),"htm") != 0) + ) { + strcpy(ext,"html"); + ext_chg=1; + } + break; + case 0: + if (!strnotempty(ext)) { + if (is_userknowntype(get_ext(fil))) { // mime known by user + char mime[1024]; + mime[0]=ext[0]='\0'; + get_userhttptype(0,mime,get_ext(fil)); + if (strnotempty(mime)) { + give_mimext(ext,mime); + if (strnotempty(ext)) { + ext_chg=1; + } + } + } + } + break; + } + + + // si option check_type activée + if ((opt->check_type) && (!ext_chg)) { + if ( (!strfield(adr_complete,"file://")) + && (!strfield(adr_complete,"ftp://")) + ) { + // tester type avec requète HEAD si on ne connait pas le type du fichier + if (!( (opt->check_type==1) && (fil[strlen(fil)-1]=='/') )) // slash doit être html? + if (ishtml(fil)<0) { // on ne sait pas si c'est un html ou un fichier.. + // lire dans le cache + htsblk r = cache_read(opt,cache,adr,fil,NULL); // test uniquement + if (r.statuscode != -1) { // pas d'erreur de lecture cache + char s[16]; s[0]='\0'; + if ( (opt->debug>1) && (opt->log!=NULL) ) { + fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type (from cache) %s%s"LF,adr_complete,fil_complete); + test_flush; + } + if (strnotempty(r.cdispo)) { /* filename given */ + ext_chg=2; /* change filename */ + strcpy(ext,r.cdispo); + } + else if (!may_unknown(r.contenttype)) { // on peut patcher à priori? + give_mimext(s,r.contenttype); // obtenir extension + if (strnotempty(s)>0) { // on a reconnu l'extension + ext_chg=1; + strcpy(ext,s); + } + } + // + } else { // test imposible dans le cache, faire une requête + // +#if HTS_ANALYSTE + int hihp=_hts_in_html_parsing; +#endif + int has_been_moved=0; + char curr_adr[HTS_URLMAXSIZE*2],curr_fil[HTS_URLMAXSIZE*2]; + curr_adr[0]=curr_fil[0]='\0'; +#if HTS_ANALYSTE + _hts_in_html_parsing=2; // test +#endif + if ( (opt->debug>1) && (opt->log!=NULL) ) { + fspc(opt->log,"debug"); fprintf(opt->log,"Testing link type %s%s"LF,adr_complete,fil_complete); + test_flush; + } + strcpy(curr_adr,adr_complete); + strcpy(curr_fil,fil_complete); + // ajouter dans le backing le fichier en mode test + // savename: rien car en mode test + if (back_add(back,back_max,opt,cache,curr_adr,curr_fil,BACK_ADD_TEST,referer_adr,referer_fil,1,NULL)!=-1) { + int b; + b=back_index(back,back_max,curr_adr,curr_fil,BACK_ADD_TEST); + if (b>=0) { + int petits_tours=0; + int get_test_request=0; // en cas de bouclage sur soi même avec HEAD, tester avec GET.. parfois c'est la cause des problèmes + do { + // temps à attendre, et remplir autant que l'on peut le cache (backing) + if (back[b].status>0) back_wait(back,back_max,opt,cache,0); + if (ptr>=0) + back_fillmax(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot); + + // on est obligé d'appeler le shell pour le refresh.. +#if HTS_ANALYSTE + { + + // 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)) { + return -1; + } else if (_hts_cancel) { // cancel 2 ou 1 (cancel parsing) + back_delete(back,b); // cancel test + } + } +#endif + + + // traitement des 304,303.. + if (back[b].status<=0) { + if ( (back[b].r.statuscode==301) + || (back[b].r.statuscode==302) + || (back[b].r.statuscode==303) + || (back[b].r.statuscode==307) + ) { // agh moved.. un tit tour de plus + if ((petits_tours<5) && (former_adr) && (former_fil)) { // on va pas tourner en rond non plus! + if ((int) strnotempty(back[b].r.location)) { // location existe! + char mov_url[HTS_URLMAXSIZE*2],mov_adr[HTS_URLMAXSIZE*2],mov_fil[HTS_URLMAXSIZE*2]; + mov_url[0]=mov_adr[0]=mov_fil[0]='\0'; + // + strcpy(mov_url,back[b].r.location); // copier URL + if (ident_url_relatif(mov_url,curr_adr,curr_fil,mov_adr,mov_fil)>=0) { + // si non bouclage sur soi même, ou si test avec GET non testé + if ((strcmp(mov_adr,curr_adr)) || (strcmp(mov_fil,curr_fil)) || (get_test_request==0)) { + // bouclage? + if ((!strcmp(mov_adr,curr_adr)) && (!strcmp(mov_fil,curr_fil))) + get_test_request=1; // faire requète avec GET + + // recopier former_adr/fil? + if ((former_adr) && (former_fil)) { + if (strnotempty(former_adr)==0) { // Pas déja noté + strcpy(former_adr,curr_adr); + strcpy(former_fil,curr_fil); + } + } + + // check explicit forbidden - don't follow 3xx in this case + { + int set_prio_to=0; + robots_wizard* robots = (robots_wizard*) opt->robotsptr; + if (hts_acceptlink(opt,ptr,lien_tot,liens, + mov_adr,mov_fil, + opt->filters.filters,opt->filters.filptr,opt->maxfilter, + robots, + &set_prio_to, + NULL) == 1) + { /* forbidden */ + has_been_moved = 1; + back_delete(back,b); // ok + strcpy(curr_adr,mov_adr); + strcpy(curr_fil,mov_fil); + mov_url[0]='\0'; + } + } + + // ftp: stop! + if (strfield(mov_url,"ftp://")) { // ftp, ok on arrête + has_been_moved = 1; + back_delete(back,b); // ok + strcpy(curr_adr,mov_adr); + strcpy(curr_fil,mov_fil); + } else if (*mov_url) { + char* methode; + if (!get_test_request) + methode=BACK_ADD_TEST; // tester avec HEAD + else { + methode=BACK_ADD_TEST2; // tester avec GET + if ( opt->errlog!=NULL ) { + fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Loop with HEAD request (during prefetch) at %s%s"LF,curr_adr,curr_fil); + test_flush; + } + } + // Ajouter + if (back_add(back,back_max,opt,cache,mov_adr,mov_fil,methode,referer_adr,referer_fil,1,NULL)!=-1) { // OK + if ( (opt->debug>1) && (opt->errlog!=NULL) ) { + fspc(opt->errlog,"warning"); fprintf(opt->errlog,"(during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil); + test_flush; + } + + // libérer emplacement backing actuel et attendre le prochain + back_delete(back,b); + strcpy(curr_adr,mov_adr); + strcpy(curr_fil,mov_fil); + b=back_index(back,back_max,curr_adr,curr_fil,methode); + if (!get_test_request) + has_been_moved = 1; // sinon ne pas forcer has_been_moved car non déplacé + petits_tours++; + // + } else {// sinon on fait rien et on s'en va.. (ftp etc) + if ( (opt->debug>1) && (opt->errlog)) { + fspc(opt->errlog,"debug"); fprintf(opt->errlog,"Warning: Savename redirect backing error at %s%s"LF,mov_adr,mov_fil); + test_flush; + } + } + } + } else { + if ( opt->errlog!=NULL ) { + fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop to same filename)"LF,adr_complete,fil_complete); + test_flush; + } + } + + } + } + } else{ // arrêter les frais + if ( opt->errlog!=NULL ) { + fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Unable to test %s%s (loop)"LF,adr_complete,fil_complete); + test_flush; + } + } + } // ok, leaving + } + + } while(back[b].status>0); + + // Si non déplacé, forcer type? + if (!has_been_moved) { + if (back[b].r.statuscode!=-10) { // erreur + if (strnotempty(back[b].r.contenttype)==0) + strcpy(back[b].r.contenttype,"text/html"); // message d'erreur en html + // Finalement on, renvoie un erreur, pour ne toucher à rien dans le code + // libérer emplacement backing + /*if (opt->errlog!=NULL) { + fspc(opt->errlog,0); fprintf(opt->errlog,"Error: (during prefetch) %s (%d) to link %s at %s%s"LF,back[b].r.msg,back[b].r.statuscode,back[b].r.location,curr_adr,curr_fil); + test_flush; + } + back_delete(back,b); + return -1; // ERREUR (404 par exemple) + */ + } + + { // pas d'erreur, changer type? + char s[16]; + s[0]='\0'; + if (strnotempty(back[b].r.cdispo)) { /* filename given */ + ext_chg=2; /* change filename */ + strcpy(ext,back[b].r.cdispo); + } + else if ((!may_unknown(back[b].r.contenttype)) || (!get_ext(back[b].url_fil)) ) { // on peut patcher à priori? (pas interdit ou pas de type) + give_mimext(s,back[b].r.contenttype); // obtenir extension + if (strnotempty(s)>0) { // on a reconnu l'extension + ext_chg=1; + strcpy(ext,s); + } + } + } + } + // FIN Si non déplacé, forcer type? + + // libérer emplacement backing + back_delete(back,b); + + // --- --- --- + // oops, a été déplacé.. on recalcule en récursif (osons!) + if (has_been_moved) { + // copier adr, fil (optionnel, mais sinon marche pas pour le rip) + strcpy(adr_complete,curr_adr); + strcpy(fil_complete,curr_fil); + // copier adr, fil + + return url_savename(curr_adr,curr_fil,save,NULL,NULL,referer_adr,referer_fil,opt,liens,lien_tot,back,back_max,cache,hash,ptr,numero_passe); + } + // --- --- --- + + } + + } else { + printf("PANIC! : Savename Crash adding error, unexpected error found.. [%d]\n",__LINE__); +#if BDEBUG==1 + printf("error while savename crash adding\n"); +#endif + if (opt->errlog) { + fspc(opt->errlog,"error"); fprintf(opt->errlog,"Unexpected savename backing error at %s%s"LF,adr,fil_complete); + test_flush; + } + + } + // restaurer +#if HTS_ANALYSTE + _hts_in_html_parsing=hihp; +#endif + } // caché? + } + } + } + + + + // - - - DEBUT NOMMAGE - - - + + // Donner nom par défaut? + if (fil[strlen(fil)-1]=='/') { + if (!strfield(adr_complete,"ftp://")) + strcat(fil,DEFAULT_HTML); // nommer page par défaut!! + else { + if (!opt->proxy.active) + strcat(fil,DEFAULT_FTP); // nommer page par défaut (texte) + else + strcat(fil,DEFAULT_HTML); // nommer page par défaut (à priori ici html depuis un proxy http) + } + } + // Changer extension? + // par exemple, php3 sera sauvé en html, cgi en html ou gif, xbm etc.. selon les cas + if (ext_chg) { // changer ext + char* a=fil+strlen(fil)-1; + if ( (opt->debug>1) && (opt->log!=NULL) ) { + fspc(opt->log,"debug"); + if (ext_chg==1) + fprintf(opt->log,"Changing link extension %s%s to .%s"LF,adr_complete,fil_complete,ext); + else + fprintf(opt->log,"Changing link name %s%s to %s"LF,adr_complete,fil_complete,ext); + test_flush; + } + if (ext_chg==1) { + while((a > fil) && (*a!='.') && (*a!='/')) a--; + if (*a=='.') *a='\0'; // couper + strcat(fil,"."); // recopier point + } else { + while(( a > fil) && (*a!='/')) a--; + if (*a=='/') a++; + *a='\0'; + } + strcat(fil,ext); // copier ext/nom + } + + // Rechercher premier / et dernier . + { + char* a=fil+strlen(fil)-1; + + // passer structures + start_pos=fil; + while(( a > fil) && (*a != '/') && (*a != '\\')) { + if (*a == '.') // point? noter position + if (!dot_pos) + dot_pos=a; + a--; + } + if ((*a=='/') || (*a=='\\')) a++; + nom_pos = a; + } + + + // un nom de fichier est généré + // s'il existe déja, alors on le mofifie légèrement + + // ajouter nom du site éventuellement en premier + if (opt->savename_type == -1) { // utiliser savename_userdef! (%h%p/%n%q.%t) + char* a = opt->savename_userdef; + char* b = save; + /*char *nom_pos=NULL,*dot_pos=NULL; // Position nom et point */ + char tok; + + /* + { // Rechercher premier / + char* a=fil+strlen(fil)-1; + // passer structures + while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) { + if (*a == '.') // point? noter position + if (!dot_pos) + dot_pos=a; + a--; + } + if ((*a=='/') || (*a=='\\')) a++; + nom_pos = a; + } + */ + + // Construire nom + while ((*a) && (((int) (b - save)) < HTS_URLMAXSIZE ) ) { // parser, et pas trop long.. + if (*a == '%') { + int short_ver=0; + a++; + if (*a == 's') { + short_ver=1; + a++; + } + *b='\0'; + switch(tok=*a++) { + case '[': // %[param] + if (strchr(a,']')) { + char name[256]; + char* c=name; + while(*a!=']') { + *c++=*a++; + } + a++; + *c++='\0'; + strcat(name,"="); /* param=.. */ + c=strchr(fil_complete,'?'); + /* parameters exists */ + if (c) { + c=strstr(c,name); /* finds param= */ + if (c) { + c+=strlen(name); /* jumps "param=" */ + while( (*c) && (*c!='&')) + *b++=*c++; + } + } + } + break; + case '%': *b++='%'; break; + case 'n': // nom sans ext + if (dot_pos) { + if (!short_ver) // Noms longs + strncat(b,nom_pos,(int) (dot_pos - nom_pos)); + else + strncat(b,nom_pos,min((int) (dot_pos - nom_pos),8)); + } else { + if (!short_ver) // Noms longs + strcpy(b,nom_pos); + else + strncat(b,nom_pos,8); + } + b+=strlen(b); // pointer à la fin + break; + case 'N': // nom avec ext + // RECOPIE NOM + EXT + *b='\0'; + if (dot_pos) { + if (!short_ver) // Noms longs + strncat(b,nom_pos,(int) (dot_pos - nom_pos)); + else + strncat(b,nom_pos,min((int) (dot_pos - nom_pos),8)); + } else { + if (!short_ver) // Noms longs + strcpy(b,nom_pos); + else + strncat(b,nom_pos,8); + } + b+=strlen(b); // pointer à la fin + // RECOPIE NOM + EXT + *b='\0'; + if (dot_pos) { + if (!short_ver) // Noms longs + strcpy(b,dot_pos+1); + else + strncat(b,dot_pos+1,3); + } else { + if (!short_ver) // Noms longs + strcpy(b,DEFAULT_EXT); // pas de.. + else + strcpy(b,DEFAULT_EXT_SHORT); // pas de.. + } + b+=strlen(b); // pointer à la fin + // + break; + case 't': // ext + *b='\0'; + if (dot_pos) { + if (!short_ver) // Noms longs + strcpy(b,dot_pos+1); + else + strncat(b,dot_pos+1,3); + } else { + if (!short_ver) // Noms longs + strcpy(b,DEFAULT_EXT); // pas de.. + else + strcpy(b,DEFAULT_EXT_SHORT); // pas de.. + } + b+=strlen(b); // pointer à la fin + break; + case 'p': // path sans dernier / + *b='\0'; + if (nom_pos != fil + 1) { // pas: /index.html (chemin nul) + if (!short_ver) { // Noms longs + strncat(b,fil,(int) (nom_pos - fil) - 1); + } else { + char pth[HTS_URLMAXSIZE*2],n83[HTS_URLMAXSIZE*2]; + pth[0]=n83[0]='\0'; + // + strncat(pth,fil,(int) (nom_pos - fil) - 1); + long_to_83(opt->savename_83,n83,pth); + strcpy(b,n83); + } + } + b+=strlen(b); // pointer à la fin + break; + case 'h': // host + *b='\0'; + if (strcmp(adr_complete,"file://")==0) { + if (!short_ver) // Noms longs + strcpy(b,"localhost"); + else + strcpy(b,"local"); + } else { + if (!short_ver) // Noms longs + strcpy(b,print_adr); + else + strncat(b,print_adr,8); + } + b+=strlen(b); // pointer à la fin + break; + case 'M': /* host/address?query MD5 (128-bits) */ + *b='\0'; + { + char digest[32+2]; + char buff[HTS_URLMAXSIZE*2]; + digest[0]=buff[0]='\0'; + strcpy(buff,adr); + strcat(buff,fil_complete); + domd5mem(buff,strlen(buff),digest,1); + strcpy(b,digest); + } + b+=strlen(b); // pointer à la fin + break; + case 'Q': case 'q': /* query MD5 (128-bits/16-bits) + GENERATED ONLY IF query string exists! */ + *b='\0'; + strncat(b,url_md5(fil_complete),(tok == 'Q')?32:4); + b+=strlen(b); // pointer à la fin + break; + } + } else + *b++=*a++; + } + *b++='\0'; + // + // Types prédéfinis + // + + } + // + // Structure originale + else if (opt->savename_type%100==0) { + /* recopier www.. */ + if (opt->savename_type!=100) { + if (((opt->savename_type/1000)%2)==0) { // >1000 signifie "pas de www/" + if (strcmp(adr_complete,"file://")==0) { + //## if (*adr==lOCAL_CHAR) { + if (opt->savename_83 != 1) // noms longs + strcat(save,"localhost"); + else + strcat(save,"local"); + } else { + // adresse url + if (!opt->savename_83) { // noms longs (et pas de .) + strcat(save,print_adr); + } else { // noms 8-3 + if (strlen(print_adr)>4) { + if (strfield(print_adr,"www.")) + strncat(save,print_adr+4,max_char); + else + strncat(save,print_adr,8); + } else strncat(save,print_adr,max_char); + } + } + if (*fil!='/') strcat(save,"/"); + } + } + +#if HTS_CASSE==0 + hts_lowcase(save); +#endif + + /* + // ne sert à rien car a déja été filtré normalement + if ((*fil=='.') && (*(fil+1)=='/')) // ./index.html ** // + url_savename_addstr(save,fil+2); + else // index.html ou /index.html + url_savename_addstr(save,fil); + if (save[strlen(save)-1]=='/') + strcat(save,DEFAULT_HTML); // nommer page par défaut!! +*/ + + /* add name */ + ADD_STANDARD_PATH; + ADD_STANDARD_NAME(0); + + } + // + // Structure html/image + else { + // dossier "web" ou "www.xxx" ? + if (((opt->savename_type/1000)%2)==0) { // >1000 signifie "pas de www/" + if ((opt->savename_type/100)%2) { + if (strcmp(adr_complete,"file://")==0) { + //## if (*adr==lOCAL_CHAR) { + if (opt->savename_83 != 1) // noms longs + strcat(save,"localhost/"); + else + strcat(save,"local/"); + } else { + // adresse url + if (!opt->savename_83) { // noms longs + strcat(save,print_adr); strcat(save,"/"); + } else { // noms 8-3 + if (strlen(print_adr)>4) { + if (strfield(print_adr,"www.")) + strncat(save,print_adr+4,max_char); + else + strncat(save,print_adr,max_char); + strcat(save,"/"); + } else { + strncat(save,print_adr,max_char); strcat(save,"/"); + } + } + } + } else { + strcat(save,"web/"); // répertoire général + } + } + + // si un html à coup sûr + if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) { + if (opt->savename_type%100==2) { // html/ + strcat(save,"html/"); + } + } else { + if ((opt->savename_type%100==1) || (opt->savename_type%100==2)) { // html & images + strcat(save,"images/"); + } + } + + switch (opt->savename_type%100) { + case 4: case 5: { // séparer par types + char* a=fil+strlen(fil)-1; + // passer structures + while(( a > fil) && (*a != '/') && (*a != '\\')) a--; + if ((*a=='/') || (*a=='\\')) a++; + + // html? + if ( (ext_chg!=0) ? (ishtml_ext(ext)==1) : (ishtml(fil)==1) ) { + if (opt->savename_type%100==5) + strcat(save,"html/"); + } else { + char* a=fil+strlen(fil)-1; + while(( a> fil) && (*a != '/') && (*a != '.')) a--; + if (*a!='.') + strcat(save,"other"); + else + strcat(save,a+1); + strcat(save,"/"); + } + /*strcat(save,a);*/ + /* add name */ + ADD_STANDARD_NAME(0); + } + break; + case 99: { // 'codé' .. c'est un gadget + int i; + int j; + char* a; + char C[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-"; + int L; + // pseudo-CRC sur fil et adr pour initialiser générateur aléatoire.. + unsigned int s=0; + L=strlen(C); + for(i=0;i<(int) strlen(fil_complete);i++) { + s+=(unsigned int) fil_complete[i]; + } + for(i=0;i<(int) strlen(adr_complete);i++) { + s+=(unsigned int) adr_complete[i]; + } + srand(s); + + j=strlen(save); + for(i=0;i<8;i++) { + char c=C[(rand()%L)]; + save[i+j]=c; + } + save[i+j]='\0'; + // ajouter extension + a=fil+strlen(fil)-1; + while(( a > fil) && (*a != '/') && (*a != '.')) a--; + if (*a=='.') { + strcat(save,a); // ajouter + } + } + break; + default: { // noms sans les noms des répertoires + // ne garder que le nom, pas la structure + /* + char* a=fil+strlen(fil)-1; + while(((int) a>(int) fil) && (*a != '/') && (*a != '\\')) a--; + if ((*a=='/') || (*a=='\\')) a++; + strcat(save,a); + */ + + /* add name */ + ADD_STANDARD_NAME(0); + } + break; + } + +#if HTS_CASSE==0 + hts_lowcase(save); +#endif + + if (save[strlen(save)-1]=='/') + strcat(save,DEFAULT_HTML); // nommer page par défaut!! + } + + + // vérifier qu'on ne doit pas forcer l'extension + // par exemple, asp sera sauvé en html, cgi en html ou gif, xbm etc.. selon les cas + /*if (ext_chg) { + char* a=save+strlen(save)-1; + while(((int) a>(int) save) && (*a!='.') && (*a!='/')) a--; + if (*a=='.') *a='\0'; // couper + // recopier extension + strcat(save,"."); + strcat(save,ext); // copier ext + }*/ + // de même en cas de manque d'extension on en place une de manière forcée.. + // cela évite les /chez/toto et les /chez/toto/index.html incompatibles + if (opt->savename_type != -1) { + char* a=save+strlen(save)-1; + while(( a > save) && (*a!='.') && (*a!='/')) a--; + if (*a!='.') { // agh pas de point + //strcat(save,".none"); // a éviter + strcat(save,".html"); // préférable! + if ( (opt->debug>1) && (opt->errlog!=NULL) ) { + fspc(opt->errlog,"warning"); fprintf(opt->errlog,"Default HTML type set for %s%s"LF,adr_complete,fil_complete); + test_flush; + } + } + } + + // effacer pass au besoin pour les autentifications + // (plus la peine : masqué au début) +/* + { + char* a=jump_identification(save); + if (a!=save) { + char tempo[HTS_URLMAXSIZE*2]; + char *b; + tempo[0]='\0'; + strcpy(tempo,"["); + b=strchr(save,':'); + if (!b) b=strchr(save,'@'); + if (b) + strncat(tempo,save,(int) b-(int) a); + strcat(tempo,"]"); + strcat(tempo,a); + strcpy(save,a); + } + } +*/ + + // éviter les / au début (cause: N100) + if (save[0]=='/') { + char tempo[HTS_URLMAXSIZE*2]; + strcpy(tempo,save+1); + strcpy(save,tempo); + } + + // changer les ~,:,",*,? en _ pour sauver sur disque + hts_replace(save,'~','_'); // interdit sous unix (~foo) + // + hts_replace(save,'\\','_'); + hts_replace(save,':','_'); // interdit sous windows + hts_replace(save,'*','_'); // interdit sous windows + hts_replace(save,'?','_'); // doit pas arriver!! + hts_replace(save,'\"','_'); // interdit sous windows + hts_replace(save,'<','_'); // interdit sous windows + hts_replace(save,'>','_'); // interdit sous windows + hts_replace(save,'|','_'); // interdit sous windows + // + hts_replace(save,'@','_'); + // + { // éliminer les // (comme ftp://) + char* a; + while( (a=strstr(save,"//")) ) *a='_'; + // Eliminer chars spéciaux + a=save -1 ; + while(*(++a)) + if ( ((unsigned char)(*a) <= 31) + || ((unsigned char)(*a) == 127) ) + *a='_'; + } + + +#if HTS_OVERRIDE_DOS_FOLDERS + /* Replace /foo/nul/bar by /foo/nul-/bar */ + { + int i=0; + while(hts_tbdev[i][0]) { + char* a=save; + while((a=strstr(a,hts_tbdev[i]))) { + switch ( (int) a[strlen(hts_tbdev[i])] ) { + case '\0': + case '/': { + char tempo[HTS_URLMAXSIZE*2]; tempo[0]='\0'; + strncat(tempo,save,(int) (a - save) + strlen(hts_tbdev[i])); + strcat(tempo,"-"); + strcat(tempo,a+strlen(hts_tbdev[i])); + strcpy(save,tempo); + } + break; + } + a+=strlen(hts_tbdev[i]); + } + i++; + } + } +#endif + + // conversion 8-3 .. y compris pour les répertoires + if (opt->savename_83) { + char n83[HTS_URLMAXSIZE*2]; + long_to_83(opt->savename_83,n83,save); + strcpy(save,n83); + } + + + /* ensure that there is no ../ (potential vulnerability) */ + fil_simplifie(save); + +#if HTS_ANALYSTE + { + hts_htmlcheck_savename(adr_complete,fil_complete,referer_adr,referer_fil,save); + if ( (opt->debug>0) && (opt->log!=NULL) ) { + fspc(opt->log,"info"); fprintf(opt->log,"engine: save-name: local name: %s%s -> %s"LF,adr,fil,save); + test_flush; + } + } +#endif + + // chemin primaire éventuel A METTRE AVANT + if (strnotempty(opt->path_html)) { + char tempo[HTS_URLMAXSIZE*2]; + strcpy(tempo,opt->path_html); + strcat(tempo,save); + strcpy(save,tempo); + } + + + // vérifier que le nom n'est pas déja pris... + if (liens!=NULL) { + int nom_ok; + do { + int i; + int len; + len=strlen(save); // taille + // + nom_ok=1; // à priori bon + // on part de la fin pour optimiser, plus les opti de taille pour aller encore plus vite.. +#if DEBUG_SAVENAME +printf("\nStart search\n"); +#endif + +#if HTS_HASH + i=hash_read(hash,save,"",0); // lecture type 0 (sav) + if (i>=0) +#else + for(i=lien_tot-1;i>=0;i--) { +#if DEBUG_SAVENAME +printf("%cParse: %d",13,i); +#endif + + if (liens[i]->sav_len==len) { // même taille de chaîne +#if HTS_CASSE + if (strcmp(liens[i]->sav,save)==0) // existe déja +#else + if (strfield2(liens[i]->sav,save)) // un tel nom existe déja +#endif +#endif + { +#if HTS_CASSE + if ((strcmp(liens[i]->adr,adr)==0) && (strcmp(liens[i]->fil,fil_complete)==0)) +#else + if ((strfield2(liens[i]->adr,adr)) && (strfield2(liens[i]->fil,fil_complete))) +#endif + { // ok c'est le même lien, adresse déja définie + //printf("Ok, %s\n",save); + //i=lien_tot; // sortir + i=0; +#if DEBUG_SAVENAME +printf("\nOK ALREADY DEFINED\n",13,i); +#endif + } else { // utilisé par un AUTRE, changer de nom + char tempo[HTS_URLMAXSIZE*2]; + char* a=save+strlen(save)-1; + char* b; + int n=2; + tempo[0]='\0'; + +#if DEBUG_SAVENAME +printf("\nWRONG CASE UNMATCH : \n%s\n%s, REDEFINE\n",liens[i]->fil,fil_complete); +#endif + nom_ok=0; + i=0; + + while(( a > save) && (*a!='.') && (*a!='\\') && (*a!='/')) a--; + if (*a=='.') + strncat(tempo,save,(int) (a - save)); + else + strcat(tempo,save); + + // tester la présence d'un -xx (ex: index-2.html -> index-3.html) + b=tempo+strlen(tempo)-1; + while (isdigit((unsigned char)*b)) b--; + if (*b=='-') { + sscanf(b+1,"%d",&n); + *b='\0'; // couper + n++; // plus un + } + + // en plus il faut gérer le 8-3 .. pas facile le client + if (opt->savename_83) { + int max; + char* a=tempo+strlen(tempo)-1; + while(( a > tempo) && (*a!='/')) a--; + if (*a=='/') a++; + max=max_char-1-nombre_digit(n); + if ((int) strlen(a)>max) + *(a+max)='\0'; // couper sinon il n'y aura pas la place! + } + + // ajouter -xx (ex: index.html -> index-2.html) + sprintf(tempo+strlen(tempo),"-%d",n); + + // ajouter extension + if (*a=='.') + strcat(tempo,a); + + strcpy(save,tempo); + + //printf("switched: %s\n",save); + + } // if +#if HTS_HASH + } +#else + } // if + } // if sav_len + } // for +#endif +#if DEBUG_SAVENAME +printf("\nEnd search, %s\n",fil_complete); +#endif + } while(!nom_ok); + + } + + //printf("'%s' %s %s\n",save,adr,fil); + + return 0; +} + +/* nom avec md5 urilisé partout */ +void standard_name(char* b,char* dot_pos,char* nom_pos,char* fil_complete,int short_ver) { + b[0]='\0'; + /* Nom */ + if (dot_pos) { + if (!short_ver) // Noms longs + strncat(b,nom_pos,(int) (dot_pos - nom_pos)); + else + strncat(b,nom_pos,min((int) (dot_pos - nom_pos),8)); + } else { + if (!short_ver) // Noms longs + strcat(b,nom_pos); + else + strncat(b,nom_pos,8); + } + /* MD5 - 16 bits */ + strncat(b,url_md5(fil_complete),4); + /* Ext */ + if (dot_pos) { + strcat(b,"."); + if (!short_ver) // Noms longs + strcat(b,dot_pos+1); + else + strncat(b,dot_pos+1,3); + } else { + if (!short_ver) // Noms longs + strcat(b,DEFAULT_EXT); // pas de.. + else + strcat(b,DEFAULT_EXT_SHORT); // pas de.. + } +} + + +/* Petit md5 */ +char* url_md5(char* fil_complete) { + char* digest; + char* a; + NOSTATIC_RESERVE(digest, char, 32+2); + digest[0]='\0'; + a=strchr(fil_complete,'?'); + if (a) { + if (strlen(a)) { + char buff[HTS_URLMAXSIZE*2]; + a++; + digest[0]=buff[0]='\0'; + strcat(buff,a); /* query string MD5 */ + domd5mem(buff,strlen(buff),digest,1); + } + } + return digest; +} + +// interne à url_savename: ajoute une chaîne à une autre avec \ -> / +void url_savename_addstr(char* d,char* s) { + int i=strlen(d); + while(*s) { + if (*s=='\\') // remplacer \ par des / + d[i++]='/'; + else + d[i++]=*s; + s++; + } + d[i]='\0'; +} + +#undef test_flush |