home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / DCLAP 4j / DNet / DURL.cpp < prev    next >
Encoding:
Text File  |  1995-12-17  |  10.5 KB  |  411 lines  |  [TEXT/R*ch]

  1. // DURL
  2. // d.g.gilbert, Sep.94
  3.  
  4. #include <ncbi.h>
  5. #include <dgg.h>
  6.  
  7. #include <DFile.h>
  8. #include "DTCP.h"
  9. #include "DGopher.h"
  10. #include "DGoClasses.h"
  11. #include "DURL.h"
  12.  
  13.  
  14.  
  15.  
  16. // DURL ------------------------------
  17.  
  18.  
  19. DURL::DURL()
  20. {
  21. }
  22.  
  23.  
  24. short DURL::IsURL( const char *line, char*& url, long maxline)
  25. {    // adapated from Lynx
  26.   char *cp, *lineend;
  27.     
  28.   // don't crash on an empty argument 
  29.   if (line == NULL || *line == '\0') return(DGopher::kUnknownProt);
  30.     if (maxline) lineend = (char*)line + maxline;
  31.     else lineend= StrChr( (char*)line,'\0');
  32.     
  33.     for (cp= (char*)line; cp < lineend && *cp!= ':'; cp++) ;
  34.     if (*cp != ':') return(DGopher::kUnknownProt);
  35.     else if (cp[1] != '/' && cp[2] != '/') {
  36.       // these are only ones that don't contain "://"  
  37.       if (!Nlm_StrNICmp( (url=cp-4),"news",4))                    return(DGopher::kNNTPprot);
  38.       else if (!Nlm_StrNICmp( (url=cp-6),"mailto",6))        return(DGopher::kSMTPprot);
  39.       else if (!Nlm_StrNICmp( (url=cp-5),"whois",5))        return(DGopher::kWhoisprot);
  40.       else if (!Nlm_StrNICmp( (url=cp-6),"finger",6))        return(DGopher::kFingerprot);
  41.       else if (!Nlm_StrNICmp( (url=cp-4),"nntp",4))            return(DGopher::kNNTPprot);
  42.       else if (!Nlm_StrNICmp( (url=cp-9),"newspost",8))    return(DGopher::kUnsupportedProt);
  43.         else     return(DGopher::kUnknownProt);
  44.         }
  45.  
  46.   else if (!Nlm_StrNICmp( (url=cp-6),"gopher",6))        return(DGopher::kGopherprot);
  47.   else if (!Nlm_StrNICmp( (url=cp-4),"http",4))            return(DGopher::kHTTPprot);
  48.   else if (!Nlm_StrNICmp( (url=cp-3),"ftp",3))             return(DGopher::kFTPprot);
  49.   else if (!Nlm_StrNICmp( (url=cp-4),"file",4))             return(DGopher::kFileprot);
  50.   else if (!Nlm_StrNICmp( (url=cp-4),"wais",4))             return(DGopher::kWAISprot);
  51.   else if (!Nlm_StrNICmp( (url=cp-6),"telnet",6))        return(DGopher::kTelnetprot);
  52.   else if (!Nlm_StrNICmp( (url=cp-6),"tn3270",6))        return(DGopher::kTN3270prot);
  53.   else if (!Nlm_StrNICmp( (url=cp-6),"rlogin",6))         return(DGopher::kUnsupportedProt);
  54.   else if (!Nlm_StrNICmp( (url=cp-3),"afs",3))             return(DGopher::kUnsupportedProt);
  55.   else if (!Nlm_StrNICmp( (url=cp-8),"prospero",8))    return(DGopher::kUnsupportedProt);
  56.         // !! Need also to support User-Added protocols via Type/Handler method !
  57.   else    return(DGopher::kUnknownProt);
  58. }
  59.  
  60.  
  61.  
  62. // from Lynx
  63.  
  64. /*        Escape undesirable characters using %        HTEscape()
  65. **        -------------------------------------
  66. **
  67. **    This function takes a pointer to a string in which
  68. **    some characters may be unacceptable unescaped.
  69. **    It returns a string which has these characters
  70. **    represented by a '%' character followed by two hex digits.
  71. **
  72. **    In the tradition of being conservative in what you do and liberal
  73. **    in what you accept, we encode some characters which in fact are
  74. **    allowed in URLs unencoded -- so DON'T use the table below for
  75. **    parsing! 
  76. **
  77. **    Unlike HTUnEscape(), this routine returns a malloced string.
  78. **
  79. */
  80.  
  81.     
  82. static unsigned char isAcceptable[96] =
  83. /* Overencodes */
  84. /*    Bit 0        alphaChars        -- see HTFile.h
  85. **    Bit 1        alphaPlusChars -- as alphaChars but with plus.
  86. **    Bit 2 ...    pathChars        -- as alphaPlusChars but with /
  87. */
  88. /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  89. {  0,0,0,0,0,0,0,0,0,0,7,6,0,7,7,4,    /* 2x   !"#$%&'()*+,-./     */
  90.      7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,    /* 3x  0123456789:;<=>?     */
  91.      7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,    /* 4x  @ABCDEFGHIJKLMNO  */
  92.      7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,    /* 5X  PQRSTUVWXYZ[\]^_     */
  93.      0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,    /* 6x  `abcdefghijklmno     */
  94.      7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0 };    /* 7X  pqrstuvwxyz{\}~    DEL */
  95.  
  96. #define OKAYCHAR(a,mask)    ( a>=32 && a<128 && ((isAcceptable[a-32]) & mask))
  97.  
  98. char* DURL::EncodeChars( const char* str, unsigned char mask)
  99. {
  100.     static char *hexchars = "0123456789ABCDEF";
  101.   const char * p;
  102.   char * q;
  103.   char * result;
  104.   int unacceptable = 0;
  105.  
  106.   for (p=str; *p; p++)
  107.          if (!OKAYCHAR( (unsigned char)*p, mask)) 
  108.             unacceptable++;
  109.   result = (char *) MemNew( p - str + unacceptable + unacceptable + 1);
  110.   if (result == NULL) return "";
  111.  
  112.   for (q=result, p=str; *p; p++) {
  113.       unsigned char a = *p;
  114.         if (!OKAYCHAR(a, mask)) {
  115.         *q++ = HEX_ESCAPE;    
  116.         *q++ = hexchars[a >> 4];
  117.         *q++ = hexchars[a & 15];
  118.             }
  119.         else *q++ = *p;
  120.       }
  121.   *q++ = 0;            
  122.   return result;
  123. }
  124.  
  125.  
  126. /*        Decode %xx escaped characters            HTUnEscape()
  127. **        -----------------------------
  128. **
  129. **    This function takes a pointer to a string in which some
  130. **    characters may have been encoded in %xy form, where xy is
  131. **    the acsii hex code for character 16x+y.
  132. **    The string is converted in place, as it will never grow.
  133. */
  134.  
  135. static char from_hex(char c)
  136. {
  137.     return  c >= '0' && c <= '9' ?  c - '0' 
  138.             : c >= 'A' && c <= 'F'? c - 'A' + 10
  139.             : c - 'a' + 10;     
  140. }
  141.  
  142. //static
  143. char* DURL::DecodeChars( char * str)
  144. {
  145.   char * p = str;
  146.   char * q = str;
  147.  
  148.   if (!str) return "";
  149.   while(*p) {
  150.        if (*p == HEX_ESCAPE) {
  151.         p++;
  152.         if (*p) *q  = from_hex(*p++) * 16;
  153.          if (*p) *q += from_hex(*p++);
  154.       q++;
  155.             } 
  156.    else 
  157.         *q++ = *p++; 
  158.      }
  159.   *q++ = 0;
  160.   return str;
  161.  
  162.  
  163. char* DURL::GetParts( const char* url, long whichparts, long urlsize)
  164. {
  165.     char *cp, *ep, sep, *newurl, *line, *newline;
  166.     
  167.   if (url == NULL || *url == '\0') return NULL;
  168.     if (!urlsize) urlsize= StrLen(url);
  169.     line= (char*) Nlm_MemNew(urlsize+1);
  170.     Nlm_MemCopy(line, url, urlsize);
  171.   line[urlsize]= 0;
  172.     newline= (char*) Nlm_MemNew(urlsize+1);
  173.   *newline= 0;
  174.   
  175.     long prot= IsURL( line, newurl);
  176.     cp= newurl;
  177.     ep= StrChr( newurl+3, ':');
  178.     if (ep) ep++;
  179.     if (*ep == '/') ep++;
  180.     if (*ep == '/') ep++;
  181.     if (whichparts & kPartProtocol) {
  182.         sep= *ep; *ep= 0;
  183.         StrCat( newline, cp);
  184.         *ep= sep;
  185.         }
  186.     cp= ep;
  187.     
  188.     while (isspace(*cp)) cp++;
  189.     ep= cp;
  190.     while ( *ep && (OKAYCHAR(*ep, alphaPlusChars)) ) ep++;
  191.     //while (*ep && (isalnum(*ep) || *ep == '.')) ep++;
  192.     while (isspace(*ep)) ep++;
  193.     if (whichparts & kPartHost) {
  194.         sep= *ep; *ep= 0;
  195.         StrCat( newline, cp);        
  196.         *ep= sep;
  197.         }
  198.     cp= ep;  
  199.  
  200.     if (*cp == ':') {    // port num
  201.         ep = cp + 1;
  202.         while (isspace(*ep)) ep++;
  203.         while (isdigit(*ep)) ep++;
  204.         if (whichparts & kPartPort) {
  205.             sep= *ep; *ep= 0;
  206.             StrCat( newline, cp);        
  207.             *ep= sep;
  208.             }
  209.         cp= ep;  
  210.         }        
  211.     while (isspace(*cp)) cp++;
  212.  
  213.     if (*newline && *cp == '/') {
  214.         StrCat( newline, "/");        
  215.         }
  216.         
  217.     if (whichparts & kPartPath) {
  218.         if (*cp == '/') cp++;
  219.         StrCat( newline, cp);        
  220.         }
  221.  
  222.     MemFree( line);
  223.     return newline;
  224. }
  225.  
  226.  
  227.  
  228. Boolean DURL::ParseURL( DGopher* go, const char *url, long urlsize, Boolean verbatim)
  229. {
  230.   char *cp, *ep, *qp, sep, *line, *newurl;
  231.     short prot;
  232.     Boolean isLocalhost;
  233.     
  234.   if (!go || url == NULL || *url == '\0') return false;
  235.   if (!urlsize) urlsize= StrLen(url);
  236.  
  237.       // can we do this space check safely?
  238.   newurl= (char*)url;  while (isspace(*newurl)) { newurl++; urlsize--; }
  239.   ep= newurl + urlsize - 1;  while (isspace(*ep)) { ep--; urlsize--; }
  240.   
  241.     line= (char*) Nlm_MemNew(urlsize+1);
  242.     Nlm_MemCopy(line, newurl, urlsize);
  243.   line[urlsize]= 0;
  244.     prot= IsURL( line, newurl);
  245.     if (prot <= DGopher::kUnknownProt) {
  246.         MemFree( line);
  247.         return false;
  248.         }
  249.     else {
  250.         // need to drop "", '', <> or other delimiters from url end
  251.         // also filter out newlines, controls, and spaces unless "" or ''
  252.         {
  253.             cp= newurl;
  254.             if (cp>line) do { cp--; } while (cp>line && !isgraph(*cp));
  255.             ep= cp;
  256.             switch (*cp) {
  257.                 case '"': 
  258.                     newurl= cp+1;  
  259.                     do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='"');
  260.                     *ep= 0;
  261.                     break;
  262.                 case '\'':
  263.                     newurl= cp+1;  
  264.                     do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='\'');
  265.                     *ep= 0;
  266.                     break;
  267.                 case '<':
  268.                     newurl= cp+1; 
  269.                     if (verbatim)
  270.                         do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='>');
  271.                     else 
  272.                         do { if (isgraph(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='>');
  273.                     *ep= 0;
  274.                     break;
  275.                 default:
  276.                     newurl= cp;  
  277.                     if (verbatim)
  278.                         do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp);
  279.                     else 
  280.                         do { if (isgraph(*cp)) *ep++= *cp; cp++; } while (*cp);
  281.                     *ep= 0;
  282.                     break;
  283.                 }
  284.             }
  285.         go->StoreProtocol( prot);
  286.          go->StoreURL(newurl);
  287.         cp= StrChr(newurl+3,':');
  288.         cp++;
  289.         if (*cp == '/') cp++;
  290.         if (*cp == '/') cp++;
  291.         while (isspace(*cp)) cp++;
  292.         if (prot == DGopher::kSMTPprot) {
  293.             DecodeChars(cp);
  294.             go->fType= kMailType; // mailto gopher kind  
  295.             go->StorePath(cp);
  296.             MemFree( line);
  297.             return true;
  298.             }
  299.             
  300.         ep= cp;
  301.         while ( *ep && (OKAYCHAR(*ep, alphaPlusChars)) ) ep++;
  302.         //while (*ep && (isalnum(*ep) || *ep == '.' || *ep == '-')) ep++;
  303.  
  304.          while (isspace(*ep)) ep++;
  305.         sep= *ep; *ep= 0;
  306.         isLocalhost = (ep - cp < 2); // || StrICmp( cp, "localhost")==0 );
  307.         go->StoreHost( cp);    
  308.         *ep= sep;
  309.         cp= ep; // NO: +1;
  310.  
  311.         if (sep == ':') {    // port num
  312.             ep= ++cp;
  313.             while (isspace(*ep)) ep++;
  314.             while (isdigit(*ep)) ep++;
  315.             sep= *ep; *ep= 0;
  316.             go->StorePort( cp);    
  317.             *ep= sep;
  318.             cp= ep; //+1;
  319.             }        
  320.         if (sep == '/') ;
  321.         while (isspace(*cp)) cp++;
  322.  
  323.         qp= StrChr(cp, '?');
  324.         if (qp) {
  325.             *qp++= 0;
  326.             go->fQueryGiven= StrDup(qp);
  327.             }
  328.             
  329.         DecodeChars(cp);    // ???
  330.  
  331.         switch (prot) {
  332.             case DGopher::kGopherprot: // gopher://host.name:70/00/path/to/data
  333.                 if (*cp) cp++;
  334.                 if (*cp == 0) {
  335.                     go->fType= kTypeFolder;  
  336.                     go->StorePath(""); 
  337.                     }
  338.                 else {
  339.                     go->fType= *cp;  
  340.                     go->StorePath( cp+1); 
  341.                     }
  342.                 break;
  343.                 
  344.             case DGopher::kFTPprot: // file:///path:to:file
  345.             case DGopher::kFileprot: // file:///path:to:file
  346.                 if (*cp == '/') {          
  347.                         // this leading slash is artifact of silly url syntax !!
  348.                         // skip for all????? but sometimes (non-local) this is valid
  349. #if 1
  350.                     if (isLocalhost) cp++;
  351. #else
  352. #ifdef OS_VMS
  353.                     cp++; // vms, skip leading /
  354. #endif
  355. #ifdef OS_MAC
  356.                     cp++; // mac, skip leading /
  357. #endif
  358. #ifdef OS_DOS
  359.                     if (StrChr(cp,':')) cp++; // have "/C:\dos\path" form
  360.                     else *cp= '\\'; // have a "/dos\path" form
  361. #endif
  362. #endif
  363.                     }
  364.                 go->fType= kTypeFile;  // !! need ftp folder handling !?
  365.                 go->StorePath( cp);  
  366.                 break;
  367.  
  368.             case DGopher::kHTTPprot:    // http://host.name:80/path/to/data
  369.                 go->fType= kTypeHtml;  
  370.                 if (*cp == 0) go->StorePath( "/");
  371.                 else go->StorePath( cp);  
  372.                 break;
  373.  
  374.             case DGopher::kTelnetprot:
  375.                 go->fType= kTypeTelnet;  
  376.                 go->StorePath( cp);  
  377.                 break;
  378.             case DGopher::kTN3270prot:
  379.                 go->fType= kTypeTn3270;  
  380.                 go->StorePath( cp);  
  381.                 break;
  382.  
  383.             case DGopher::kFingerprot:
  384.             case DGopher::kWhoisprot:
  385.                 go->fType= kTypeQuery;  
  386.                 go->StorePath( cp);  
  387.                 break;
  388.             
  389.             case DGopher::kWAISprot: // ?? or need Folder type or Waisdir & WaisDoc types?
  390.             default:
  391.                 go->fType= kTypeFile;  
  392.                 go->StorePath( cp);  
  393.                 break;
  394.             }
  395.             
  396.                 // set a usable title !?
  397.         const char *name= go->GetPath();
  398.         if ( name == NULL || *name == 0 || StrCmp(name, "/") == 0) 
  399.             name= go->GetHost();
  400.         else 
  401.             name= gFileManager->FilenameFromPath(name);
  402.         if ( name && *name != 0 ) 
  403.             go->StoreName( (char*)name);  
  404.              
  405.         }
  406.     
  407.     MemFree( line);
  408.     return true;
  409. }
  410.