--- src/url.c.orig	Thu Sep 10 17:23:26 1998
+++ src/url.c	Fri Feb 11 23:41:42 2000
@@ -56,9 +56,9 @@
    encoding, and \033 for safe printing.  */
 
 #ifndef WINDOWS
-# define URL_UNSAFE " <>\"#%{}|\\^~[]`@:\033"
+# define URL_UNSAFE "& <>\"#%{}|\\^~[]`@:\033"
 #else  /* WINDOWS */
-# define URL_UNSAFE " <>\"%{}|\\^[]`\033"
+# define URL_UNSAFE "& <>\"%{}|\\^[]`\033"
 #endif /* WINDOWS */
 
 /* If S contains unsafe characters, free it and replace it with a
@@ -143,6 +143,7 @@
 static uerr_t parse_uname PARAMS ((const char *, char **, char **));
 static char *construct PARAMS ((const char *, const char *, int , int));
 static char *construct_relative PARAMS ((const char *, const char *));
+static char *construct_escape PARAMS ((const char *path));
 static char process_ftp_type PARAMS ((char *));
 
 
@@ -626,7 +627,7 @@
 str_url (const struct urlinfo *u, int hide)
 {
   char *res, *host, *user, *passwd, *proto_name, *dir, *file;
-  int i, l, ln, lu, lh, lp, lf, ld;
+  int i, l, ln, lu, lh, lp, lf, ld, offset;
 
   /* Look for the protocol name.  */
   for (i = 0; i < ARRAY_SIZE (sup_protos); i++)
@@ -637,7 +638,27 @@
   proto_name = sup_protos[i].name;
   host = CLEANDUP (u->host);
   dir = CLEANDUP (u->dir);
+  l = strlen(dir);
+  offset = 0;
+  for(i = 0, offset = 0; i < l ; i++, offset++) {
+    dir[offset] = dir[i];
+    if(strncasecmp(dir + i, "%26amp;", 7) == 0) {
+      i += 6;
+      offset += 2;
+    }
+  }
+  dir[offset] = 0;
   file = CLEANDUP (u->file);
+  l = strlen(file);
+  offset = 0;
+  for(i = 0, offset = 0; i < l ; i++, offset++) {
+    file[offset] = file[i];
+    if(strncasecmp(file + i, "%26amp;", 7) == 0) {
+      i += 6;
+      offset += 2;
+    }
+  }
+  file[offset] = 0;
   user = passwd = NULL;
   if (u->user)
     user = CLEANDUP (u->user);
@@ -1314,6 +1335,24 @@
 	  strncat (constr + i, sub, subsize);
 	  constr[i + subsize] = '\0';
 	} /* *sub == `/' */
+        {
+                int len, current;
+                len = strlen(constr);
+                current = 0;
+                for(i = 0 ; i < len ; i++, current++) {
+                        if(strncmp(constr + i, "/../", 4) == 0) {
+                                i += 4;
+				for(current--; current > 0 ; current--) {
+					if(constr[current] == '/') {
+						current++;
+						break;
+					}
+				}
+                        }
+                        constr[current] = constr[i];
+                }
+                constr[current] = 0;
+        }
     }
   else /* !no_proto */
     {
@@ -1369,6 +1408,7 @@
   FILE *fp;
   char *buf, *p, *p2;
   long size;
+  int i;
 
   logprintf (LOG_VERBOSE, _("Converting %s... "), file);
   /* Read from the file....  */
@@ -1401,23 +1441,46 @@
       /* If the URL already is relative or it is not to be converted
 	 for some other reason (e.g. because of not having been
 	 downloaded in the first place), skip it.  */
-      if ((l->flags & URELATIVE) || !(l->flags & UABS2REL))
-	{
-	  DEBUGP (("Skipping %s at position %d (flags %d).\n", l->url,
-		   l->pos, l->flags));
-	  continue;
-	}
+      if((l->flags & UABS2REL) == 0) {
+	DEBUGP (("Skipping %s at position %d (flags %d).\n", l->url,
+	   l->pos, l->flags));
+
+	continue;
+      }
       /* Else, reach the position of the offending URL, echoing
 	 everything up to it to the outfile.  */
       for (p2 = buf + l->pos; p < p2; p++)
 	putc (*p, fp);
-      if (l->flags & UABS2REL)
-	{
-	  char *newname = construct_relative (file, l->local_name);
-	  fprintf (fp, "%s", newname);
+      if(l->local_name != NULL) {
+	  char *newname;
+	  char *collect;
+
+	  newname = construct_relative (file, l->local_name);
+	  collect = construct_escape(newname);
+	  fprintf (fp, "%s", collect);
 	  DEBUGP (("ABS2REL: %s to %s at position %d in %s.\n",
 		   l->url, newname, l->pos, file));
 	  free (newname);
+	  free (collect);
+	} else {
+	  struct urlinfo *url = newurl();
+	  char *collect;
+	  char *newname;
+
+	  parseurl(l->url, url, 0);
+	  l->local_name = url_filename(url);
+	  newname = construct_escape(file);
+	  collect = construct_relative (newname, l->local_name);
+	  free(l->local_name);
+	  l->local_name = NULL;
+
+	  fprintf (fp, "%s", collect);
+	  DEBUGP (("ABS2REL: %s to %s at position %d in %s.\n",
+		   l->url, collect, l->pos, file));
+	  free (collect);
+	  free (newname);
+
+	  freeurl(url, 1);
 	}
       p += l->size;
     }
@@ -1429,6 +1492,32 @@
   fclose (fp);
   free (buf);
   logputs (LOG_VERBOSE, _("done.\n"));
+}
+
+/*
+ */
+static char * construct_escape(const char *path)
+{
+	unsigned int	length = strlen(path);
+	unsigned int	i, offset;
+	char *		string = NULL;
+
+	for(i = 0 ; path[i] != 0 ; i++) {
+		if(path[i] == '%') {
+			length += 2;
+		}
+	}
+	string = xmalloc(length + 1);
+	for(i = 0, offset = 0 ; path[i] != 0 ; i++, offset++) {
+		string[offset] = path[i];
+		if(path[i] == '%') {
+			string[offset + 1] = '2';
+			string[offset + 2] = '5';
+			offset += 2;
+		}
+	}
+	string[offset] = 0;
+	return string;
 }
 
 /* Construct and return a malloced copy of the relative link from two
