/** xurl.c - (c) 1994 Copyright by John R. Punin
 *
 * ASHE Editor of the HTML. 
 * 
 * This file has the routines to parse the url into a structure. 
 * These routines are based on the code written by students of the
 * topic WWW. 
 * 
 * John R. Punin      March -12 - 1994
 *
*/

#include "xhtml.h"
#include "xurl.h"

void 
initialize_url(GURL *url)
{
   url->ws_protocol=NULL;
   url->ws_user=NULL;
   url->ws_password=NULL;
   url->ws_host=NULL;
   url->ws_port=NULL;
   url->ws_path=NULL;
   url->ws_name=NULL;
   url->ws_rest=NULL;
   url->wc_jump=NULL;
}

int 
identify (char *furl)
{
  if (strncmp(furl,"ftp://",6) == 0)
      return(UFTP);
  if (strncmp(furl,"http://",7) == 0)
      return(UHTTP);
  if (strncmp(furl,"gopher://",9) == 0)
      return(UGOPHER);
  if (strncmp(furl,"mailto:",7) == 0)
      return(UMAILTO);
  if (strncmp(furl,"news:",5) == 0)
      return(UNEWS);
  if (strncmp(furl,"nntp://",7) == 0)
      return(UNNTP);
  if (strncmp(furl,"telnet://",9) == 0)
      return(UTELNET);
  if (strncmp(furl,"wais://",7) == 0)
      return(UWAIS);
  if (strncmp(furl,"file:",5) == 0)
      return(UFILE);
  if (strncmp(furl,"prospero://",11) == 0)
      return(UPROSPERO);

  return(0);
}

int 
reserved_char(char c)
{
   if((c == '=')||(c == ';')||(c == '/') || (c == '#') ||
      (c == '?') || (c == ':') || (c == ' '))
      return 1;
   return 0;
}
     


char * 
get_prot(char *furl, int code)
{
   switch(code)
   {
   case UFTP:
      return(&(furl[6]));
   case UHTTP:
      return(&(furl[7]));
   case UMAILTO:
      return(&(furl[7]));
   case UFILE:
      return(&(furl[5]));
   case UGOPHER:
      return(&(furl[9]));
   case UNEWS:
      return(&(furl[5]));
   case UTELNET:
      return(&(furl[9]));
   case UWAIS:
      return(&(furl[7]));
   case UNNTP:
      return(&(furl[7]));
   case UPROSPERO:
      return(&(furl[11]));
   }
   return NULL;
}

char *
get_login(char *furl, GURL *url)
{
   int i, len = strlen(furl);
   for(i=0;i<len;i++)
   {
      if((furl[i]=='@')||(furl[i]==':'))
	 break;
   }
   if(i<len)
   {
      url->ws_user = malloc(i+2);
      strncpy(url->ws_user, furl,i);
      url->ws_user[i]='\0';

      if(furl[i]==':')
      {
	 furl=&(furl[i+1]);
	 len = strlen(furl);
	 for(i = 0; i< len ; i++)
	 {
	    if(furl[i]=='@')
	       break;
	 }
	 if(i < len)
	 {
	    url->ws_password = malloc(i+2);
	    strncpy(url->ws_password, furl, i);
	    url->ws_password[i]='\0';
	 }
      }
      if(furl[i]!='@')
	 return NULL;
      else
	 return (&(furl[i+1])); 
   }
   return furl;
}

char *
get_host(char *furl, GURL *url)
{
   char *wp_furl1 = NULL;
   int wi_long, wi_long1,i;

   wi_long = 0;
   wi_long1 = -1;

   wi_long = strlen(furl);
   for (i = 0; i < wi_long; i++)
   {
      if ((furl[i] == ':')||(furl[i] == '/'))
      {
	 wi_long1 = i;
	 wp_furl1 = &furl[i];
	 break;
      }
   }

   if (wi_long1 != -1)
   {
      url->ws_host = malloc(wi_long1+2);
      strncpy(url->ws_host,furl,wi_long1);
      url->ws_host[wi_long1]='\0';
   }
   else
   {
      url->ws_host = malloc(wi_long);
      strcpy(url->ws_host,furl);
   }
   return(wp_furl1);
}

char *
get_port(char *furl, GURL *url)
{
   char *wp_furl1=NULL;
   int wi_long,wi_long1=-1,i;

   if(furl[0]!=':')
      return furl;

   furl = &(furl[1]);
   
   wi_long = strlen(furl);
   for (i = 0; i < wi_long; i++)
   {
      if (furl[i] == '/')
      {
	 wi_long1 = i;
	 wp_furl1 = &furl[i];
	 break;
      }
   }
   if (wi_long1 != -1)
   {
      url->ws_port = malloc(wi_long1+2);
      strncpy(url->ws_port,furl,wi_long1);
      url->ws_port[wi_long1]='\0';
   }
   else
   {
      url->ws_port = malloc(wi_long+2);
      strcpy(url->ws_port,furl);
   }
   return(wp_furl1);
}

char *
get_path(char *furl, GURL *url)
{ 
   char *wp_furl1=NULL;
   int wi_long,wi_long1=-1,i;

   if(furl[0]!='/')
      return furl;

   wi_long = strlen(furl);

   for (i = 0; i < wi_long; i++)
   {
      if ((furl[i] == '?')||(furl[i]==';'))
      {
	 wi_long1 = i;
	 wp_furl1 = &(furl[i]);
	 break;
      }
   }

   if (wi_long1 != -1)
   {
      url->ws_path = malloc(wi_long1+2);
      strncpy(url->ws_path,furl,wi_long1);
      url->ws_path[wi_long]='\0';
   }
   else
   {
      url->ws_path = malloc(wi_long+2);
      strcpy(url->ws_path,furl);
   }
   return(wp_furl1);
}

char *
get_ftp_rest(char *furl, GURL *url)
{
   if(furl[0]!=';')
      return furl;
   url->ws_rest = strdup(furl);
   return NULL;
}
char *
get_http_rest(char *furl, GURL *url)
{
   if(furl[0]!='?')
      return furl;
   url->ws_rest = strdup(furl);
   return NULL;
}
char *
get_mailto_rest(char *furl, GURL *url)
{
   int len,i;
   len = strlen(furl);
   for(i = 0; i<len; i++)
   {
      if(furl[i]=='@')
	 break;
   }
   if(i<len)
   {
      url->ws_rest = strdup(furl);
      return NULL;
   }
   return furl;
}
char *
get_news_rest(char *furl, GURL *url)
{
   int len, i;
   len = strlen(furl);
   for(i = 0; i<len; i++)
   {
      if(reserved_char(furl[i]))
	 break;
   }
   if(i==len)
   {
      url->ws_rest = strdup(furl);
      return NULL;
   }
   return furl;
}
void
get_rest(char *furl, GURL *url)
{
   url->ws_rest = strdup(furl);
}


int 
val_ftp(char *furl, GURL *url)
{
   url->ws_protocol = malloc(5);
   strcpy(url->ws_protocol,"ftp");
   url->protocol = UFTP;
   furl = get_prot(furl,UFTP);


   if(furl) furl = get_login(furl,url); /*  login */

   if(furl) furl = get_host(furl,url); /* host */
   if(furl) furl = get_port(furl,url);
   if(furl) furl = get_path(furl,url);
   if(furl) furl = get_ftp_rest(furl, url);

   if(furl)
      return ERROR_FTP;
   else
      return 0;
}
int 
val_http(char *furl, GURL *url)
{
   url->ws_protocol = malloc(6);
   strcpy(url->ws_protocol,"http");
   url->protocol = UHTTP;
  furl = get_prot(furl,UHTTP);
  if(furl) furl = get_host(furl,url);
  if(furl) furl = get_port(furl,url);
  if(furl) furl = get_path(furl,url);
  if(furl) furl = get_http_rest(furl,url);

   if(furl)
      return ERROR_HTTP;
   else
      return 0;
}
int 
val_mailto(char *furl, GURL *url)
{
   url->ws_protocol = malloc(8);
   strcpy(url->ws_protocol,"mailto");
   url->protocol = UMAILTO;
   furl = get_prot(furl,UMAILTO);
   furl = get_mailto_rest(furl,url);

   if (furl)
      return(ERROR_MAILTO);
   else
      return 0;
}
int 
val_file(char *furl, GURL *url)
{
   url->ws_protocol = malloc(6);
   strcpy(url->ws_protocol,"file");
   url->protocol = UFILE;
   furl = get_prot(furl,UFILE);

   if(furl && strlen(furl) > 3)
   {
      if(furl[0]=='/' && furl[1]=='/')
	 furl = get_host(&(furl[2]),url);
   }

   if(furl) furl = get_path(furl,url);
   if(furl) furl = get_ftp_rest(furl,url); /* ftp equivalent */

   if (furl)
      return(ERROR_FILE);
   else
      return 0;
   
}
int
val_gopher(char *furl, GURL *url)
{
   url->ws_protocol = malloc(8);
   strcpy(url->ws_protocol,"gopher");
   url->protocol = UGOPHER;
   furl = get_prot(furl,UGOPHER);
   if(furl) furl = get_host(furl,url);
   if(furl) furl = get_path(furl,url);
   if (furl)
      return(ERROR_GOPHER);
   else
      return 0;
   
}
int
val_news(char *furl, GURL *url)
{
   url->ws_protocol = malloc(6);
   strcpy(url->ws_protocol,"news");
   url->protocol = UNEWS;
   furl = get_prot(furl,UNEWS);
   if(furl) furl = get_news_rest(furl,url);
   if (furl)
      return(ERROR_NEWS);
   else
      return 0;
}
int
val_telnet(char *furl, GURL *url)
{
   url->ws_protocol = malloc(8);
   strcpy(url->ws_protocol,"telnet");
   url->protocol = UTELNET;
   furl = get_prot(furl,UTELNET);
   if(furl) furl = get_login(furl,url);  /*  login */
   if(furl) furl = get_host(furl,url); /* host */
   if(furl) furl = get_port(furl,url);
   if (furl)
      return(ERROR_TELNET);
   else
      return 0;
   
   

}
int
val_wais(char *furl, GURL *url)
{
   url->ws_protocol = malloc(6);
   strcpy(url->ws_protocol,"wais");
   url->protocol = UWAIS;
   furl = get_prot(furl,UWAIS);
   if(furl) furl = get_host(furl,url); /* host */
   if(furl) furl = get_port(furl,url);
   if(furl) furl = get_path(furl,url);
   if(furl) furl = get_http_rest(furl, url);

   if (furl)
      return(ERROR_WAIS);
   else
      return 0;
   
}
int
val_prospero(char *furl, GURL *url)
{
   url->ws_protocol = malloc(10);
   strcpy(url->ws_protocol,"prospero");
   url->protocol = UPROSPERO;
   furl = get_prot(furl,UPROSPERO);
   if(furl) furl = get_host(furl,url); /* host */
   if(furl) furl = get_port(furl,url);
   if(furl) furl = get_path(furl,url);
   if (furl)
      return(ERROR_PROSPERO);
   else
      return 0;
   
}
int
val_nntp(char *furl, GURL *url)
{
   url->ws_protocol = malloc(6);
   strcpy(url->ws_protocol,"nntp");
   url->protocol = UNNTP;
   furl = get_prot(furl,UNNTP);
   if(furl) furl = get_news_rest(furl,url);
   if (furl)
      return(ERROR_NNTP);
   else
      return 0;
   
}
int
val_unknown(char *furl, GURL *url)
{
   int i,len=strlen(furl);

   if(len==0)
      return ERROR_FILE;

   for(i=0;i<len;i++)
   {
      if(furl[i]==':')
	 break;
   }
   if(i<len)
   {
      url->ws_protocol = malloc(i+2);
      strncpy(url->ws_protocol,furl,i);
      url->protocol = UNKNOWN;
      url->ws_protocol[i]='\0';
      get_rest(&(furl[i+1]),url);
   }
   else
   {
      url->ws_protocol = malloc(6);
      strcpy(url->ws_protocol,"file");
      url->protocol = UFILE;
      furl = get_path(furl,url);
      if(furl) get_rest(furl,url);
   }
   return 0;
}
int 
recognize_url(char *furl,GURL *url)
{
   int error = 0;
   switch (identify(furl))
   {
   case  UFTP: /* Ftp Protocol      */
      error = val_ftp(furl,url);
      break;
   case  UHTTP: /* HTTP Protocol     */
      error = val_http(furl,url);
      break;
   case  UGOPHER: /* Gopher Protocol  */
      error = val_gopher(furl,url);
      break;
   case  UMAILTO: /* Mailto Protocol   */
      error = val_mailto(furl,url);
      break;
   case  UNEWS: /* News Protocol     */
      error = val_news(furl,url);
      break;
   case  UNNTP: /* NNTP Protocol     */
      error = val_nntp(furl,url);
      break;
   case  UTELNET: /* Telnet Protocol   */
      error = val_telnet(furl,url);
      break;
   case  UWAIS: /* Wais Protocol     */
      error = val_wais(furl,url);
      break;
   case UFILE: /* File Protocol     */
      error = val_file(furl,url);
      break;
   case UPROSPERO: /* Prospero Protocol */
      error = val_prospero(furl,url);
      break;
   default: /* Unknown Protocol  */
      error = val_unknown(furl,url);;
      break;
   }
   return error;
}
void 
print_url(GURL *url)
{
  printf("\nurl->ws_protocol: %s",url->ws_protocol);
  printf("\nurl->ws_user  : %s",url->ws_user);
  printf("\nurl->ws_password : %s",url->ws_password);
  printf("\nurl->ws_host     : %s",url->ws_host);
  printf("\nurl->ws_port     : %s",url->ws_port);
  printf("\nurl->ws_path     : %s",url->ws_path);
  printf("\nurl->ws_name     : %s",url->ws_name);
  printf("\nurl->ws_rest    : %s\n",url->ws_rest);
}
void 
delete_url(GURL *url)
{
   if(url->ws_protocol) 
      free(url->ws_protocol);
   if(url->ws_user) 
      free(url->ws_user);
   if(url->ws_password) 
      free(url->ws_password);
   if(url->ws_host) 
      free(url->ws_host);
   if(url->ws_port) 
      free(url->ws_port);
   if(url->ws_path) 
      free(url->ws_path);
   if(url->ws_name) 
      free(url->ws_name);
   if(url->ws_rest)
      free(url->ws_rest);
}

char * 
suppress_dots(char *file)
{
   int len = strlen(file);
   int i=0;
   int find=0, sind=0, tind=0;
   i=1;
   while(1)
   {
      if(file[0]!='/')
	 return NULL;
      if(len < 4)
	 return (strdup(file));
      if((file[1]=='.')&&(file[2]=='.')&&(file[3]=='/'))
	 return NULL;

      while(file[i]!='/'&& i< len)
	 i++;
      if(i==len)
	 return(strdup(file));
   
      sind = i;
      if((file[sind+1]=='.')&&(file[sind+2]=='.')&&(file[sind+3]=='/'))
      {
	 char *tstr = strdup(file);
	 tind = sind + 4;
	 strcpy(&(file[find+1]),&(tstr[tind]));
	 free(tstr);
	 find = 0; i=0;
	 len = strlen(file);
      }
      else
      {
	 i=sind+1;
	 find = sind;
      }
   }
}	 

/* Get a directory from a File name */
char *
getdirectory (char *fname)
{
   int i,j,len=strlen(fname);
   char *path=NULL;
   if(len!=0)
   {
      for(i=len-1;i>=0;i--)
	 if(fname[i]=='/')
	    break;  
      if(i!=0)
      {
	 path = XtMalloc(len+2);
	 for(j=0;j<=i;j++)
	    path[j]=fname[j];
	 path[j]='\0';
      }
   }
   return(path);
}

String
binding_relative_url(String url_rel,HTMLED *he,String directory,int *isfile)
{
   
   String href=NULL;
   GURL *surl = (GURL *)malloc(sizeof(GURL));
   int code; 

   initialize_url(surl);
   code = recognize_url(url_rel,surl);
   if((code == 0) && !strcmp(surl->ws_protocol,"file"))
   {
      /* We should check if url is absolute or not */ /* Not implemented */
      if(url_rel[0]!='/')
      {
	 href = XtMalloc(strlen(directory)+strlen(url_rel)+5);
	 sprintf(href,"%s%s",directory,url_rel);
      }
      else if(url_rel[0]=='/')
      {
	 href = strdup(url_rel);
      }
   }
   else
   {
      href = strdup(url_rel);
   }
   *isfile = surl->protocol; /* Used  Protocol */
   delete_url(surl);
   free(surl);

   return href;
}

char *
get_url_file(HTMLED *he,char *url_rel,String directory,int *isfile)
{
   String oref,href,name,fhref;

   oref = binding_relative_url(url_rel,he,directory,isfile);
   strip_href(oref,&href,&name);
   if(oref)
      XtFree(oref);
   if(name)
      XtFree(name);
   fhref = suppress_dots(href);
   if(fhref)
   {
      XtFree(href);
      return fhref;
   }
   else
      return href;
}

void 
strip_href(char *ohref,char **href, char**name)
{
   int len=0;
   int i;
   *href = NULL;
   *name = NULL;
   if(ohref!=NULL)
      len = strlen(ohref);

   if(len!=0)
   {
      *href = XtMalloc(len+2);
      *name = XtMalloc(len+2);
      (*name)[0]='\0';
      for(i=len-1;i>=0;i--)
	 if(ohref[i]=='#')
	    break;
      strcpy(*href,ohref);
      if((i>=0)||((i==0)&&((*href)[0]=='#')))
      {
	 (*href)[i]='\0';
	 strcpy(*name,&(ohref[i+1]));
      }
   }
}      




