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

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche, Yann Philippot and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. This project has been developed by Xavier Roche and Yann Philippot,
  29. from the company Serianet at Caen, France (http://www.serianet.com)
  30. and other contributors (see the greetings file)
  31.  
  32. Please visit our Website: http://www.httrack.com
  33. */
  34.  
  35.  
  36. /* ------------------------------------------------------------ */
  37. /* File: Subroutines                                            */
  38. /* Author: Xavier Roche                                         */
  39. /* ------------------------------------------------------------ */
  40.  
  41. // Fichier librairie .c
  42.  
  43. #include "htslib.h"
  44. #include "htsbauth.h"
  45.  
  46. /* specific definitions */
  47. #include "htsbase.h"
  48. #include "htsnet.h"
  49. #include "htsbauth.h"
  50. #include "htsthread.h"
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <time.h>
  55. #include <sys/timeb.h>
  56. #include <fcntl.h>
  57. // pour utimbuf
  58. #if HTS_WIN
  59. #include <sys/utime.h>
  60. #else
  61. #if HTS_PLATFORM!=3
  62. #include <utime.h>
  63. #else
  64. #include <utime.h>
  65. #endif
  66. #endif
  67. /* END specific definitions */
  68.  
  69.  
  70.  
  71. // DΘbuggage de contr⌠le
  72. #if HTS_DEBUG_CLOSESOCK
  73. #define _HTS_WIDE 1
  74. #endif
  75. #if HTS_WIDE_DEBUG
  76. #define _HTS_WIDE 1
  77. #endif
  78. #if _HTS_WIDE
  79. FILE* DEBUG_fp=NULL;
  80. #define DEBUG_W(A)  { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,":>"A); fflush(DEBUG_fp); }
  81. #define DEBUG_W2(A) { if (DEBUG_fp==NULL) DEBUG_fp=fopen("bug.out","wb"); fprintf(DEBUG_fp,A); fflush(DEBUG_fp); }
  82. #endif
  83.  
  84. /* variables globales */
  85. int _DEBUG_HEAD;
  86. FILE* ioinfo;
  87.  
  88. /* dΘtection complΘmentaire */
  89. const char hts_detect[][32] = {
  90.   "archive",
  91.   "background",
  92.   "dynsrc",
  93.   "lowsrc",
  94.   "src",
  95.   "url",
  96.   ""
  97. };
  98.  
  99. /* dΘtection de mini-code javascript */
  100. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  101. const char hts_detect_js[][32] = {
  102.   "onAbort",
  103.   "onBlur",
  104.   "onChange",
  105.   "onClick",
  106.   "onDblClick",
  107.   "onDragDrop",
  108.   "onError",
  109.   "onFocus",
  110.   "onKeyDown",
  111.   "onKeyPress",
  112.   "onKeyUp",
  113.   "onLoad",
  114.   "onMouseDown",
  115.   "onMouseMove",
  116.   "onMouseOut",
  117.   "onMouseOver",
  118.   "onMouseUp",
  119.   "onMove",
  120.   "onReset",
  121.   "onResize",
  122.   "onSelect",
  123.   "onSubmit",
  124.   "onUnload",
  125.   ""
  126. };
  127.  
  128. /* dΘtection "...URL=<url>" */
  129. const char hts_detectURL[][32] = {
  130.   "content",
  131.   ""
  132. };
  133.  
  134. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  135. const char hts_detectandleave[][32] = {
  136.   "action",
  137.   ""
  138. };
  139.  
  140. /* ne pas renommer les types renvoyΘs (couvent types inconnus) */
  141. const char hts_mime_keep[][32] = {
  142.   "application/octet-stream",
  143.   "text/plain",
  144.   ""
  145. };
  146.  
  147. /* types MIME */
  148. const char hts_mime[][2][32] = {
  149.   {"application/acad","dwg"},
  150.   {"application/arj","arj"},
  151.   {"application/clariscad","ccad"},
  152.   {"application/drafting","drw"},
  153.   {"application/dxf","dxf"},
  154.   {"application/excel","xl"},
  155.   {"application/i-deas","unv"},
  156.   {"application/iges","isg"},
  157.   {"application/iges","iges"},
  158.   {"application/mac-binhex40","hqx"},
  159.   {"application/mac-compactpro","cpt"},
  160.   {"application/msword","word"},
  161.   {"application/msword","w6w"},
  162.   {"application/msword","doc"},
  163.   {"application/mswrite","wri"},
  164.   /*{"application/octet-stream","dms"},*/
  165.   /*{"application/octet-stream","lzh"},*/
  166.   /*{"application/octet-stream","lha"},*/
  167.   /*{"application/octet-stream","bin"},*/
  168.   {"application/oda","oda"},
  169.   {"application/pdf","pdf"},
  170.   {"application/postscript","ai"},
  171.   {"application/postscript","ps"},
  172.   {"application/postscript","eps"},
  173.   {"application/powerpoint","ppt"},
  174.   {"application/pro_eng","prt"},
  175.   {"application/pro_eng","part"},
  176.   {"application/rtf","rtf"},
  177.   {"application/set","set"},
  178.   {"application/sla","stl"},
  179.   {"application/smil","smi"},
  180.   {"application/smil","smil"},
  181.   {"application/smil","sml"},
  182.   {"application/solids","sol"},
  183.   {"application/STEP","stp"},
  184.   {"application/STEP","step"},
  185.   {"application/vda","vda"},
  186.   {"application/x-authorware-map","aam"},     
  187.   {"application/x-authorware-seg","aas"},
  188.   {"application/x-authorware-bin","aab"},
  189.   {"application/x-cocoa","cco"},
  190.   {"application/x-csh","csh"},
  191.   {"application/x-director","dir"},
  192.   {"application/x-director","dcr"},
  193.   {"application/x-director","dxr"},
  194.   {"application/x-mif","mif"},
  195.   {"application/x-dvi","dvi"},
  196.   {"application/x-gzip","gz"},
  197.   {"application/x-gzip","gzip"},
  198.   {"application/x-hdf","hdf"},
  199.   {"application/x-javascript","js"},
  200.   {"application/x-koan","skp"},
  201.   {"application/x-koan","skd"},
  202.   {"application/x-koan","skt"},
  203.   {"application/x-koan","skm"},
  204.   {"application/x-latex","latex"},
  205.   {"application/x-netcdf","nc"},
  206.   {"application/x-netcdf","cdf"},
  207.   /* {"application/x-sh","sh"}, */
  208.   /* {"application/x-csh","csh"}, */
  209.   /* {"application/x-ksh","ksh"}, */
  210.   {"application/x-shar","shar"},
  211.   {"application/x-stuffit","sit"},
  212.   {"application/x-tcl","tcl"},
  213.   {"application/x-tex","tex"},
  214.   {"application/x-texinfo","texinfo"},
  215.   {"application/x-texinfo","texi"},
  216.   {"application/x-troff","t"},
  217.   {"application/x-troff","tr"},
  218.   {"application/x-troff","roff"},
  219.   {"application/x-troff-man","man"},
  220.   {"application/x-troff-me","ms"},
  221.   {"application/x-wais-source","src"},
  222.   {"application/zip","zip"},
  223.   {"application/x-bcpio","bcpio"},
  224.   {"application/x-cdlink","vcd"},
  225.   {"application/x-cpio","cpio"},
  226.   {"application/x-gtar","tgz"},
  227.   {"application/x-gtar","gtar"},
  228.   {"application/x-shar","shar"},
  229.   {"application/x-shockwave-flash","swf"},
  230.   {"application/x-sv4cpio","sv4cpio"},
  231.   {"application/x-sv4crc","sv4crc"},
  232.   {"application/x-tar","tar"},
  233.   {"application/x-ustar","ustar"},
  234.   {"application/x-winhelp","hlp"},
  235.   {"audio/midi","mid"},
  236.   {"audio/midi","midi"},
  237.   {"audio/midi","kar"},
  238.   {"audio/mpeg","mp3"},
  239.   {"audio/mpeg","mpga"},
  240.   {"audio/mpeg","mp2"},
  241.   {"audio/basic","au"},
  242.   {"audio/basic","snd"},
  243.   {"audio/x-aiff","aif"},
  244.   {"audio/x-aiff","aiff"},
  245.   {"audio/x-aiff","aifc"},
  246.   {"audio/x-pn-realaudio","ra"},
  247.   {"audio/x-pn-realaudio","ram"},
  248.   {"audio/x-pn-realaudio-plugin","rpm"},
  249.   {"audio/x-wav","wav"},
  250.   {"chemical/x-pdb","pdb"},
  251.   {"chemical/x-pdb","xyz"},
  252.   {"drawing/x-dwf","dwf"},
  253.   {"image/gif","gif"},
  254.   {"image/ief","ief"},
  255.   {"image/jpeg","jpg"},
  256.   {"image/jpeg","jpe"},
  257.   {"image/jpeg","jpeg"},
  258.   {"image/pict","pict"},
  259.   {"image/png","png"},
  260.   {"image/tiff","tiff"},
  261.   {"image/tiff","tif"},
  262.   {"image/x-cmu-raster","ras"},
  263.   {"image/x-freehand","fh4"},
  264.   {"image/x-freehand","fh7"},
  265.   {"image/x-freehand","fh5"},  
  266.   {"image/x-freehand","fhc"},
  267.   {"image/x-freehand","fh"},   
  268.   {"image/x-portable-anymap","pnm"},
  269.   {"image/x-portable-bitmap","pgm"},
  270.   {"image/x-portable-pixmap","ppm"},
  271.   {"image/x-rgb","rgb"},
  272.   {"image/x-xbitmap","xbm"},
  273.   {"image/x-xpixmap","xpm"},
  274.   {"image/x-xwindowdump","xwd"},
  275.   {"model/mesh","msh"},  
  276.   {"model/mesh","mesh"},  
  277.   {"model/mesh","silo"},  
  278.   {"multipart/x-zip","zip"},
  279.   {"multipart/x-gzip","gzip"},
  280.   {"text/css","css"},
  281.   {"text/html","html"},
  282.   {"text/html","htm"},
  283.   {"text/plain","txt"},
  284.   {"text/plain","g"},
  285.   {"text/plain","h"},
  286.   {"text/plain","c"},
  287.   {"text/plain","cc"},
  288.   {"text/plain","hh"},
  289.   {"text/plain","m"},
  290.   {"text/plain","f90"},
  291.   {"text/richtext","rtx"},
  292.   {"text/tab-separated-values","tsv"},
  293.   {"text/x-setext","etx"},
  294.   {"text/x-sgml","sgml"},
  295.   {"text/x-sgml","sgm"},
  296.   {"text/xml","xml"},  
  297.   {"text/xml","dtd"},  
  298.   {"video/mpeg","mpeg"},
  299.   {"video/mpeg","mpg"},
  300.   {"video/mpeg","mpe"},
  301.   {"video/quicktime","qt"},
  302.   {"video/quicktime","mov"},
  303.   {"video/x-msvideo","avi"},
  304.   {"video/x-sgi-movie","movie"},
  305.   {"x-conference/x-cooltalk","ice"},
  306.   /*{"application/x-httpd-cgi","cgi"},*/
  307.   {"x-world/x-vrml","wrl"},
  308.   
  309.   {"*","class"},
  310.   
  311.   {"",""}};
  312.  
  313.  
  314.   
  315. // conversion Θventuelle / vers antislash
  316. #if HTS_WIN
  317. char* antislash(char* s) {
  318.   static char buff[HTS_URLMAXSIZE*2];
  319.   static char* a;
  320.   strcpy(buff,s);
  321.   while(a=strchr(buff,'/')) *a='\\';
  322.   return buff;
  323. }
  324. #endif
  325.  
  326.  
  327.  
  328. // RΘcupΘration d'un fichier http sur le net.
  329. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  330. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  331. //
  332. // Une adresse de structure htsmsg peut Ωtre transmise pour
  333. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  334. // en background
  335.  
  336. htsblk httpget(char* url) {
  337.   char adr[HTS_URLMAXSIZE*2];   // adresse
  338.   char fil[HTS_URLMAXSIZE*2];   // chemin
  339.   
  340.   // sΘparer URL en adresse+chemin
  341.   if (ident_url(url,adr,fil)==-1) {
  342.     htsblk retour;
  343.     bzero((char *)&retour, sizeof(htsblk));    // effacer
  344.     // retour prΘdΘfini: erreur
  345.     retour.adr=NULL;
  346.     retour.size=0;
  347.     retour.msg[0]='\0';
  348.     retour.statuscode=-1;    
  349.     strcpy(retour.msg,"Error invalid URL");
  350.     return retour;
  351.   }
  352.   
  353.   return xhttpget(adr,fil);
  354. }
  355.  
  356. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  357. // retour: socket
  358. int http_fopen(char* adr,char* fil,htsblk* retour) {
  359.   //                / GET, traiter en-tΩte
  360.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  361. }
  362.  
  363. // ouverture d'une liaison http, envoi d'une requΦte
  364. // mode: 0 GET  1 HEAD  [2 POST]
  365. // treat: traiter header?
  366. // waitconnect: attendre le connect()
  367. // note: dans retour, on met les params du proxy
  368. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  369.   //htsblk retour;
  370.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  371.   T_SOC soc=INVALID_SOCKET;
  372.   //char *p,*q;
  373.   
  374.   // retour prΘdΘfini: erreur
  375.   if (retour) {
  376.     retour->adr=NULL;
  377.     retour->size=0;
  378.     retour->msg[0]='\0';
  379.     retour->statuscode=-5;          // a priori erreur non fatale
  380.   }
  381.  
  382. #if HDEBUG
  383.   printf("adr=%s\nfichier=%s\n",adr,fil);
  384. #endif
  385.   
  386.   // ouvrir liaison
  387. #if HDEBUG
  388.   printf("CrΘation d'une socket sur %s\n",adr);
  389. #endif
  390.  
  391. #if CNXDEBUG
  392.   printf("..newhttp\n");
  393. #endif
  394.  
  395.   /* connexion */
  396.   if (retour) {
  397.     if ( (!(retour->req.proxy.active)) || (strcmp(adr,"file://")==0) ){    /* pas de proxy, ou non utilisable ici */
  398.       soc=newhttp(adr,retour,-1,waitconnect);
  399.     } else {
  400.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  401.     }
  402.   } else {
  403.     soc=newhttp(adr,NULL,-1,waitconnect);    
  404.   }
  405.  
  406.   // copier index socket retour
  407.   if (retour) retour->soc=soc;
  408.  
  409.   // --------------------
  410.   // court-circuit (court circuite aussi le proxy..)
  411.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  412.   if (soc==LOCAL_SOCKET_ID) {
  413.     retour->is_file=1;  // fichier local
  414.     if (mode==0) {    // GET
  415.  
  416.       // Test en cas de file:///C|...
  417.       if (!fexist(fconv(unescape_http(fil))))
  418.         if (fexist(fconv(unescape_http(fil+1)))) {
  419.           char tempo[HTS_URLMAXSIZE*2];
  420.           strcpy(tempo,fil+1);
  421.           strcpy(fil,tempo);
  422.         }
  423.  
  424.       // Ouvrir
  425.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  426.       retour->msg[0]='\0';
  427.       soc=INVALID_SOCKET;
  428.       if (retour->totalsize<0)
  429.         strcpy(retour->msg,"Unable to open file");
  430.       else if (retour->totalsize==0)
  431.         strcpy(retour->msg,"File empty");
  432.       else {
  433.         // Note: On passe par un FILE* (plus propre)
  434.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  435.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  436.         if (retour->fp==NULL)
  437.           soc=INVALID_SOCKET;
  438.         else
  439.           soc=LOCAL_SOCKET_ID;
  440.       }
  441.       retour->soc=soc;
  442.       if (soc!=INVALID_SOCKET) {
  443.         retour->statuscode=200;   // OK
  444.         strcpy(retour->msg,"OK");
  445.         guess_httptype(retour->contenttype,fil);
  446.       } else if (strnotempty(retour->msg)==0)
  447.           strcpy(retour->msg,"Unable to open file");
  448.       return soc;  // renvoyer
  449.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  450.       strcpy(retour->msg,"Unexpected Head/Post local request");
  451.       soc=INVALID_SOCKET;    // erreur
  452.       retour->soc=soc;
  453.       return soc;
  454.     }
  455.   } 
  456.   // --------------------
  457.  
  458.   if (soc!=INVALID_SOCKET) {    
  459.     char rcvd[1100];
  460.     rcvd[0]='\0';
  461. #if HDEBUG
  462.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  463. #endif
  464.     
  465.     // connectΘ?
  466.     if (waitconnect) {
  467.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  468.     } 
  469.     
  470.     if (soc!=INVALID_SOCKET) {
  471.       
  472. #if HDEBUG
  473.       printf("Attente de la rΘponse:\n");
  474. #endif
  475.       
  476.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  477.       // et ensuite le corps
  478.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  479.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  480.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  481.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  482.         
  483.         // status-line α rΘcupΘrer
  484.         finput(soc,rcvd,1024);
  485.         if (strnotempty(rcvd)==0)
  486.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  487.  
  488.         // traiter status-line
  489.         treatfirstline(retour,rcvd);
  490.  
  491. #if HDEBUG
  492.         printf("Status-Code=%d\n",retour->statuscode);
  493. #endif
  494.         
  495.         // en-tΩte
  496.         
  497.         // header // ** !attention! HTTP/0.9 non supportΘ
  498.         do {
  499.           finput(soc,rcvd,1024);          
  500. #if HDEBUG
  501.           printf(">%s\n",rcvd);      
  502. #endif
  503.           if (strnotempty(rcvd))
  504.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  505.  
  506.         } while(strnotempty(rcvd));
  507.         
  508.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  509.         
  510.         //if (retour)
  511.         //  retour->totalsize=rcvsize;
  512.         
  513.       } else { // si GET, on recevra l'en tΩte APRES
  514.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  515.         if (retour)
  516.           retour->totalsize=-1;
  517.       }
  518.       
  519.     }
  520.  
  521.   }
  522.     
  523.   return soc;
  524. }
  525.  
  526.  
  527. // envoi d'une requΦte
  528. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  529.   char buff[8192];
  530.   //int use_11=0;     // HTTP 1.1 utilisΘ
  531.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  532.   char* search_tag=NULL;
  533.   buff[0]='\0';
  534.  
  535.   // header Date
  536.   //strcat(buff,"Date: ");
  537.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  538.   //sendc("\n");
  539.   //strcat(buff,buff);
  540.  
  541.   // possibilitΘ non documentΘe: >post: et >postfile:
  542.   // si prΘsence d'un tag >post: alors executer un POST
  543.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  544.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  545.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  546.   search_tag=strstr(fil,POSTTOK":");
  547.   if (!search_tag) {
  548.     search_tag=strstr(fil,POSTTOK"file:");
  549.     if (search_tag) {     // postfile
  550.       if (mode==0) {      // GET!
  551.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  552.         if (fp) {
  553.           char line[1100];
  554.           char protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  555.           linput(fp,line,1000);
  556.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  557.             // selon que l'on a ou pas un proxy
  558.             if (retour->req.proxy.active)
  559.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  560.             else
  561.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  562.             // lire le reste en brut
  563.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  564.           }
  565.           fclose(fp);
  566.         }
  567.       }
  568.     }
  569.   }
  570.   // Fin postfile
  571.   
  572.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  573.     // Type de requΦte?
  574.     if ((search_tag) && (mode==0)) {
  575.       strcat(buff,"POST ");
  576.     } else if (mode==0) {    // GET
  577.       strcat(buff,"GET ");
  578.     } else {  // if (mode==1) {
  579.       if (!retour->req.http11)        // forcer HTTP/1.0
  580.         strcat(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  581.       else
  582.         strcat(buff,"HEAD ");
  583.     }
  584.     
  585.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  586.     if (retour->req.proxy.active) {
  587.       if (strncmp(adr,"ftp://",6)!=0) {
  588. #if HDEBUG
  589.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  590. #endif
  591.         strcat(buff,"http://");
  592.         strcat(buff,jump_identification(adr));
  593.       } else {          // ftp:// en proxy http
  594. #if HDEBUG
  595.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  596. #endif
  597.         direct_url=1;             // ne pas analyser user/pass
  598.         strcat(buff,adr);
  599.       }
  600.     } 
  601.     
  602.     // NOM DU FICHIER
  603.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  604.     if (*fil!='/') strcat(buff,"/");
  605.     {
  606.       char tempo[HTS_URLMAXSIZE*2];
  607.       tempo[0]='\0';
  608.       if (search_tag)
  609.         strncat(tempo,fil,(int) search_tag -(int) fil);
  610.       else
  611.         strcpy(tempo,fil);
  612.       escape_check_url(tempo);
  613.       strcat(buff,tempo);       // avec Θchappement
  614.     }
  615.     
  616.     // protocole
  617.     if (!retour->req.http11) {     // forcer HTTP/1.0
  618.       //use_11=0;
  619.       strcat(buff," HTTP/1.0\x0d\x0a");
  620.     } else {                   // RequΦte 1.1
  621.       //use_11=1;
  622.       strcat(buff," HTTP/1.1\x0d\x0a");
  623.     }
  624.  
  625.     /* supplemental data */
  626.     if (xsend) strcat(buff,xsend);    // Θventuelles autres lignes
  627.  
  628.     // tester proxy authentication
  629.     if (retour->req.proxy.active) {
  630.       char* a=jump_identification(retour->req.proxy.name);
  631.       if (a!=retour->req.proxy.name) {  // et hop, authentification proxy!
  632.         char autorisation[1100];
  633.         char user_pass[256];        
  634.         autorisation[0]=user_pass[0]='\0';
  635.         //
  636.         strncat(user_pass,retour->req.proxy.name,(int) a - (int) retour->req.proxy.name - 1);
  637.         strcpy(user_pass,unescape_http(user_pass));
  638.         code64(user_pass,autorisation);
  639.         strcat(buff,"Proxy-Authorization: Basic ");
  640.         strcat(buff,autorisation);
  641.         strcat(buff,H_CRLF);
  642. #if HDEBUG
  643.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  644. #endif
  645.       }
  646.     }
  647.     
  648.     // Referer?
  649.     if ((referer_adr) && (referer_fil)) {       // existe
  650.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  651.         if (strcmp(referer_adr,"file://")) {      // PAS file://
  652.           strcat(buff,"Referer: ");
  653.           strcat(buff,"http://");
  654.           strcat(buff,referer_adr);
  655.           strcat(buff,referer_fil);
  656.           strcat(buff,H_CRLF);
  657.         }
  658.       }
  659.     }
  660.     
  661.     // POST?
  662.     if (mode==0) {      // GET!
  663.       if (search_tag) {
  664.         char clen[256];
  665.         sprintf(clen,"Content-length: %d"H_CRLF,strlen(unescape_http(search_tag+strlen(POSTTOK)+1)));
  666.         strcat(buff,clen);
  667.       }
  668.     }
  669.     
  670.     // gestion cookies?
  671.     if (cookie) {
  672.       char* b=cookie->data;
  673.       int cook=0;
  674.       int max_cookies=8;
  675.       int max_size=2048;
  676.       max_size+=strlen(buff);
  677.       do {
  678.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  679.         if (b) {
  680.           max_cookies--;
  681.           if (!cook) {
  682.             strcat(buff,"Cookie: ");
  683.             strcat(buff,"$Version=1; ");
  684.             cook=1;
  685.           } else
  686.             strcat(buff,"; ");
  687.           strcat(buff,cookie_get(b,5));
  688.           strcat(buff,"=");
  689.           strcat(buff,cookie_get(b,6));
  690.           strcat(buff,"; $Path=");
  691.           strcat(buff,cookie_get(b,2));
  692.           b=cookie_nextfield(b);
  693.         }
  694.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  695.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  696.         strcat(buff,H_CRLF);
  697. #if DEBUG_COOK
  698.         printf("Header:\n%s\n",buff);
  699. #endif
  700.       }
  701.     }
  702.     
  703.     // connection close?
  704.     //if (use_11)     // Si on envoie une requΦte 1.1, prΘciser qu'on ne veut pas de keep-alive!!
  705.     strcat(buff,"Connection: close"H_CRLF);
  706.     
  707.     //strcat(buff,"Referer: http://");ppp
  708.     //strcat(buff,adr); 
  709.     //strcat(buff,"\n");
  710.     
  711.     // gΘrer le keep-alive (garder socket)
  712.     //strcat(buff,"Connection: Keep-Alive\n");
  713.     
  714.     {
  715.       char* real_adr=jump_identification(adr);
  716.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  717.       if (!direct_url) {     // pas ftp:// par exemple
  718.         //if (!retour->req.proxy.active) {
  719.         strcat(buff,"Host: "); strcat(buff,real_adr); strcat(buff,H_CRLF);
  720.         //}
  721.       }
  722.       //}
  723.  
  724.       // PrΘsence d'un user-agent?
  725.       if (retour->req.user_agent_send) {  // ohh un user-agent
  726.         char s[256];
  727.         // HyperTextSeeker/"HTSVERSION
  728.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  729.         strcat(buff,s);
  730.         
  731.         // pour les serveurs difficiles
  732.         strcat(buff,"Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"H_CRLF);
  733.         if (strnotempty(retour->req.lang_iso)) {
  734.           strcat(buff,"Accept-Language: "); strcat(buff,retour->req.lang_iso); strcat(buff,H_CRLF);
  735.         }
  736.         strcat(buff,"Accept-Charset: iso-8859-1, *"H_CRLF);   
  737.         strcat(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  738.       } else {
  739.         strcat(buff,"Accept: */*"H_CRLF);         // le minimum
  740.       }
  741.  
  742.       /* Authentification */
  743.       {
  744.         char autorisation[1100];
  745.         char* a;
  746.         autorisation[0]='\0';
  747.         if (real_adr != adr) {  // ohh une authentification!
  748.           if (!direct_url) {      // pas ftp:// par exemple
  749.             char user_pass[256];
  750.             user_pass[0]='\0';
  751.             strncat(user_pass,adr,(int) real_adr - (int) adr - 1);
  752.             strcpy(user_pass,unescape_http(user_pass));
  753.             code64(user_pass,autorisation);
  754.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  755.               bauth_add(cookie,real_adr,fil,autorisation);
  756.           }
  757.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  758.           strcpy(autorisation,a);
  759.         /* On a une autorisation a donner?  */
  760.         if (strnotempty(autorisation)) {
  761.           strcat(buff,"Authorization: Basic ");
  762.           strcat(buff,autorisation);
  763.           strcat(buff,H_CRLF);
  764.         }
  765.       }
  766.  
  767.     }
  768.     //strcat(buff,"Accept-Language: en\n");
  769.     //strcat(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  770.     
  771.     // CRLF de fin d'en tΩte
  772.     strcat(buff,H_CRLF);
  773.     
  774.     // donnΘes complΘmentaires?
  775.     if (search_tag)
  776.     if (mode==0)      // GET!
  777.       strcat(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  778.   }
  779.   
  780. #if HDEBUG
  781. #endif
  782.   if (_DEBUG_HEAD) {
  783.     if (ioinfo) {
  784.       fprintf(ioinfo,"Out:\r\n%s\r\n",buff);
  785.       fflush(ioinfo);
  786.     }
  787.   }  // Fin test pas postfile
  788.   //
  789.  
  790.   // Envoi
  791.   if (sendc(retour->soc,buff)<0) {  // ERREUR, socket rompue?...
  792.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  793.     deletesoc(retour->soc);  // fermer tout de mΩme
  794.     // et tenter de reconnecter
  795.     
  796.     strcpy(retour->msg,"Broken pipe");
  797.     retour->soc=INVALID_SOCKET;
  798.     /* non, α cause du poll connect()
  799.     // si on avait une connexion proxy, tenter une connexion directe cette fois!
  800.     retour->proxy.active=0;
  801.     if (retour) {
  802.     soc=newhttp(adr,retour->msg,-1,1);
  803.     retour->soc=soc;
  804.     }
  805.     else {
  806.     soc=newhttp(adr,NULL,-1,1);   
  807.     }
  808.     
  809.       // reconnectΘ?
  810.       if (soc!=INVALID_SOCKET) {        
  811.       if (sendc(soc,buff)<0) {  // NAN MARCHE PAS
  812.       strcpy(retour->msg,"Can not write to a re-established socket connexion");
  813.       deletesoc(soc);  // fermer tout de mΩme
  814.       soc=INVALID_SOCKET;
  815.       }
  816.       
  817.         } else {
  818.         strcpy(retour->msg,"Can not re-establish a socket connexion");
  819.         }
  820.     */
  821.   }
  822.   
  823.   // RX'98
  824.   return 0;
  825. }
  826.  
  827.  
  828.  
  829.  
  830. // traiter 1ere ligne d'en tΩte
  831. void treatfirstline(htsblk* retour,char* rcvd) {
  832.   char* a=rcvd;
  833.   // exemple:
  834.   // HTTP/1.0 200 OK
  835.   if (*a) {
  836.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  837.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  838.     // sauter HTTP/1.x
  839.     while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  840.     if (*a != '\0') {
  841.       while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  842.       if ((*a>='0') && (*a<='9')) {
  843.         sscanf(a,"%d",&(retour->statuscode));
  844.         // sauter 200
  845.         while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  846.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  847.         if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  848.           strcpy(retour->msg,a);
  849.         else
  850.           infostatuscode(retour->msg,retour->statuscode);
  851.         // type MIME par dΘfaut
  852.         strcpy(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  853.       } else {  // pas de code!
  854.         retour->statuscode=-1;
  855.         strcpy(retour->msg,"Unknown response structure");
  856.       }
  857.     } else {  // euhh??
  858.       retour->statuscode=-1;
  859.       strcpy(retour->msg,"Unknown response structure");
  860.     }
  861.   } else {  // vide!
  862.     retour->statuscode=-1;
  863.     strcpy(retour->msg,"Empty reponse or internal error");
  864.   }
  865. }
  866.  
  867. // traiter ligne par ligne l'en tΩte
  868. // gestion des cookies
  869. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  870.   int p;
  871.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  872. #if HDEBUG
  873.     printf("ok, Content-length: dΘtectΘ\n");
  874. #endif
  875.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  876.   }
  877.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  878.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  879.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  880.       char tmp[256];
  881.       char *a=NULL,*b=NULL;
  882.       strcpy(tmp,rcvd+p);
  883.       a=strstr(tmp,"filename=");
  884.       if (a) {
  885.         a+=strlen("filename=");
  886.         while(is_space(*a)) a++;
  887.         //a=strchr(a,'"');
  888.         if (a) {
  889.           char *c=NULL;
  890.           //a++;      /* jump " */
  891.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  892.             a=c+1;
  893.           //b=strchr(a+1,'"');
  894.           b=a+strlen(a)-1;
  895.           while(is_space(*b)) b--;
  896.           b++;
  897.           if (b) {
  898.             *b='\0';
  899.             if ((int) strlen(a) < 200) { // pas trop long?
  900.               strcpy(retour->cdispo,a);
  901.             }
  902.           }
  903.         }
  904.       } 
  905.     }
  906.   }
  907.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  908.     while(*(rcvd+p)==' ') p++;    // sauter espaces
  909.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  910.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  911.       strcpy(retour->lastmodified,rcvd+p);
  912.     }
  913.   }
  914.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  915.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  916.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  917.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  918.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  919.         strcpy(retour->lastmodified,rcvd+p);
  920.       }
  921.     }
  922.   }
  923.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  924.     if (retour) {
  925.       while(*(rcvd+p)==' ') p++;    // sauter espaces
  926.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  927.         strcpy(retour->etag,rcvd+p);
  928.       else    // erreur.. ignorer
  929.         retour->etag[0]='\0';
  930.     }
  931.   }
  932.   else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  933.     retour->is_chunk=1;     // chunked
  934.     //retour->http11=2;     // chunked
  935. #if HDEBUG
  936.     printf("ok, Transfer-Encoding: dΘtectΘ\n");
  937. #endif
  938.   }
  939.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  940.     if (retour) {
  941.       char tempo[1100];
  942.       // Θviter les text/html; charset=foo
  943.       {
  944.         char* a=strchr(rcvd+p,';');
  945.         if (a) *a='\0';
  946.       }
  947.       sscanf(rcvd+p,"%s",tempo);
  948.       if (strlen(tempo)<64)    // pas trop long!!
  949.         strcpy(retour->contenttype,tempo);
  950.       else
  951.         strcpy(retour->contenttype,"application/octet-stream-unknown");    // erreur
  952.     }
  953.   }
  954.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  955.     if (retour) {
  956.       if (retour->location) {
  957.         while(*(rcvd+p)==' ') p++;    // sauter espaces
  958.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  959.           sscanf(rcvd+p,"%s",retour->location);
  960.         else    // erreur.. ignorer
  961.           retour->location[0]='\0';
  962.       }
  963.     }
  964.   }
  965.   else if ((p=strfield(rcvd,"Connection: Keep-Alive"))!=0) {
  966.     // non, pas de keep-alive! on dΘconnectera..          
  967.   }
  968.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {    // params keep-alive
  969.     // rien α faire          
  970.   }
  971.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  972.     char* a = rcvd+p;           // pointeur
  973.     char domain[256];           // domaine cookie (.netscape.com)
  974.     char path[256];             // chemin (/)
  975.     char cook_name[256];        // nom cookie (MYCOOK)
  976.     char cook_value[8192];      // valeur (ID=toto,S=1234)
  977. #if DEBUG_COOK
  978.     printf("set-cookie detected\n");
  979. #endif
  980.     while(*a) {
  981.       char *token_st,*token_end;
  982.       char *value_st,*value_end;
  983.       char name[256];
  984.       char value[8192];
  985.       int next=0;
  986.       name[0]=value[0]='\0';
  987.       //
  988.  
  989.       // initialiser cookie lu actuellement
  990.       if (adr)
  991.         strcpy(domain,jump_identification(adr));     // domaine
  992.       strcpy(path,"/");         // chemin (/)
  993.       strcpy(cook_name,"");     // nom cookie (MYCOOK)
  994.       strcpy(cook_value,"");    // valeur (ID=toto,S=1234)
  995.       // boucler jusqu'au prochain cookie ou la fin
  996.       do {
  997.         char* start_loop=a;
  998.         while(is_space(*a)) a++;    // sauter espaces
  999.         token_st=a;                 // dΘpart token
  1000.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1001.         token_end=a;
  1002.         while(is_space(*a)) a++;    // sauter espaces
  1003.         if (*a=='=') {    // name=value
  1004.           a++;
  1005.           while(is_space(*a)) a++;    // sauter espaces
  1006.           value_st=a;
  1007.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1008.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1009.           value_end=a;
  1010.           //if (*a==';') {  // finit par un ;
  1011.           // vΘrifier dΘbordements
  1012.           if ( (((int) token_end - (int) token_st)<200) && (((int) value_end - (int) value_st)<8000)
  1013.             && (((int) token_end - (int) token_st)>0)   && (((int) value_end - (int) value_st)>0) ) {
  1014.             name[0]='\0';
  1015.             value[0]='\0';
  1016.             strncat(name,token_st,(int) token_end - (int) token_st);
  1017.             strncat(value,value_st,(int) value_end - (int) value_st);
  1018. #if DEBUG_COOK
  1019.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1020. #endif
  1021.             if (strfield2(name,"domain")) {
  1022.               strcpy(domain,value);
  1023.             }
  1024.             else if (strfield2(name,"path")) {
  1025.               strcpy(path,value);
  1026.             }
  1027.             else if (strfield2(name,"max-age")) {
  1028.               // ignorΘ..
  1029.             }
  1030.             else if (strfield2(name,"expires")) {
  1031.               // ignorΘ..
  1032.             }
  1033.             else if (strfield2(name,"version")) {
  1034.               // ignorΘ..
  1035.             }
  1036.             else if (strfield2(name,"comment")) {
  1037.               // ignorΘ
  1038.             }
  1039.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1040.               // ignorΘ
  1041.             }
  1042.             else {
  1043.               if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1044.                 strcpy(cook_name,name);
  1045.                 strcpy(cook_value,value);
  1046.               } else {                             // prochain cookie
  1047.                 a=start_loop;      // on devra recommencer α cette position
  1048.                 next=1;            // enregistrer
  1049.               }
  1050.             }
  1051.           }
  1052.         }
  1053.         if (!next) {
  1054.           while((*a!=';') && (*a)) a++;    // prochain
  1055.           while(*a==';') a++;             // sauter ;
  1056.         }
  1057.       } while((*a) && (!next));
  1058.       if (strnotempty(cook_name)) {          // cookie?
  1059. #if DEBUG_COOK
  1060.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1061. #endif
  1062.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1063.       }
  1064.     }
  1065.   }
  1066. }
  1067.  
  1068.  
  1069. // transforme le message statuscode en chaεne
  1070. void infostatuscode(char* msg,int statuscode) {
  1071.   switch( statuscode) {    
  1072.     // Erreurs HTTP, selon RFC
  1073.   case 100: strcpy( msg,"Continue"); break; 
  1074.   case 101: strcpy( msg,"Switching Protocols"); break; 
  1075.   case 200: strcpy( msg,"OK"); break; 
  1076.   case 201: strcpy( msg,"Created"); break; 
  1077.   case 202: strcpy( msg,"Accepted"); break; 
  1078.   case 203: strcpy( msg,"Non-Authoritative Information"); break; 
  1079.   case 204: strcpy( msg,"No Content"); break; 
  1080.   case 205: strcpy( msg,"Reset Content"); break; 
  1081.   case 206: strcpy( msg,"Partial Content"); break; 
  1082.   case 300: strcpy( msg,"Multiple Choices"); break; 
  1083.   case 301: strcpy( msg,"Moved Permanently"); break; 
  1084.   case 302: strcpy( msg,"Moved Temporarily"); break; 
  1085.   case 303: strcpy( msg,"See Other"); break; 
  1086.   case 304: strcpy( msg,"Not Modified"); break; 
  1087.   case 305: strcpy( msg,"Use Proxy"); break; 
  1088.   case 306: strcpy( msg,"Undefined 306 error"); break; 
  1089.   case 307: strcpy( msg,"Temporary Redirect"); break; 
  1090.   case 400: strcpy( msg,"Bad Request"); break; 
  1091.   case 401: strcpy( msg,"Unauthorized"); break; 
  1092.   case 402: strcpy( msg,"Payment Required"); break; 
  1093.   case 403: strcpy( msg,"Forbidden"); break; 
  1094.   case 404: strcpy( msg,"Not Found"); break; 
  1095.   case 405: strcpy( msg,"Method Not Allowed"); break; 
  1096.   case 406: strcpy( msg,"Not Acceptable"); break; 
  1097.   case 407: strcpy( msg,"Proxy Authentication Required"); break; 
  1098.   case 408: strcpy( msg,"Request Time-out"); break; 
  1099.   case 409: strcpy( msg,"Conflict"); break; 
  1100.   case 410: strcpy( msg,"Gone"); break; 
  1101.   case 411: strcpy( msg,"Length Required"); break; 
  1102.   case 412: strcpy( msg,"Precondition Failed"); break; 
  1103.   case 413: strcpy( msg,"Request Entity Too Large"); break; 
  1104.   case 414: strcpy( msg,"Request-URI Too Large"); break; 
  1105.   case 415: strcpy( msg,"Unsupported Media Type"); break; 
  1106.   case 416: strcpy( msg,"Requested Range Not Satisfiable"); break; 
  1107.   case 417: strcpy( msg,"Expectation Failed"); break; 
  1108.   case 500: strcpy( msg,"Internal Server Error"); break; 
  1109.   case 501: strcpy( msg,"Not Implemented"); break; 
  1110.   case 502: strcpy( msg,"Bad Gateway"); break; 
  1111.   case 503: strcpy( msg,"Service Unavailable"); break; 
  1112.   case 504: strcpy( msg,"Gateway Time-out"); break; 
  1113.   case 505: strcpy( msg,"HTTP Version Not Supported"); break; 
  1114.     //
  1115.   default: if (strnotempty(msg)==0) strcpy( msg,"Unknown error"); break;
  1116.   }
  1117. }
  1118.  
  1119.  
  1120. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1121. htsblk xhttpget(char* adr,char* fil) {
  1122.   T_SOC soc;
  1123.   htsblk retour;
  1124.   
  1125.   bzero((char *)&retour, sizeof(htsblk));
  1126.   soc=http_fopen(adr,fil,&retour);
  1127.  
  1128.   if (soc!=INVALID_SOCKET) {
  1129.     http_fread(soc,&retour);
  1130. #if HTS_DEBUG_CLOSESOCK
  1131.     DEBUG_W("xhttpget: deletehttp\n");
  1132. #endif
  1133.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1134.     retour.soc=INVALID_SOCKET;
  1135.   }
  1136.   return retour;
  1137. }
  1138.  
  1139. // variation sur un thΦme...
  1140. // rΘceptionne uniquement un en-tΩte (HEAD)
  1141. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1142. htsblk http_gethead(char* adr,char* fil) {
  1143.   T_SOC soc;
  1144.   htsblk retour;
  1145.  
  1146.   bzero((char *)&retour, sizeof(htsblk));
  1147.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1148.  
  1149.   if (soc!=INVALID_SOCKET) {
  1150.     http_fread(soc,&retour);    // rΘception en-tΩte
  1151. #if HTS_DEBUG_CLOSESOCK
  1152.     DEBUG_W("http_gethead: deletehttp\n");
  1153. #endif
  1154.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1155.     retour.soc=INVALID_SOCKET;
  1156.   }
  1157.   return retour;
  1158. }
  1159. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1160.  
  1161.  
  1162. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1163. // il ne reste plus qu'α lire les donnΘes
  1164. // (pour HEAD le header est lu ici!)
  1165. void http_fread(T_SOC soc,htsblk* retour) {  
  1166.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1167.   
  1168.   if (retour) retour->soc=soc;
  1169.   if (soc!=INVALID_SOCKET) {    
  1170.     // fonction de lecture d'une socket (plus propre)
  1171.     while(http_fread1(retour)!=-1);
  1172.     soc=retour->soc;
  1173.     if (retour->adr==NULL) {
  1174.       if (strnotempty(retour->msg)==0)
  1175.         sprintf(retour->msg,"Unable to read");
  1176.       return ;    // erreur
  1177.     } 
  1178.     
  1179. #if HDEBUG
  1180.     printf("Ok, donnΘes reτues\n");
  1181. #endif   
  1182.  
  1183.     return ;
  1184.     
  1185.   } 
  1186.   
  1187.   return ;
  1188. }
  1189.  
  1190. // lecture d'un bloc sur une socket (ou un fichier!)
  1191. HTS_INLINE LLint http_fread1(htsblk* r) {
  1192.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1193.   return http_xfread1(r,TAILLE_BUFFER);
  1194. }
  1195.  
  1196. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1197. // SI bufl=0 alors le buffer est censΘ Ωtre de 8kos, et on recoit caractΦres
  1198. // par caractΦres en Θliminant les cr (ex: header)
  1199. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1200. LLint http_xfread1(htsblk* r,int bufl) {
  1201.   int nl=-1;
  1202.  
  1203.   if (bufl>0) {
  1204.     if (!r->is_write) {     // stocker en mΘmoire
  1205.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1206.         if (r->adr==NULL) {
  1207.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1208.           r->size=0;
  1209.         }
  1210.         if (r->adr!=NULL) {
  1211.           // lecture
  1212.           nl=hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1213.           // nouvelle taille
  1214.           if (nl>0) r->size+=nl;
  1215.           
  1216.           if ((nl<=0) || (r->size >= r->totalsize))
  1217.             nl=-1;  // break
  1218.           
  1219.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1220.         }
  1221.         
  1222.       } else {                 // inconnu..
  1223.         // rΘserver de la mΘmoire?
  1224.         if (r->adr==NULL) {
  1225. #if HDEBUG
  1226.           printf("..alloc xfread\n");
  1227. #endif
  1228.           r->adr=(char*) malloct(bufl + 1);
  1229.           r->size=0;
  1230.         }
  1231.         else {
  1232. #if HDEBUG
  1233.           printf("..realloc xfread1\n");
  1234. #endif
  1235.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1236.         }
  1237.         
  1238.         if (r->adr!=NULL) {
  1239.           // lecture
  1240.           nl=hts_read(r,r->adr+(int)r->size,bufl);
  1241.           if (nl>0) {
  1242.             // resize
  1243.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1244.             // nouvelle taille
  1245.             if (nl>0) r->size+=nl;
  1246.  
  1247.             if (r->adr) r->adr[r->size]='\0';    // octet nul
  1248.  
  1249.           } // sinon on a fini
  1250. #if HDEBUG
  1251.           else
  1252.             printf("..end read (%d)\n",nl);
  1253. #endif
  1254.         }
  1255. #if HDEBUG
  1256.         else printf("..-> error\n");
  1257. #endif
  1258.       }
  1259.  
  1260.       // pas de adr=erreur
  1261.       if (r->adr==NULL) nl=-1;
  1262.  
  1263.     } else {    // stocker sur disque
  1264.       char* buff;
  1265.       buff=(char*) malloct(bufl);
  1266.       if (buff!=NULL) {
  1267.         // lecture
  1268.         nl=hts_read(r,buff,bufl);
  1269.         // nouvelle taille
  1270.         if (nl>0) { 
  1271.           r->size+=nl;
  1272.           if ((int) fwrite(buff,1,nl,r->out)!=nl) {
  1273.             r->statuscode=-1;
  1274.             strcpy(r->msg,"Write error on disk");
  1275.             nl=-1;
  1276.           }
  1277.         }
  1278.  
  1279.         if ((nl<=0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1280.           nl=-1;  // break
  1281.  
  1282.         // libΘrer bloc tempo
  1283.         freet(buff);
  1284.       } else nl=-1;
  1285.       
  1286.       // NON ce n'est pas notre r⌠le - et cela pose des problΦmes pour la rΘception en chunk
  1287.       /*
  1288.         //if (nl<=0)    // fin
  1289.         //if (r->out!=NULL) { fclose(r->out); r->out=NULL; }
  1290.       */
  1291.       if (nl<=0)    // fin
  1292.       if (r->out!=NULL) { fflush(r->out); }
  1293.         
  1294.         
  1295.     } // stockage disque ou mΘmoire
  1296.  
  1297.   } else {    // rΘception d'un en-tΩte octet par octet
  1298.  
  1299.     if (r->adr==NULL) {
  1300.       r->adr=(char*) malloct(8192);
  1301.       r->size=0;
  1302.     }
  1303.     
  1304.     if (r->adr!=NULL) {
  1305.       // lecture
  1306.       nl=hts_read(r,r->adr+r->size,1);
  1307.       if (nl>0) {
  1308.         if (*(r->adr+r->size) != 13)    // sauter caractΦres 13
  1309.           (r->size)++;
  1310.         *(r->adr+r->size)='\0';    // terminer par octet nul
  1311.       }
  1312.       if (r->size>=8190) {
  1313.         nl=-1;    // break
  1314.       }
  1315.     }
  1316.     // pas de adr=erreur
  1317.     if (r->adr==NULL) nl=-1;
  1318.   }
  1319. #if HDEBUG
  1320.   //printf("add to %d / %d\n",r->size,r->totalsize);
  1321. #endif
  1322.   return ((nl>0)?0:-1);
  1323. }
  1324.  
  1325.  
  1326. // teste une adresse, et suit l'Θventuel chemin "moved"
  1327. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1328. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1329. htsblk http_location(char* adr,char* fil,char* loc) {
  1330.   htsblk retour;
  1331.   int retry=0;
  1332.   int tryagain;
  1333.   // note: "RFC says"
  1334.   // 5 boucles au plus, on en teste au plus 8 ici
  1335.   // sinon abandon..
  1336.   do {
  1337.     tryagain=0;
  1338.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1339.     case 200: break;   // ok!
  1340.     case 301: case 302: case 303: case 307: // moved!
  1341.       // recalculer adr et fil!
  1342.       if (ident_url(loc,adr,fil)!=-1) {
  1343.         tryagain=1;  // retenter
  1344.         retry++;     // ..encore une fois
  1345.       }
  1346.     }
  1347.   } while((tryagain) && (retry<5+3));
  1348.   return retour;
  1349. }
  1350.  
  1351.  
  1352. // teste si une URL (validitΘ, header, taille)
  1353. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1354. // en cas de moved xx, dans location
  1355. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1356. // qui nous font poireauter 5 heures..) -> -2=timeout
  1357. htsblk http_test(char* adr,char* fil,char* loc) {
  1358.   T_SOC soc;
  1359.   htsblk retour;
  1360.   //int rcvsize=-1;
  1361.   //char* rcv=NULL;    // adresse de retour
  1362.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1363.   double tl;
  1364.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1365.  
  1366.   // pour abandonner un site trop lent
  1367.   tl=time_local();
  1368.  
  1369.   loc[0]='\0';
  1370.   bzero((char *)&retour, sizeof(htsblk));    // effacer
  1371.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1372.  
  1373.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1374.  
  1375.   // on ouvre en head, et on traite l'en tΩte
  1376.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1377.   
  1378.   if (soc!=INVALID_SOCKET) {
  1379.     int e=0;
  1380.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1381.     do {
  1382.       if (http_xfread1(&retour,0)==-1)
  1383.         e=1;
  1384.       else {
  1385.         if (retour.adr!=NULL) {
  1386.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1387.             e=1;
  1388.         }
  1389.       }
  1390.             
  1391.       if (!e) {
  1392.         if ((time_local()-tl)>=timeout) {
  1393.           e=-1;
  1394.         }
  1395.       }
  1396.       
  1397.     } while (!e);
  1398.     
  1399.     if (e==1) {
  1400.       if (adr!=NULL) {
  1401.         int ptr=0;
  1402.         char rcvd[1100];
  1403.  
  1404.         // note: en gros recopie du traitement de back_wait()
  1405.         //
  1406.  
  1407.  
  1408.         // ----------------------------------------
  1409.         // traiter en-tΩte!
  1410.         // status-line α rΘcupΘrer
  1411.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1412.         if (strnotempty(rcvd)==0)
  1413.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1414.         
  1415.         // traiter status-line
  1416.         treatfirstline(&retour,rcvd);
  1417.         
  1418. #if HDEBUG
  1419.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1420. #endif
  1421.         
  1422.         // en-tΩte
  1423.         
  1424.         // header // ** !attention! HTTP/0.9 non supportΘ
  1425.         do {
  1426.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  1427. #if HDEBUG
  1428.           printf("(buffer)>%s\n",rcvd);      
  1429. #endif
  1430.           if (strnotempty(rcvd))
  1431.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  1432.           
  1433.         } while(strnotempty(rcvd));
  1434.         // ----------------------------------------                    
  1435.         
  1436.         // libΘrer mΘmoire
  1437.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  1438.       }
  1439.     } else {
  1440.       retour.statuscode=-2;
  1441.       strcpy(retour.msg,"Timeout While Testing");
  1442.     }
  1443.     
  1444.     
  1445. #if HTS_DEBUG_CLOSESOCK
  1446.     DEBUG_W("http_test: deletehttp\n");
  1447. #endif
  1448.     deletehttp(&retour);
  1449.     retour.soc=INVALID_SOCKET;
  1450.   }
  1451.   return retour;    
  1452. }
  1453.  
  1454. // CrΘe un lien (http) vers une adresse internet iadr
  1455. // retour: structure (adresse, taille, message si erreur (si !adr))
  1456. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  1457. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  1458.   T_SOC soc;                           // descipteur de la socket
  1459.   char* iadr;
  1460.   // unsigned short int port;
  1461.   
  1462.   // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  1463.   iadr = jump_identification(_iadr);
  1464.   
  1465.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  1466.   // local.
  1467.   // utile pour les tests!
  1468.   //## if (iadr[0]!=lOCAL_CHAR) {
  1469.   if (strcmp(iadr,"file://")) {           /* non fichier */
  1470.     struct sockaddr_in server;
  1471.     t_hostent* hp;    
  1472.     // effacer structure
  1473.     bzero((char *)&server, sizeof(server));
  1474.  
  1475. #if HDEBUG
  1476.     printf("gethostbyname\n");
  1477. #endif
  1478.     
  1479.     // tester un Θventuel port
  1480.     if (port==-1) {
  1481.       char *a=strchr(iadr,':');
  1482.       port=80;    // port par dΘfaut
  1483.       if (a) {
  1484.         char iadr2[HTS_URLMAXSIZE*2];
  1485.         int i=-1;
  1486.         iadr2[0]='\0';
  1487.         sscanf(a+1,"%d",&i);
  1488.         if (i!=-1) {
  1489.           port=(unsigned short int) i;
  1490.         }
  1491.         
  1492.         // adresse vΘritable (sans :xx)
  1493.         strncat(iadr2,iadr,(int) a-(int) iadr);
  1494.  
  1495.         // adresse sans le :xx
  1496.         hp = hts_gethostbyname(iadr2);
  1497.         
  1498.       } else {
  1499.  
  1500.         // adresse normale (port par dΘfaut par la suite)
  1501.         hp = hts_gethostbyname(iadr);
  1502.         
  1503.       }
  1504.       
  1505.     } else    // port dΘfini
  1506.       hp = hts_gethostbyname(iadr);
  1507.  
  1508.     
  1509.     // Conversion iadr -> adresse
  1510.     // structure recevant le nom de l'h⌠te, etc
  1511.     //struct     hostent     *hp;
  1512.     if (hp == NULL) {
  1513. #if DEBUG
  1514.       printf("erreur gethostbyname\n");
  1515. #endif
  1516.       if (retour)
  1517.       if (retour->msg)
  1518.         strcpy(retour->msg,"Unable to get server's address");
  1519.       return INVALID_SOCKET;
  1520.     }  
  1521.     // copie adresse
  1522.     bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  1523.  
  1524.     
  1525.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  1526. #if HDEBUG
  1527.     printf("socket\n");
  1528. #endif
  1529. #if HTS_WIDE_DEBUG    
  1530.     DEBUG_W("socket\n");
  1531. #endif
  1532.     soc=socket(AF_INET,SOCK_STREAM,0);
  1533. #if HTS_WIDE_DEBUG    
  1534.     DEBUG_W("socket done\n");
  1535. #endif
  1536.     if (soc==INVALID_SOCKET) {
  1537.       if (retour)
  1538.       if (retour->msg)
  1539.         strcpy(retour->msg,"Unable to create a socket");
  1540.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  1541.     }
  1542.     // structure: connexion au domaine internet, port 80 (ou autre)
  1543.     server.sin_family = AF_INET;
  1544.     server.sin_port = htons((unsigned short int) port);
  1545. #if HDEBUG
  1546.     printf("==%d\n",soc);
  1547. #endif
  1548.  
  1549.     // connexion non bloquante?
  1550.     if (!waitconnect ) {
  1551.       unsigned long p=1;  // non bloquant
  1552. #if HTS_WIN
  1553.       ioctlsocket(soc,FIONBIO,&p);
  1554. #else
  1555.       ioctl(soc,FIONBIO,&p);
  1556. #endif
  1557.     }
  1558.     
  1559.     // Connexion au serveur lui mΩme
  1560. #if HDEBUG
  1561.     printf("connect\n");
  1562. #endif
  1563.     
  1564. #if HTS_WIDE_DEBUG
  1565.     DEBUG_W("connect\n");
  1566. #endif
  1567. #if HTS_WIN
  1568.     if (connect(soc, (const struct sockaddr FAR *)&server, sizeof(server)) != 0) {
  1569. #else
  1570.       if (connect(soc, (struct sockaddr *)&server, sizeof(server)) == -1) {
  1571. #endif
  1572.         // bloquant
  1573.         if (waitconnect) {
  1574. #if HDEBUG
  1575.           printf("unable to connect!\n");
  1576. #endif
  1577.           if (retour)
  1578.           if (retour->msg)
  1579.             strcpy(retour->msg,"Unable to connect to the server");
  1580.           deletesoc(soc);
  1581.           return INVALID_SOCKET;
  1582.         }
  1583.       }
  1584. #if HTS_WIDE_DEBUG    
  1585.       DEBUG_W("connect done\n");
  1586. #endif
  1587.       
  1588. #if HDEBUG
  1589.       printf("connexion Θtablie\n");
  1590. #endif
  1591.     
  1592.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  1593.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  1594.     // read(soc,adr,taille)
  1595.  
  1596.   } else {    // on doit ouvrir un fichier local!
  1597.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  1598.  
  1599.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  1600.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  1601.  
  1602.   }   // teste fichier local ou http
  1603.   
  1604.   return soc;
  1605. }
  1606.  
  1607.  
  1608.  
  1609. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  1610. // retour=-1 si erreur.
  1611. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  1612. int ident_url(char* url,char* adr,char* fil) {
  1613.   char *p,*q;
  1614.   // traiter url
  1615.  
  1616.   // effacer adr et fil
  1617.   adr[0]=fil[0]='\0';
  1618.   
  1619.   p=strstr(url,"://");    // "scheme":// (RFC1945)
  1620.   if (p) {
  1621. #if HDEBUG
  1622.     printf("protocol: %s\n",url);
  1623. #endif
  1624.     // analyser le scheme
  1625.     if (strfield(url,"mailto")!=0) {
  1626.       return -1;    // erreur non reconnu
  1627.     } else if (strfield(url,"news")!=0) {
  1628.       return -1;    // erreur non reconnu
  1629.     } else if (strfield(url,"javascript")!=0) {
  1630.       return -1;    // erreur non reconnu
  1631.     //
  1632.     } else if (strfield(url,"file")!=0) {    // fichier local!! (pour les tests)
  1633.       p+=3;
  1634.       strcpy(adr,"file://");
  1635.       //## strcpy(adr,lOCAL_CHAR_STR);    // indique un fichier local..
  1636.     //
  1637.     } else if (strfield(url,"http")!=0) {    // HTTP
  1638.       p+=3;
  1639.     //
  1640.     } else if (strfield(url,"ftp")!=0) {    // FTP
  1641.       //if (ftp_available()) {
  1642.       strcpy(adr,"ftp://");    // FTP!!
  1643.       //}
  1644.       p+=3;
  1645.     } else {
  1646.       // return -1;
  1647.       p+=3;    // tant pis, beaucoup de ftp acceptent des requΦtes http 
  1648.                // on peut tjs essayer!
  1649.     }
  1650.   } else {
  1651.     int n;
  1652.     p=url;    // sans http://
  1653.     /* Bogus form: 
  1654.        "http:foo.html" means "foo.html" */
  1655.     if ((n=strfield(url,"http:")) !=0 ) {
  1656.       p+=n;
  1657.     }
  1658.   }
  1659.  
  1660.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  1661.   if (strcmp(adr,"file://")) {      // PAS file://
  1662.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  1663.     q=strchr(jump_identification(p),'/');
  1664.     if (q==0) q=p+strlen(p);  // pointe sur \0
  1665.     // pointe sur le chemin, ex: index.html?query=recherche
  1666.     
  1667.     // chemin www... trop long!!
  1668.     if ( ( ((int) q)- ((int) p) )  > HTS_URLMAXSIZE) {
  1669.       //strcpy(retour.msg,"Path too long");
  1670.       return -1;    // erreur
  1671.     }
  1672.     
  1673.     // recopier adresse www..
  1674.     strncat(adr,p, ((int) q) - ((int) p) );
  1675.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  1676.     // recopier chemin /pub/..
  1677.     strcat(fil,q);
  1678.     if (strnotempty(fil)==0)    // page par dΘfaut (/)
  1679.       strcat(fil,"/");
  1680.     // SECURITE:
  1681.     // simplifier url pour les ../
  1682.     fil_simplifie(fil);
  1683.   } else {    // localhost file://
  1684.     int i;
  1685.     char* a;
  1686.     strcat(fil,p);    // fichier local ; adr="#"
  1687.     a=strchr(fil,'?');
  1688.     if (a) 
  1689.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  1690.     // filtrer les \\ -> / pour les fichiers DOS
  1691.     for(i=0;i<(int) strlen(fil);i++)
  1692.       if (fil[i]=='\\')
  1693.         fil[i]='/';
  1694.   }
  1695.  
  1696.   // nommer au besoin.. (non utilisΘ normalement)
  1697.   if (strnotempty(fil)==0)
  1698.     strcpy(fil,"default-index.html");
  1699.  
  1700.   // case insensitive pour adresse
  1701.   {
  1702.     char *a=jump_identification(adr);
  1703.     while(*a) {
  1704.       if ((*a>='A') && (*a<='Z'))
  1705.         *a+='a'-'A';       
  1706.       a++;
  1707.     }
  1708.   }
  1709.   
  1710.   return 0;
  1711. }
  1712.  
  1713. // simplification des ../
  1714. void fil_simplifie(char* f) {
  1715.   int i=0;
  1716.   int last=0;
  1717.   char* a;
  1718.  
  1719.   // Θliminer ../
  1720.   while (f[i]) {
  1721.     
  1722.     if (f[i]=='/') {
  1723.       if (f[i+1]=='.')
  1724.       if (f[i+2]=='.')      // couper dernier rΘpertoire
  1725.       if (f[i+3]=='/')      // Θviter les /tmp/..coolandlamedir/
  1726.       {    // couper dernier rΘpertoire
  1727.         char tempo[HTS_URLMAXSIZE*2];
  1728.         tempo[0]='\0';
  1729.         //
  1730.         if (!last)                /* can't go upper.. */
  1731.           strcpy(tempo,"/");
  1732.         else
  1733.           strncpy(tempo,f,last+1);
  1734.         tempo[last+1]='\0';
  1735.         strcat(tempo,f+i+4);
  1736.         strcpy(f,tempo);    // remplacer
  1737.         i=-1;             // recommencer
  1738.         last=0;
  1739.       }
  1740.       
  1741.       if (i>=0)
  1742.         last=i;
  1743.       else
  1744.         last=0;
  1745.     }
  1746.     
  1747.     i++;
  1748.   }
  1749.  
  1750.   // Θliminer ./
  1751.   while ( (a=strstr(f,"./")) ) {
  1752.     char tempo[HTS_URLMAXSIZE*2];
  1753.     tempo[0]='\0';
  1754.     strcpy(tempo,a+2);
  1755.     strcpy(a,tempo);
  1756.   }
  1757.   // delete all remaining ../ (potential threat)
  1758.   while ( (a=strstr(f,"../")) ) {
  1759.     char tempo[HTS_URLMAXSIZE*2];
  1760.     tempo[0]='\0';
  1761.     strcpy(tempo,a+3);
  1762.     strcpy(a,tempo);
  1763.   }
  1764.   
  1765. }
  1766.  
  1767.  
  1768. // fermer liaison fichier ou socket
  1769. HTS_INLINE void deletehttp(htsblk* r) {
  1770. #if HTS_DEBUG_CLOSESOCK
  1771.     char info[256];
  1772.     sprintf(info,"deletehttp: (htsblk*) %d\n",r);
  1773.     DEBUG_W2(info);
  1774. #endif
  1775.   if (r->soc!=INVALID_SOCKET) {
  1776.     if (r->is_file) {
  1777.       if (r->fp)
  1778.         fclose(r->fp);
  1779.       r->fp=NULL;
  1780.     } else {
  1781.       if (r->soc!=LOCAL_SOCKET_ID)
  1782.         deletesoc(r->soc);
  1783.     }
  1784.     r->soc=INVALID_SOCKET;
  1785.   }
  1786. }
  1787.  
  1788. // fermer une socket
  1789. HTS_INLINE void deletesoc(T_SOC soc) {
  1790.   if (soc!=INVALID_SOCKET) {
  1791. // J'ai plantΘ.. pas de shutdown
  1792. //#if HTS_WIDE_DEBUG    
  1793. //    DEBUG_W("shutdown\n");
  1794. //#endif
  1795. //    shutdown(soc,2);  // shutdown
  1796. //#if HTS_WIDE_DEBUG    
  1797. //    DEBUG_W("shutdown done\n");
  1798. //#endif
  1799.     // Ne pas oublier de fermer la connexion avant de partir.. (plus propre)
  1800. #if HTS_WIDE_DEBUG    
  1801.     DEBUG_W("close\n");
  1802. #endif
  1803. #if HTS_WIN
  1804.     closesocket(soc);
  1805. #else
  1806.     close(soc);
  1807. #endif
  1808. #if HTS_WIDE_DEBUG    
  1809.     DEBUG_W("close done\n");
  1810. #endif
  1811.   }
  1812. }
  1813.  
  1814. // renvoi le nombre de secondes depuis 1970
  1815. HTS_INLINE double time_local() {
  1816.   return ((double) time(NULL));
  1817. }
  1818.  
  1819. // number of millisec since 1970
  1820. HTS_INLINE double mtime_local() {
  1821. #ifndef HTS_DO_NOT_USE_FTIME
  1822.   struct timeb B;
  1823.   ftime( &B );
  1824.   return (double) ( ((double) B.time * (double) 1000.0)
  1825.         + ((double) B.millitm) );
  1826. #else
  1827.   // not precise..
  1828.   return (double) ( ((double) time_local() * (double) 1000.0)
  1829.         + ((double) 0) );
  1830. #endif
  1831. }
  1832.  
  1833. // convertit un nombre de secondes en temps (chaine)
  1834. void sec2str(char *st,double t) {
  1835.   int j,h,m,s;
  1836.   
  1837.   j=(int) (t/(3600.0*24.0));
  1838.   t-=((double) j)*(3600.0*24.0);
  1839.   h=(int) (t/(3600.0));
  1840.   t-=((double) h)*3600.0;
  1841.   m=(int) (t/60.0);
  1842.   t-=((double) m)*60.0;
  1843.   s=(int) t;
  1844.   
  1845.   if (j>0)
  1846.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  1847.   else if (h>0)
  1848.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  1849.   else if (m>0)
  1850.     sprintf(st,"%d minutes %d seconds",m,s);
  1851.   else
  1852.     sprintf(st,"%d seconds",s);
  1853. }
  1854.  
  1855. // idem, plus court (chaine)
  1856. void qsec2str(char *st,double t) {
  1857.   int j,h,m,s;
  1858.   
  1859.   j=(int) (t/(3600.0*24.0));
  1860.   t-=((double) j)*(3600.0*24.0);
  1861.   h=(int) (t/(3600.0));
  1862.   t-=((double) h)*3600.0;
  1863.   m=(int) (t/60.0);
  1864.   t-=((double) m)*60.0;
  1865.   s=(int) t;
  1866.   
  1867.   if (j>0)
  1868.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  1869.   else if (h>0)
  1870.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  1871.   else if (m>0)
  1872.     sprintf(st,"%dmin%02ds",m,s);
  1873.   else
  1874.     sprintf(st,"%ds",s);
  1875. }
  1876.  
  1877.  
  1878. // heure actuelle, GMT, format rfc (taille buffer 256o)
  1879. void time_gmt_rfc822(char* s) {
  1880.   time_t tt;
  1881.   struct tm* A;
  1882.   tt=time(NULL);
  1883.   A=gmtime(&tt);
  1884.   if (A==NULL)
  1885.     A=localtime(&tt);
  1886.   time_rfc822(s,A);
  1887. }
  1888.  
  1889. // heure actuelle, format rfc (taille buffer 256o)
  1890. void time_local_rfc822(char* s) {
  1891.   time_t tt;
  1892.   struct tm* A;
  1893.   tt=time(NULL);
  1894.   A=localtime(&tt);
  1895.   time_rfc822_local(s,A);
  1896. }
  1897.  
  1898. /* convertir une chaine en temps */
  1899. struct tm* convert_time_rfc822(char* s) {
  1900.   static struct tm result;
  1901.   /* */
  1902.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  1903.   char str[256];
  1904.   char* a;
  1905.   /* */
  1906.   int result_mm=-1;
  1907.   int result_dd=-1;
  1908.   int result_n1=-1;
  1909.   int result_n2=-1;
  1910.   int result_n3=-1;
  1911.   int result_n4=-1;
  1912.   /* */
  1913.   if ((int) strlen(s) > 200)
  1914.     return NULL;
  1915.   strcpy(str,s);
  1916.   hts_lowcase(str);
  1917.   /* Θliminer :,- */
  1918.   while( (a=strchr(str,'-')) ) *a=' ';
  1919.   while( (a=strchr(str,':')) ) *a=' ';
  1920.   while( (a=strchr(str,',')) ) *a=' ';
  1921.   /* tokeniser */
  1922.   a=str;
  1923.   while(*a) {
  1924.     char *first,*last;
  1925.     char tok[256];
  1926.     /* dΘcouper mot */
  1927.     while(*a==' ') a++;   /* sauter espaces */
  1928.     first=a;
  1929.     while((*a) && (*a!=' ')) a++;
  1930.     last=a;
  1931.     tok[0]='\0';
  1932.     if (first!=last) {
  1933.       char* pos;
  1934.       strncat(tok,first,(int) last-(int) first);
  1935.       /* analyser */
  1936.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  1937.         result_mm=((int) pos-(int) months)/4;
  1938.       } else {
  1939.         int number;
  1940.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  1941.           if (result_dd<0)                        /* day always first number */
  1942.             result_dd=number;
  1943.           else if (result_n1<0)
  1944.             result_n1=number;
  1945.           else if (result_n2<0)
  1946.             result_n2=number;
  1947.           else if (result_n3<0)
  1948.             result_n3=number;
  1949.           else if (result_n4<0)
  1950.             result_n4=number;
  1951.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  1952.       }
  1953.     }
  1954.   }
  1955.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  1956.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  1957.       result.tm_year=result_n4-1900;
  1958.       result.tm_hour=result_n1;
  1959.       result.tm_min=result_n2;
  1960.       result.tm_sec=max(result_n3,0);
  1961.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  1962.       result.tm_hour=result_n2;
  1963.       result.tm_min=result_n3;
  1964.       result.tm_sec=max(result_n4,0);
  1965.       if (result_n1<=50)                /* 00 means 2000 */
  1966.         result.tm_year=result_n1+100;
  1967.       else if (result_n1<1000)          /* 99 means 1999 */
  1968.         result.tm_year=result_n1;
  1969.       else                              /* 2000 */
  1970.         result.tm_year=result_n1-1900;
  1971.     }
  1972.     result.tm_isdst=0;        /* assume GMT */
  1973.     result.tm_yday=-1;        /* don't know */
  1974.     result.tm_wday=-1;        /* don't know */
  1975.     result.tm_mon=result_mm;
  1976.     result.tm_mday=result_dd;
  1977.     return &result;
  1978.   }
  1979.   return NULL;
  1980. }
  1981.  
  1982. /* sets file time. -1 if error */
  1983. int set_filetime(char* file,struct tm* tm_time) {
  1984.   struct utimbuf tim;
  1985. #ifndef HTS_DO_NOT_USE_FTIME
  1986.   struct timeb B;
  1987.   B.timezone=0;
  1988.   ftime( &B );
  1989.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  1990. #else
  1991.   // bogus time (GMT/local)..
  1992.   tim.actime=tim.modtime=mktime(tm_time); 
  1993. #endif
  1994.   return utime(file,&tim);
  1995. }
  1996.  
  1997. /* sets file time from RFC822 date+time, -1 if error*/
  1998. int set_filetime_rfc822(char* file,char* date) {
  1999.   struct tm* tm_s=convert_time_rfc822(date);
  2000.   if (tm_s) {
  2001.     return set_filetime(file,tm_s);
  2002.   } else return -1;
  2003. }
  2004.  
  2005.  
  2006. // heure au format rfc (taille buffer 256o)
  2007. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2008.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2009. }
  2010.  
  2011. // heure locale au format rfc (taille buffer 256o)
  2012. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2013.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2014. }
  2015.  
  2016. // conversion en b,Kb,Mb
  2017. char* int2bytes(LLint n) {
  2018.   static char buff[256];
  2019.   char** a=int2bytes2(n);
  2020.   strcpy(buff,a[0]);
  2021.   strcat(buff,a[1]);
  2022.   return buff;
  2023. }
  2024.  
  2025. // conversion en b/s,Kb/s,Mb/s
  2026. char* int2bytessec(long int n) {
  2027.   static char buff[256];
  2028.   char** a=int2bytes2(n);
  2029.   strcpy(buff,a[0]);
  2030.   strcat(buff,a[1]);
  2031.   return concat(buff,"/s");
  2032. }
  2033.  
  2034. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2035. // limite: 2.10^9.10^6B
  2036. char** int2bytes2(LLint n) {
  2037.   static char buff1[256];
  2038.   static char buff2[32];
  2039.   static char* buffadr[2];
  2040.   if (n<1024) {
  2041.     sprintf(buff1,"%d",(int)n);
  2042.     strcpy(buff2,"B");
  2043.   } else if (n<(1024*1024)) {
  2044.     sprintf(buff1,"%d,%02d",(int)(n/1024),(int)((n%1024)*100)/1024);
  2045.     strcpy(buff2,"KB");
  2046.   } else {
  2047.     sprintf(buff1,"%d,%02d",(int)(n/(1024*1024)),(int)(((n%(1024*1024))*100)/(1024*1024)));
  2048.     strcpy(buff2,"MB");
  2049.   }
  2050.   buffadr[0]=buff1;
  2051.   buffadr[1]=buff2;
  2052.   return buffadr;
  2053. }
  2054.  
  2055.  
  2056. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2057. HTS_INLINE int sendc(T_SOC soc,char* s) {
  2058. #if HDEBUG
  2059.   write(0,s,strlen(s));
  2060. #endif
  2061. //#if HTS_WIN
  2062.   return send(soc,s,strlen(s),0);
  2063. //#else
  2064. //  return write(soc,s,strlen(s));
  2065. //#endif
  2066. }
  2067.  
  2068.  
  2069. // Remplace read
  2070. void finput(int fd,char* s,int max) {
  2071.   static char c;
  2072.   register int j=0;
  2073.   do {
  2074.     //c=fgetc(fp);
  2075.     if (read(fd,&c,1)<=0) {
  2076.       c=0;
  2077.     }
  2078.     if (c!=0) {
  2079.       switch(c) {
  2080.       case 10: c=0; break;
  2081.       case 13: break;  // sauter ces caractΦres
  2082.       default: s[j++]=c; break;
  2083.       }
  2084.     }
  2085.   }  while((c!=0) && (j<max-1));
  2086.   s[j++]='\0';
  2087.  
  2088. // lire ligne dans buffer, renvoi incrΘment α opΘrer sur l'adresse ensuite
  2089. int binput(char* buff,char* s,int max) {
  2090.   static char c;
  2091.   register int j=0;
  2092.   register int i=0;
  2093.   if ((*buff)=='\0') {  // fin du buffer
  2094.     s[0]='\0';
  2095.     return 0;  // eof  
  2096.   }
  2097.   do {
  2098.     //c=fgetc(fp);
  2099.     c=*(buff++); i++;
  2100.     if (c!=0) {
  2101.       switch(c) {
  2102.       case 10: c=0; break;
  2103.       case 13: break;  // sauter ces caractΦres
  2104.       default: s[j++]=c; break;
  2105.       }
  2106.     }
  2107.   }  while((c!=0) && (j<max-1));
  2108.   s[j++]='\0';
  2109.   return i;
  2110.  
  2111. // Remplace fscanf(fp,"%s",s)
  2112. void linput(FILE* fp,char* s,int max) {
  2113.   register int c;
  2114.   register int j=0;
  2115.   do {
  2116.     c=fgetc(fp);
  2117.     if (c!=EOF) {
  2118.       switch(c) {
  2119.         case 13: break;  // sauter CR
  2120.         case 10: c=-1; break;
  2121.         case 9: case 12: break;  // sauter ces caractΦres
  2122.         default: s[j++]=(char) c; break;
  2123.       }
  2124.     }
  2125.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2126.   s[j++]='\0';
  2127. }
  2128. void linput_trim(FILE* fp,char* s,int max) {
  2129.   char* ls=(char*) malloc(max+2);
  2130.   if (ls) {
  2131.     char* a;
  2132.     // lire ligne
  2133.     linput(fp,ls,max);
  2134.     // sauter espaces et tabs en fin
  2135.     while((ls[strlen(ls)-1]==' ') || (ls[strlen(ls)-1]=='\t')) ls[strlen(ls)-1]='\0';
  2136.     // sauter espaces en dΘbut
  2137.     a=ls; while((*a==' ') || (*a=='\t')) a++;
  2138.     strcpy(s,a);
  2139.     //
  2140.     free(ls);
  2141.   }
  2142. }
  2143. void linput_cpp(FILE* fp,char* s,int max) {
  2144.   s[0]='\0';
  2145.   do {
  2146.     if (s[strlen(s)-1]=='\\') s[strlen(s)-1]='\0';      // couper \ final
  2147.     // lire ligne
  2148.     linput_trim(fp,s+strlen(s),max-strlen(s));
  2149.   } while((s[strlen(s)-1]=='\\') && ((int)strlen(s)<max));
  2150. }
  2151.  
  2152. // idem avec les car spΘciaux
  2153. void rawlinput(FILE* fp,char* s,int max) {
  2154.   register int c;
  2155.   register int j=0;
  2156.   do {
  2157.     c=fgetc(fp);
  2158.     if (c!=EOF) {
  2159.       switch(c) {
  2160.         case 13: break;  // sauter CR
  2161.         case 10: c=-1; break;
  2162.         default: s[j++]=(char) c; break;
  2163.       }
  2164.     }
  2165.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2166.   s[j++]='\0';
  2167. }
  2168.  
  2169.  
  2170. // compare le dΘbut de f avec s et retourne la position de la fin
  2171. // 'A=a' (case insensitive)
  2172. int strfield(const char* f,const char* s) {
  2173.   register int r=0;
  2174.   while (streql(*f,*s) && ((*f)!=0) && ((*s)!=0)) { f++; s++; r++; }
  2175.   if (*s==0)
  2176.     return r;
  2177.   else
  2178.     return 0;
  2179. }
  2180.  
  2181. //cherche chaine, case insensitive
  2182. char* strstrcase(char *s,char *o) {
  2183.   while((*s) && (strfield(s,o)==0)) s++;
  2184.   if (*s=='\0') return NULL;
  2185.   return s;  
  2186. }
  2187.  
  2188.  
  2189. // le fichier est-il un fichier html?
  2190. //  0 : non
  2191. //  1 : oui
  2192. // -1 : on sait pas
  2193. // -2 : on sait pas, pas d'extension
  2194. int ishtml(char* fil) {
  2195.   char *a;
  2196.  
  2197.   // patch pour les truc.html?Choix=toto
  2198.   if ( (a=strchr(fil,'?')) )  // paramΦtres?
  2199.     a--;  // pointer juste avant le ?
  2200.   else
  2201.     a=fil+strlen(fil)-1;  // pointer sur le dernier caractΦre
  2202.  
  2203.   if (*a=='/') return -1;    // rΘpertoire, on sait pas!!
  2204.   //if (*a=='/') return 1;    // ok rΘpertoire, html
  2205.  
  2206.   while ( (*a!='.') && (*a!='/')  && ((int) a>(int) fil)) a--;
  2207.   if (*a=='.') {  // a une extension
  2208.     a++;  // pointer sur extension
  2209.     return ishtml_ext(a);     // retour
  2210.   } else return -2;   // indΘterminΘ, par exemple /truc
  2211. }
  2212.  
  2213. // idem, mais pour uniquement l'extension
  2214. int ishtml_ext(char* a) {
  2215.   int html=0;  
  2216.   //
  2217.   if (strfield2(a,"html"))  html = 1;
  2218.   else if (strfield2(a,"htm"))   html = 1;
  2219.   else if (strfield2(a,"shtml")) html = 1;
  2220.   else if (strfield2(a,"htmlx")) html = 1;
  2221.   else if (strfield2(a,"shtm"))  html = 1;
  2222.   else if (strfield2(a,"htmx"))  html = 1;
  2223.   //
  2224.   else if (strfield2(a,"asp"))   html = -1;
  2225.   else if (strfield2(a,"cgi"))   html = -1;    // indΘterminΘ
  2226.   //
  2227.   // insuccΦs..
  2228.   else {
  2229.     if (is_knowntype(a))
  2230.       html = 0;     // connu, non html (html ont ΘtΘ testΘs avant)
  2231.     else
  2232.       html = -1;    // inconnu..
  2233.   }
  2234.   return html;  
  2235. }
  2236.  
  2237. // error (404,500..)
  2238. HTS_INLINE int ishttperror(int err) {
  2239.   switch (err/100) {
  2240.     case 4: case 5: return 1;
  2241.       break;
  2242.   }
  2243.   return 0;
  2244. }
  2245.  
  2246.  
  2247. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant une identification
  2248. char* jump_identification(char* source) {
  2249.   char *a,*b;
  2250.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  2251.   // mais sauter ftp:// Θventuel
  2252.   a = jump_protocol(source);
  2253.   while( (b = strchr(a,'@')) ) {
  2254.     char* c;
  2255.     if ( (c=strchr(a,'/')) )        /* si un / est trouvΘ */
  2256.     if ((int) c < (int) b)      /* avant le @ */
  2257.       return a;                 /* alors exit (http://www.foo.bar/1.html@A20) */
  2258.     a=b+1;
  2259.   }
  2260.   return a;
  2261. }
  2262.  
  2263. // retourner adr sans ftp://
  2264. HTS_INLINE char* jump_protocol(char* source) {
  2265.   if (strncmp(source,"ftp://",6)==0)
  2266.     return source+6;
  2267.   else if (strncmp(source,"http://",7)==0)
  2268.     return source+7;
  2269.   /* bogus form: http:relative.html */
  2270.   else if (strncmp(source,"http:",5)==0)
  2271.     return source+5;
  2272.   return source;
  2273. }
  2274.  
  2275. // codage base 64 a vers b
  2276. void code64(char* a,char* b) {
  2277.   int i1=0,i2=0,i3=0,i4=0;
  2278.   unsigned long store;
  2279.   int n;
  2280.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  2281.   b[0]='\0';
  2282.   while(*a) {  
  2283.     // 24 bits
  2284.     n=1; store=0; store |= ((*a++) & 0xff);
  2285.     if (*a) { n=2; store <<= 8; store |= ((*a++) & 0xff); }
  2286.     if (*a) { n=3; store <<= 8; store |= ((*a++) & 0xff); }
  2287.     if (n==3) {
  2288.       i4=store & 63;
  2289.       i3=(store>>6) & 63;
  2290.       i2=(store>>12) & 63;
  2291.       i1=(store>>18) & 63;
  2292.     } else if (n==2) {
  2293.       store<<=2;    
  2294.       i3=store & 63;
  2295.       i2=(store>>6) & 63;
  2296.       i1=(store>>12) & 63;
  2297.     } else {
  2298.       store<<=4;
  2299.       i2=store & 63;
  2300.       i1=(store>>6) & 63;
  2301.     }
  2302.     
  2303.     *b++ = _hts_base64[i1];
  2304.     *b++ = _hts_base64[i2];
  2305.     if (n>=2)
  2306.       *b++ = _hts_base64[i3];
  2307.     else
  2308.       *b++ = '=';
  2309.     if (n>=3)
  2310.       *b++ = _hts_base64[i4];
  2311.     else
  2312.       *b++ = '=';
  2313.   }
  2314.   *b++='\0';
  2315. }
  2316.  
  2317. // remplacer " par " etc..
  2318. // buffer MAX 1Ko
  2319. void unescape_amp(char* s) {
  2320.   while(*s) {
  2321.     if (*s=='&') {
  2322.       char* end=strchr(s,';');
  2323.       if ( ((int) end - (int) s) <= 8) {
  2324.         char c=0;
  2325.         if (strfield(s,"&"))
  2326.           c='&';
  2327.         else if (strfield(s,"°"))
  2328.           c='░';
  2329.         else if (strfield(s,">"))
  2330.           c='>';
  2331.         else if (strfield(s,"«"))
  2332.           c='\"';
  2333.         else if (strfield(s,"<"))
  2334.           c='<';
  2335.         else if (strfield(s," "))
  2336.           c=' ';
  2337.         else if (strfield(s,"""))
  2338.           c='\"';
  2339.         else if (strfield(s,"»"))
  2340.           c='\"';
  2341.         else if (strfield(s,"­"))
  2342.           c='-';
  2343.         else if (strfield(s,"˜"))
  2344.           c='~';
  2345.         else if (strfield(s,"&"))
  2346.           c='&';
  2347.         // remplacer?
  2348.         if (c) {
  2349.           char buff[HTS_URLMAXSIZE*2];
  2350.           buff[0]=c;
  2351.           strcpy(buff+1,end+1);
  2352.           strcpy(s,buff);
  2353.         }
  2354.       }
  2355.     }
  2356.     s++;
  2357.   }
  2358. }
  2359.  
  2360. // remplacer %20 par ' ', | par : etc..
  2361. // buffer MAX 1Ko
  2362. char* unescape_http(char* s) {
  2363.   static char tempo[HTS_URLMAXSIZE*2];
  2364.   int i,j=0;
  2365.   for (i=0;i<(int) strlen(s);i++) {
  2366.     if (s[i]=='%') {
  2367.       i++;
  2368.       tempo[j++]=(char) ehex(s+i);
  2369.       i++;    // sauter 2 caractΦres finalement
  2370.     } else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  2371.       tempo[j++]=':';
  2372.     } else
  2373.       tempo[j++]=s[i];
  2374.   }
  2375.   tempo[j++]='\0';
  2376.   return tempo;
  2377. }
  2378.  
  2379. // remplacer " par %xx etc..
  2380. // buffer MAX 1Ko
  2381. void escape_spc_url(char* s) {
  2382.   x_escape_http(s,2);
  2383. }
  2384. // smith / john -> smith%20%2f%20john
  2385. void escape_in_url(char* s) {
  2386.   x_escape_http(s,1);
  2387. }
  2388. void escape_check_url(char* s) {
  2389.   x_escape_http(s,0);
  2390. }
  2391. void x_escape_http(char* s,int mode) {
  2392.   while(*s) {
  2393.     int test=0;
  2394.     if (mode == 0)
  2395.       test=(strchr("\" ",*s)!=0);
  2396.     else if (mode==1) {
  2397.       // Safe (RFC2396)
  2398.       test=(strchr(";/?:@&=+$,",*s)!=0);
  2399.       // Safe for us..
  2400.       if (!test)
  2401.         test=(strchr(" %*<>#'\"\\",*s)!=0);
  2402.       // Escape >127 (much safer)
  2403.       if (!test)
  2404.         test=((((unsigned char)*s) > 127)?1:0);
  2405.     }
  2406.     else if (mode==2)
  2407.       test=(strchr(" ",*s)!=0);           // n'escaper que espace
  2408.  
  2409.     if (test) {
  2410.       char buffer[HTS_URLMAXSIZE*2];
  2411.       int n;
  2412.       n=(int)(unsigned char) *s;
  2413.       strcpy(buffer,s+1);
  2414.       sprintf(s,"%%%02x",n);
  2415.       strcat(s,buffer);
  2416.     }
  2417.     s++;
  2418.   }
  2419. }
  2420.  
  2421.  
  2422. HTS_INLINE int ehexh(char c) {
  2423.   if ((c>='0') && (c<='9')) return c-'0';
  2424.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  2425.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  2426.   return 0;
  2427. }
  2428.  
  2429. HTS_INLINE int ehex(char* s) {
  2430.   return 16*ehexh(*s)+ehexh(*(s+1));
  2431.  
  2432. }
  2433.  
  2434. // concat, concatΦne deux chaines et renvoi le rΘsultat
  2435. // permet d'allΘger grandement le code
  2436. // il faut savoir qu'on ne peut mettre plus de 8 concat() dans une expression
  2437. char* concat(const char* a,const char* b) {
  2438.   static char buff[8][HTS_URLMAXSIZE*2];
  2439.   static int rol;
  2440.   rol=((rol+1)%8);    // roving pointer
  2441.   strcpy(buff[rol],a);
  2442.   if (b) strcat(buff[rol],b);
  2443.   return buff[rol];
  2444. }
  2445. // conversion fichier / -> antislash
  2446. #if HTS_DOSNAME
  2447. char* __fconv(char* a) {
  2448.   int i;
  2449.   for(i=0;i<(int) strlen(a);i++)
  2450.     if (a[i]=='/')  // convertir
  2451.       a[i]='\\';
  2452.   return a;
  2453. }
  2454. char* fconcat(char* a,char* b) {
  2455.   return __fconv(concat(a,b));
  2456. }
  2457. char* fconv(char* a) {
  2458.   return __fconv(concat(a,""));
  2459. }
  2460. #endif
  2461.  
  2462. /* / et \\ en / */
  2463. char* __fslash(char* a) {
  2464.   int i;
  2465.   for(i=0;i<(int) strlen(a);i++)
  2466.     if (a[i]=='\\')  // convertir
  2467.       a[i]='/';
  2468.   return a;
  2469. }
  2470. char* fslash(char* a) {
  2471.   return __fslash(concat(a,""));
  2472. }
  2473.  
  2474. // conversion minuscules, avec buffer
  2475. char* convtolower(char* a) {
  2476.   static char buff[8][HTS_URLMAXSIZE*2];
  2477.   static int rol;
  2478.   rol=((rol+1)%8);    // roving pointer
  2479.   strcpy(buff[rol],a);
  2480.   hts_lowcase(buff[rol]);  // lower case
  2481.   return buff[rol];
  2482. }
  2483.  
  2484. // conversion en minuscules
  2485. void hts_lowcase(char* s) {
  2486.   register int i;
  2487.   for(i=0;i<(int) strlen(s);i++)
  2488.     if ((s[i]>='A') && (s[i]<='Z'))
  2489.       s[i]+=('a'-'A');
  2490. }
  2491.  
  2492. // remplacer un caractΦre d'une chaεne dans une autre
  2493. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  2494.   register char* a;
  2495.   while ((a=strchr(s,from))!=NULL) {
  2496.     *a=to;
  2497.   }
  2498. }
  2499.  
  2500.  
  2501. // caractΦre espace, guillemets, CR, LF etc..
  2502. /* SECTION OPTIMISEE:
  2503.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  2504.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09",c)!=NULL)
  2505. */
  2506. /*
  2507. HTS_INLINE int is_space(char c) {
  2508.   if (c==' ')  return 1;  // spc
  2509.   if (c=='"')  return 1;  // quote
  2510.   if (c==10)   return 1;  // lf
  2511.   if (c==13)   return 1;  // cr
  2512.   if (c=='\'') return 1;  // quote
  2513.   //if (c=='`')  return 1;  // backquote      << non
  2514.   if (c==9)    return 1;  // tab
  2515.   return 0;
  2516. }
  2517. */
  2518.  
  2519. // caractΦre espace, CR, LF, TAB
  2520. /*
  2521. HTS_INLINE int is_realspace(char c) {
  2522.   if (c==' ')  return 1;  // spc
  2523.   if (c==10)   return 1;  // lf
  2524.   if (c==13)   return 1;  // cr
  2525.   if (c==9)    return 1;  // tab
  2526.   return 0;
  2527. }
  2528. */
  2529.  
  2530.  
  2531.  
  2532.  
  2533.  
  2534. // deviner type d'un fichier local..
  2535. // ex: fil="toto.gif" -> s="image/gif"
  2536. void guess_httptype(char *s,char *fil) {
  2537.   get_httptype(s,fil,1);
  2538. }
  2539. // idem
  2540. // flag: 1 si toujours renvoyer un type
  2541. void get_httptype(char *s,char *fil,int flag) {
  2542.   if (ishtml(fil)==1)
  2543.     strcpy(s,"text/html");
  2544.   else {
  2545.     char *a=fil+strlen(fil)-1;    
  2546.     while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  2547.     if (*a=='.') {
  2548.       int ok=0;
  2549.       int j=0;
  2550.       a++;
  2551.       while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  2552.         if (strfield2(hts_mime[j][1],a)) {
  2553.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  2554.             strcpy(s,hts_mime[j][0]);
  2555.             ok=1;
  2556.           }
  2557.         }
  2558.         j++;
  2559.       }
  2560.       
  2561.       if (!ok) if (flag) sprintf(s,"application/%s",a);
  2562.     } else {
  2563.       if (flag) strcpy(s,"application/octet-stream");
  2564.     }
  2565.   }
  2566. }
  2567. // renvoyer extesion d'un type mime..
  2568. // ex: "image/gif" -> gif
  2569. void give_mimext(char *s,char *st) {   
  2570.   int ok=0;
  2571.   int j=0;
  2572.   strcpy(s,"");
  2573.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  2574.     if (strfield2(hts_mime[j][0],st)) {
  2575.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  2576.         strcpy(s,hts_mime[j][1]);
  2577.         ok=1;
  2578.       }
  2579.     }
  2580.     j++;
  2581.   }    
  2582. }
  2583. // extension connue?..
  2584. int is_knowntype(char *fil) {
  2585.   int j=0;
  2586.   while(strnotempty(hts_mime[j][1])) {
  2587.     if (strfield2(hts_mime[j][1],fil)) {
  2588.       return 1;
  2589.     }
  2590.     j++;
  2591.   }
  2592.   return 0;
  2593. }
  2594. // extension : html,gif..
  2595. char* get_ext(char *fil) {
  2596.   char *a=fil+strlen(fil)-1;    
  2597.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  2598.   if (*a=='.')
  2599.     return a+1;
  2600.   else
  2601.     return NULL;
  2602. }
  2603.  
  2604. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  2605. // connaissent pas le type
  2606. int may_unknown(char* st) {
  2607.   int j=0;
  2608.   while(strnotempty(hts_mime_keep[j])) {
  2609.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  2610.       return 1;
  2611.     }
  2612.     j++;
  2613.   }    
  2614.   return 0;
  2615. }
  2616.  
  2617.  
  2618. // -- Utils fichiers
  2619. /* Le fichier existe-t-il? (ou est-il HTS_ACCESSible?) */
  2620. int fexist(char* s) {
  2621.   FILE* fp;
  2622.   if (strnotempty(s)==0)     // nom vide: non trouvΘ
  2623.     return 0;
  2624.   fp=fopen(fconv(s),"rb");
  2625.   if (fp!=NULL) fclose(fp);
  2626.   return (fp!=NULL);
  2627.  
  2628. /* Taille d'un fichier, -1 si n'existe pas */
  2629. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  2630. /* Note: NOT YET READY FOR 64-bit */
  2631. //LLint fsize(char* s) {
  2632. int fsize(char* s) {
  2633.   /*
  2634. #if HTS_WIN
  2635.   HANDLE hFile;
  2636.   DWORD dwSizeHigh = 0;
  2637.   DWORD dwSizeLow  = 0;
  2638.   hFile = CreateFile(s,0,0,NULL,OPEN_EXISTING,0,NULL);
  2639.   if (hFile) {
  2640.     dwSizeLow = GetFileSize (hFile, & dwSizeHigh) ;
  2641.     CloseHandle(hFile);
  2642.     if (dwSizeLow != 0xFFFFFFFF)
  2643.       return (dwSizeLow & (dwSizeHigh<<32));
  2644.     else
  2645.       return -1;
  2646.   } else
  2647.     return -1;
  2648. #else
  2649.     */
  2650.   FILE* fp;
  2651.   if (strnotempty(s)==0)     // nom vide: erreur
  2652.     return -1;
  2653.   fp=fopen(fconv(s),"rb");
  2654.   if (fp!=NULL) {
  2655.     int i;
  2656.     fseek(fp,0,SEEK_END);
  2657.     i=ftell(fp);
  2658.     fclose(fp);
  2659.     return i;
  2660.   } else return -1;
  2661.   /*
  2662. #endif
  2663.   */
  2664. }
  2665.  
  2666. int fpsize(FILE* fp) {
  2667.   int oldpos,size;
  2668.   if (!fp)
  2669.     return -1;
  2670.   oldpos=ftell(fp);
  2671.   fseek(fp,0,SEEK_END);
  2672.   size=ftell(fp);
  2673.   fseek(fp,oldpos,SEEK_SET);
  2674.   return size;
  2675. }
  2676.  
  2677.  
  2678. hts_stat_struct HTS_STAT;
  2679. //LLint HTS_TOTAL_RECV = 0;  // flux entrant reτu
  2680. //int HTS_TOTAL_RECV_STATE = 0;  // status: 0 tout va bien 1: ralentir un peu 2: ralentir 3: beaucoup
  2681. void HTS_TOTAL_RECV_CHECK(int var) {
  2682.   if (HTS_STAT.HTS_TOTAL_RECV_STATE) { 
  2683.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  2684.       var = min(var,32); 
  2685.       Sleep(250); 
  2686.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  2687.       var = min(var,256); 
  2688.       Sleep(100); 
  2689.     } else { 
  2690.       var/=2; 
  2691.       if (var<=0) var=1; 
  2692.       Sleep(50); 
  2693.     } 
  2694.   }
  2695. }
  2696.  
  2697. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  2698. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  2699.   register int retour;
  2700.   //  return read(soc,buff,size);
  2701.   if (r->is_file) {
  2702. #if HTS_WIDE_DEBUG    
  2703.     DEBUG_W("read\n");
  2704. #endif
  2705.     if (r->fp)
  2706.       retour=fread(buff,1,size,r->fp);
  2707.     else
  2708.       retour=-1;
  2709.   } else {
  2710. #if HTS_WIDE_DEBUG    
  2711.     DEBUG_W("recv\n");
  2712.     if (r->soc==INVALID_SOCKET)
  2713.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  2714. #endif
  2715.     HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  2716.     retour=recv(r->soc,buff,size,0);
  2717.     if (retour>0)    // compter flux entrant
  2718.       HTS_STAT.HTS_TOTAL_RECV+=retour;
  2719.   }
  2720. #if HTS_WIDE_DEBUG    
  2721.   DEBUG_W("recv/read done\n");
  2722. #endif
  2723.   return retour;
  2724. }
  2725.  
  2726.  
  2727. // -- Gestion cache DNS --
  2728. // 'RX98
  2729. #if HTS_DNSCACHE
  2730.  
  2731. // 'capsule' contenant uniquement le cache
  2732. t_dnscache* _hts_cache() {
  2733.   static t_dnscache cache;
  2734.   return &cache;
  2735. }
  2736.  
  2737. // lock le cache dns pour tout opΘration d'ajout
  2738. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  2739. // -1: status? 0: libΘrer 1:locker
  2740.  
  2741. /* 
  2742.   Simple lock function for cache
  2743.  
  2744.   Return value: always 0
  2745.   Parameter:
  2746.   1 wait for lock (mutex) available and lock it
  2747.   0 unlock the mutex
  2748.   [-1 check if locked (always return 0 with mutex)]
  2749.   -999 initialize
  2750. */
  2751. #if USE_BEGINTHREAD
  2752. int _hts_lockdns(int i) {
  2753.   static PTHREAD_LOCK_TYPE hMutex; 
  2754.   return htsSetLock(&hMutex,i);
  2755. }
  2756. #else
  2757. int _hts_lockdns(int i) {
  2758.   static int l=0;
  2759.   if (i>=0)
  2760.     l=i;
  2761.   return l;
  2762. }
  2763. #endif
  2764.  
  2765. // routine pour le cache - retour optionnel α donner α chaque fois
  2766. // NULL: nom non encore testΘ dans le cache
  2767. // si h_length==0 alors le nom n'existe pas dans le dns
  2768. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  2769.   // attendre que le cache dns soit prΩt
  2770.   while(_hts_lockdns(-1));  // attendre libΘration
  2771.   _hts_lockdns(1);          // locker
  2772.  
  2773.   while(1) {
  2774.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  2775.       if (cache->host_length>0) {  // entrΘe valide
  2776.         if (retour->h_addr)
  2777.           bcopy(cache->host_addr,(char *)retour->h_addr,cache->host_length);
  2778.         retour->h_length=cache->host_length;
  2779.       } else if (cache->host_length==0) {  // en cours
  2780.         _hts_lockdns(0);          // dΘlocker
  2781.         return NULL;
  2782.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  2783.         if (retour->h_addr)
  2784.           retour->h_addr[0]='\0';
  2785.         retour->h_length=0;  // erreur, n'existe pas
  2786.       }
  2787.       _hts_lockdns(0);          // dΘlocker
  2788.       return retour;
  2789.     } else {    // on a pas encore trouvΘ
  2790.       if (cache->n!=NULL) { // chercher encore
  2791.         cache=cache->n;   // suivant!
  2792.       } else {
  2793.         _hts_lockdns(0);          // dΘlocker
  2794.         return NULL;    // non prΘsent        
  2795.       }
  2796.     }    
  2797.   }
  2798. }
  2799.  
  2800. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  2801. // 0 non encore
  2802. // 1 ok
  2803. // 2 non prΘsent
  2804. int hts_dnstest(char* _iadr) {
  2805.   static char iadr[HTS_URLMAXSIZE*2];
  2806.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  2807.  
  2808.   // sauter user:pass@ Θventuel
  2809.   strcpy(iadr,jump_identification(_iadr));
  2810.   // couper Θventuel :
  2811.   {
  2812.     char *a;
  2813.     if ( (a=strchr(iadr,':')) )
  2814.       *a='\0';
  2815.   }
  2816.  
  2817. #if HTS_WIN
  2818.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  2819. #else
  2820.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  2821. #endif
  2822.     return 1;
  2823.  
  2824.   while(_hts_lockdns(-1));  // attendre libΘration
  2825.   _hts_lockdns(1);          // locker
  2826.   while(1) {
  2827.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  2828.       _hts_lockdns(0);          // dΘlocker
  2829.       return 1;    // prΘsent!
  2830.     } else {    // on a pas encore trouvΘ
  2831.       if (cache->n!=NULL) { // chercher encore
  2832.         cache=cache->n;   // suivant!
  2833.       } else {
  2834.         _hts_lockdns(0);          // dΘlocker
  2835.         return 2;    // non prΘsent        
  2836.       }
  2837.     }    
  2838.   }
  2839. }
  2840.  
  2841. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  2842. t_hostent* hts_gethostbyname(char* _iadr) {
  2843.   static char iadr[HTS_URLMAXSIZE*2];
  2844.   static t_hostent host;
  2845.   static char adr[HTS_URLMAXSIZE*2]="";  // buffer adr pour host
  2846.   static char* he[2];
  2847.   static unsigned long inetaddr;
  2848.   //
  2849.   t_dnscache* cache=_hts_cache();  // adresse du cache
  2850.   t_hostent* hp;
  2851.  
  2852.   strcpy(iadr,jump_identification(_iadr));
  2853.   // couper Θventuel :
  2854.   {
  2855.     char *a;
  2856.     if ( (a=strchr(adr,':')) )
  2857.       *a='\0';
  2858.   }
  2859.  
  2860.   // effacer structure de retour, crΘer nouvelle
  2861.   bzero((char *)&host,sizeof(t_hostent));  
  2862.   host.h_addr_list=he;
  2863.   he[0]=adr;
  2864.   he[1]=NULL;  
  2865.   host.h_length=0;  
  2866.   cache->iadr[0]='*';
  2867.   cache->iadr[1]='\0';
  2868.   
  2869.   /* get IP from the dns cache */
  2870.   hp = _hts_ghbn(cache,iadr,&host);
  2871.   if (hp) {
  2872.     if (hp->h_length>0)
  2873.       return hp;
  2874.     else
  2875.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  2876.   } else {  // non prΘsent dans le cache dns, tester
  2877.     t_dnscache* c=cache;
  2878.     while(c->n) c=c->n;    // calculer queue
  2879.     
  2880. #if HTS_WIDE_DEBUG    
  2881.     DEBUG_W("gethostbyname\n");
  2882. #endif      
  2883. #if HDEBUG
  2884.     printf("gethostbyname (not in cache)\n");
  2885. #endif
  2886.     {
  2887. #if HTS_WIN
  2888.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  2889. #else
  2890.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  2891. #endif        
  2892. #if DEBUGDNS 
  2893.         printf("resolving (not cached) %s\n",iadr);
  2894. #endif
  2895.         hp=gethostbyname(iadr);  // calculer IP host
  2896.       } else {     // numΘrique, convertir sans passer par le dns
  2897.         host.h_addr=(char*) &inetaddr;
  2898.         host.h_length=4;
  2899.         hp=&host;
  2900.       }
  2901.     }
  2902. #if HTS_WIDE_DEBUG    
  2903.     DEBUG_W("gethostbyname done\n");
  2904. #endif
  2905.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  2906.     if (cache->n!=NULL) {
  2907.       strcpy(cache->n->iadr,iadr);
  2908.       if (hp!=NULL) {
  2909.         bcopy(hp->h_addr,cache->n->host_addr,hp->h_length);
  2910.         cache->n->host_length=hp->h_length;
  2911.       } else {
  2912.         cache->n->host_addr[0]='\0';
  2913.         cache->n->host_length=0;  // non existant dans le dns
  2914.       }
  2915.       cache->n->n=NULL;
  2916.       return hp;
  2917.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  2918.       return hp;
  2919.     }        
  2920.   }  // retour hp du cache
  2921. }
  2922.  
  2923. #else
  2924. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr) {
  2925.   t_hostent* retour;
  2926. #if HTS_WIDE_DEBUG    
  2927.   DEBUG_W("gethostbyname (2)\n");
  2928. #endif
  2929. #if DEBUGDNS 
  2930.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  2931. #endif
  2932.   retour=gethostbyname(jump_identification(iadr));
  2933. #if HTS_WIDE_DEBUG    
  2934.   DEBUG_W("gethostbyname (2) done\n");
  2935. #endif
  2936.   return retour;
  2937. }
  2938. #endif
  2939.  
  2940.  
  2941. // --- Tracage des mallocs() ---
  2942. #if HTS_TRACE_MALLOC
  2943. typedef struct _mlink {
  2944.   void* adr;
  2945.   int len;
  2946.   int id;
  2947.   struct _mlink* next;
  2948. } mlink;
  2949. mlink trmalloc = {NULL,0,0,NULL};
  2950. int trmalloc_id=0;
  2951.  
  2952. HTS_INLINE void* hts_malloc(size_t len,size_t len2) {
  2953.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  2954.   void*  r   = NULL;
  2955.   if (lnk) {
  2956.     if (len2)
  2957.       r = calloc(len,len2);
  2958.     else
  2959.       r = malloc(len);
  2960.     if (r) {
  2961.       lnk->adr=r;
  2962.       if (len2)
  2963.         lnk->len=len*len2;
  2964.       else
  2965.         lnk->len=len;
  2966.       lnk->id=trmalloc_id++;
  2967.       lnk->next=trmalloc.next;
  2968.       trmalloc.next=lnk;
  2969. #if MEMDEBUG
  2970.       //printf("malloc: %d\n",r);
  2971. #endif
  2972.     } else free(lnk);
  2973.   }
  2974.   return r;
  2975. }
  2976. HTS_INLINE void  hts_free(void* adr) {
  2977.   mlink* lnk = &trmalloc;
  2978.   if (!adr) {
  2979. #if MEMDEBUG
  2980.     printf("* unexpected free() error at %d\n",adr);
  2981. #endif
  2982.     return;
  2983.   }
  2984.   do {
  2985.     if (lnk->next->adr==adr) {
  2986.       mlink* blk_free=lnk->next;
  2987. #if 1
  2988.       lnk->next=lnk->next->next;
  2989.       free((void*) blk_free);
  2990. #else
  2991. #if MEMDEBUG
  2992.       if (blk_free->id==-1) {
  2993.         printf("* memory has already been freed: %d (id=%d)\n",blk_free->adr,blk_free->id);
  2994.       }
  2995. #endif
  2996.       blk_free->id=-1;
  2997. #endif
  2998.       free(adr);
  2999. #if MEMDEBUG
  3000.       //printf("free: %d (id=%d)\n",blk_free->adr,blk_free->id);
  3001. #endif
  3002.       return;
  3003.     }
  3004.     lnk=lnk->next;
  3005.   } while(lnk->next != NULL);
  3006. #if MEMDEBUG
  3007.   printf("* unexpected free() error at %d\n",adr);
  3008. #endif
  3009.   free(adr);
  3010. }
  3011. HTS_INLINE void* hts_realloc(void* adr,size_t len) {
  3012.   mlink* lnk = &trmalloc;
  3013.   do {
  3014.     if (lnk->next->adr==adr) {
  3015.       adr = realloc(adr,len);
  3016.       lnk->next->adr = adr;
  3017.       lnk->next->len = len;
  3018. #if MEMDEBUG
  3019.       //printf("realloc: %d (id=%d)\n",lnk->next->adr,lnk->next->id);
  3020. #endif
  3021.       return adr;
  3022.     }
  3023.     lnk=lnk->next;
  3024.   } while(lnk->next != NULL);
  3025. #if MEMDEBUG
  3026.   printf("* unexpected realloc() error at %d\n",adr);
  3027. #endif
  3028.   return realloc(adr,len);
  3029. }
  3030. // check the malloct() and calloct() trace stack
  3031. void  hts_freeall() {
  3032.   while(trmalloc.next) {
  3033. #if MEMDEBUG
  3034.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  3035. #endif
  3036.     if (trmalloc.next->id != -1) {
  3037.       freet(trmalloc.next->adr);
  3038.     }
  3039.   }
  3040. }
  3041. #endif
  3042.  
  3043.  
  3044. // -- divers //
  3045.  
  3046. // cut path and project name
  3047. // patch also initial path
  3048. void cut_path(char* fullpath,char* path,char* pname) {
  3049.   path[0]=pname[0]='\0';
  3050.   if (strnotempty(fullpath)) {
  3051.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  3052.       fullpath[strlen(fullpath)-1]='\0';
  3053.     if (strlen(fullpath)>1) {
  3054.       char* a;
  3055.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  3056.       a=fullpath+strlen(fullpath)-2;
  3057.       while( (*a!='/') && ((int) a > (int) fullpath)) a--;
  3058.       if (*a=='/') a++;
  3059.       strcpy(pname,a);
  3060.       strncat(path,fullpath,(int) a-(int) fullpath);
  3061.     }
  3062.   }
  3063. }
  3064.  
  3065.  
  3066.  
  3067. // -- Gestion protocole ftp --
  3068.  
  3069. #if HTS_WIN
  3070. int ftp_available() {
  3071.   return 1;
  3072. }
  3073. #else
  3074. int ftp_available() {
  3075.   return 1;   // ok!
  3076.   //return 0;   // SOUS UNIX, PROBLEMES
  3077. }
  3078. #endif
  3079.  
  3080.  
  3081. // Fin
  3082.  
  3083.