diff -ur whois-4.6.9-hiding/whois.c whois-4.6.9/whois.c
--- whois-4.6.9-hiding/whois.c	2003-12-28 22:01:12.000000000 -0800
+++ whois-4.6.9/whois.c	2003-12-28 23:12:13.000000000 -0800
@@ -65,8 +65,10 @@
 int main(int argc, char *argv[])
 {
     int ch, nopar = 0;
-    const char *server = NULL, *port = NULL;
-    char *p, *q, *qstring, fstring[64] = "\0";
+    char *server = NULL, *port = NULL;
+    char *referral_server = NULL;
+    char *p, *qstring, fstring[64] = "\0";
+    int depth = 0;
 
 #ifdef ENABLE_NLS
     setlocale(LC_ALL, "");
@@ -92,12 +94,7 @@
 	/* program flags */
 	switch (ch) {
 	case 'h':
-	    server = q = malloc(strlen(optarg) + 1);
-	    if (!q) err_sys("malloc");
-	    for (p = optarg; *p && *p != ':'; *q++ = tolower(*p++));
-	    if (*p == ':')
-		port = p + 1;
-	    *q = '\0';
+	    split_server_port(optarg,&server,&port);
 	    break;
 	case 'V':
 	    client_tag = optarg;
@@ -105,7 +102,8 @@
 	    hide_discl = HIDE_UNSTARTED;	/* enable disclaimers hiding */
 	    break;
 	case 'p':
-	    port = optarg;
+	    port = strdup(optarg);
+	    if (!port) err_sys("strdup");
 	    break;
 	case 2:
 	    verb = 1;
@@ -149,14 +147,21 @@
     }
 
     /* -v or -t has been used */
-    if (!server && !*qstring)
-	server = "whois.ripe.net";
+    if (!server && !*qstring) {
+	server = strdup("whois.ripe.net");
+	if (!server) err_sys("strdup");
+    }
 
 #ifdef CONFIG_FILE
     if (!server) {
-	server = match_config_file(qstring);
-	if (verb && server)
+	const char * match_server;
+	if ((match_server = match_config_file(qstring))!=NULL) {
+	    server = strdup(match_server);
+	    if (!server) err_sys("strdup");
+	}
+	if (verb && server) {
 	    printf(_("Using server %s.\n"), server);
+	}
     }
 #endif
 
@@ -171,16 +176,79 @@
 	tmp = normalize_domain(qstring);
 	free(qstring);
 	qstring = tmp;
-	server = whichwhois(qstring);
+	server = strdup(whichwhois(qstring));
+	if (!server) err_sys("strdup");
+    }
+
+    while ((referral_server=handle_query(server,port,qstring,fstring))!=NULL) {
+	char *new_server = NULL, *new_port = NULL;
+
+	split_server_port(referral_server,&new_server,&new_port);
+
+	if (new_port) {
+	    if (*new_port!='\0') {
+		if (port) free(port);
+		port=new_port;
+	    }
+	    else {
+		free(new_port);
+	    }
+	}
+	if (new_server) {
+	    if (*new_server!='\0') {
+		if (server) free(server);
+		server=new_server;
+	    }
+	    else {
+		free(new_server);
+	    }
+	}
+
+	depth++;
+	if (depth > 10) {
+	    /* XXX add a translatable warning here? */
+	    break; /* this seems too deep: stop */
+	}
+    }
+
+    if (server) free(server);
+    if (port) free(port);
+    exit(0);
+}
+
+void split_server_port(const char *input, char ** server, char ** port) {
+    char *q, *p;
+
+    if (!server || !port || !input) return;
+
+    *server = q = strdup(input);
+    if (!q) err_sys("strdup");
+
+    for (p = q; *p && *p != ':'; *q++ = tolower(*p++));
+    if (*p == ':') {
+	*port = strdup(p + 1);
+	if (!*port) err_sys("strdup");
+    }
+    *q = '\0';
+}
+
+/* returns NULL if no referral, otherwise, the resulting string
+ * must be free'd by the caller
+ */
+char * handle_query(const char * server, const char * port,
+		    const char * qstring, const char * fstring) {
+	char *referral_server = NULL;
+        char *p;
 
-retry:
 	switch (server[0]) {
 	    case 0:
-		if (!(server = getenv("WHOIS_SERVER")))
-		    server = DEFAULTSERVER;
+		if (!(server = getenv("WHOIS_SERVER"))) {
+		    referral_server = strdup(DEFAULTSERVER);
+		    if (!referral_server) err_sys("strdup");
+		}
 		if (verb)
-		    printf(_("Using default server %s.\n"), server);
-		break;
+		    printf(_("Using default server %s.\n"), referral_server);
+		return referral_server;
 	    case 1:
 		puts(_("This TLD has no whois server, but you can access the "
 			    "whois database at"));
@@ -194,35 +262,35 @@
 		if (verb)
 		    puts(_("Connecting to whois.crsnic.net."));
 		sockfd = openconn("whois.crsnic.net", NULL);
-		server = query_crsnic(sockfd, qstring);
+		referral_server = query_crsnic(sockfd, qstring);
 		close(sockfd);
-		if (!server)
+		if (!referral_server)
 		    exit(0);
-		printf(_("\nFound a referral to %s.\n\n"), server);
+		printf(_("\nFound a referral to %s.\n\n"), referral_server);
 		alarm(60);
-		break;
+		return referral_server;
 	    case 9:
 		if (verb)
 		    puts(_("Connecting to whois.nic.cc."));
 		sockfd = openconn("whois.nic.cc", NULL);
-		server = query_crsnic(sockfd, qstring);
+		referral_server = query_crsnic(sockfd, qstring);
 		close(sockfd);
-		if (!server)
+		if (!referral_server)
 		    exit(0);
-		printf(_("\nFound a referral to %s.\n\n"), server);
+		printf(_("\nFound a referral to %s.\n\n"), referral_server);
 		alarm(60);
-		break;
+		return referral_server;
 	    case 7:
 		if (verb)
 		    puts(_("Connecting to whois.publicinterestregistry.net."));
 		sockfd = openconn("whois.publicinterestregistry.net", NULL);
-		server = query_pir(sockfd, qstring);
+		referral_server = query_pir(sockfd, qstring);
 		close(sockfd);
-		if (!server)
+		if (!referral_server)
 		    exit(0);
-		printf(_("\nFound referral to %s.\n\n"), server);
+		printf(_("\nFound referral to %s.\n\n"), referral_server);
 		alarm(60);
-		break;
+		return referral_server;
 	    case 5:
 		puts(_("No whois server is known for this kind of object."));
 		exit(0);
@@ -232,23 +300,16 @@
 	    case 0x0A:
 		{
 		char *tmp6 = convert_6to4(qstring);
-		free(qstring);
-		qstring = tmp6;
-		printf(_("\nQuerying for the IPv4 endpoint %s of a 6to4 IPv6 address.\n\n"), qstring);
-		server = whichwhois(qstring);
-		/*
-		 * This code sucks enough that I can afford to use goto...
-		 * Some day whichwhois() and queryformat() will be merged
-		 * and will return a struct with status code, server name
-		 * and query string.
-		 */
-		goto retry;
+		printf(_("\nQuerying for the IPv4 endpoint %s of a 6to4 IPv6 address.\n\n"), tmp6);
+		referral_server= strdup(whichwhois(tmp6));
+		free(tmp6);
+		if (!referral_server) err_sys("strdup");
+		return referral_server;
 		}
 	    default:
 		if (verb)
 		    printf(_("Using server %s.\n"), server);
 	}
-    }
 
     if (getenv("WHOIS_HIDE"))
 	hide_discl = HIDE_UNSTARTED;
@@ -265,9 +326,7 @@
      * This will help people who run whois ... | less
      */
     alarm(0);
-    do_query(sockfd, p);
-
-    exit(0);
+    return do_query(sockfd, p);
 }
 
 #ifdef CONFIG_FILE
@@ -509,12 +568,13 @@
     return (*hiding > HIDE_UNSTARTED);
 }
 
-void do_query(const int sock, const char *query)
+char * do_query(const int sock, const char *query)
 {
     char buf[2000], *p;
     FILE *fi;
     int i = 0;
     int hide = hide_discl;
+    char * referral_server=NULL;
 
     fi = fdopen(sock, "r");
     if (write(sock, query, strlen(query)) < 0)
@@ -543,6 +603,20 @@
 	    }
 	}
 #endif
+	if (!referral_server && strncmp(buf, "ReferralServer:", 15) == 0) {
+	    char * url;
+
+	    if ((url=strstr(buf,"://"))!=NULL) {
+		referral_server = strdup(url+3);
+		if (!referral_server) err_sys("strdup");
+		if ((url=strchr(referral_server,'/'))!=NULL) {
+		    *url='\0';
+		}
+		if (verb)
+		    printf(_("Detected referral to %s.\n"), referral_server);
+	    }
+	}
+
 	for (p = buf; *p && *p != '\r' && *p != '\n'; p++);
 	*p = '\0';
 	fprintf(stdout, "%s\n", buf);
@@ -551,12 +625,13 @@
 	err_sys("fgets");
     fclose(fi);
 
-    if (hide == 1)
+    if (hide > HIDE_UNSTARTED)
 	err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
 		   "Please upgrade this program.\n"));
+    return referral_server;
 }
 
-const char *query_crsnic(const int sock, const char *query)
+char *query_crsnic(const int sock, const char *query)
 {
     char *temp, buf[2000], *ret = NULL;
     FILE *fi;
@@ -600,7 +675,7 @@
     return ret;
 }
 
-const char *query_pir(const int sock, const char *query)
+char *query_pir(const int sock, const char *query)
 {
     char *temp, buf[2000], *ret = NULL;
     FILE *fi;
@@ -745,14 +820,14 @@
 char *convert_6to4(const char *s)
 {
     unsigned int a, b;
-    char *new = malloc(sizeof("255.255.255.255"));
-    if (!new) err_sys("malloc");
+    char *new_ip = malloc(sizeof("255.255.255.255"));
+    if (!new_ip) err_sys("malloc");
 
     if (sscanf(s, "2002:%x:%x:", &a, &b) != 2)
 	return (char *) "0.0.0.0";
 
-    sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
-    return new;
+    sprintf(new_ip, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
+    return new_ip;
 }
 
 unsigned long myinet_aton(const char *s)
diff -ur whois-4.6.9-hiding/whois.h whois-4.6.9/whois.h
--- whois-4.6.9-hiding/whois.h	2003-12-01 09:21:59.000000000 -0800
+++ whois-4.6.9/whois.h	2003-12-28 23:06:00.000000000 -0800
@@ -10,9 +10,9 @@
 const char *match_config_file(const char *);
 const char *whereas(const unsigned short);
 char *queryformat(const char *, const char *, const char *);
-void do_query(const int, const char *);
-const char *query_crsnic(const int, const char *);
-const char *query_pir(const int, const char *);
+char *do_query(const int, const char *);
+char *query_crsnic(const int, const char *);
+char *query_pir(const int, const char *);
 int openconn(const char *, const char *);
 void usage(void);
 void alarm_handler(int);
@@ -23,6 +23,9 @@
 int domfind(const char *, const char *[]);
 char *normalize_domain(const char *);
 char *convert_6to4(const char *);
+char *handle_query(const char * server, const char * port,
+		   const char * qstring, const char * fstring);
+void split_server_port(const char *input, char ** server, char ** port);
 
 void err_quit(const char *,...);
 void err_sys(const char *,...);
