--- http.c	Fri Jun  1 15:07:48 2001
+++ /home/hadara/http.c	Thu Nov 29 15:05:51 2001
@@ -33,6 +33,8 @@
 #include "mpg123.h"
 #include "libxmms/util.h"
 
+#define INET6
+
 #define min(x,y) ((x)<(y)?(x):(y))
 #define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
 #define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
@@ -43,8 +45,8 @@
 #undef DEBUG_UDP
 
 /* Static udp channel functions */
-static int udp_establish_listener (gint *sock);
-static int udp_check_for_data(gint sock);
+static int udp_establish_listener (gint *sock, char is_ipv6);
+static int udp_check_for_data(gint sock, char is_ipv6);
 
 extern gint mpg123_bitrate, mpg123_frequency, mpg123_stereo;
 extern gboolean mpg123_stereo;
@@ -329,8 +331,12 @@
 	gboolean redirect;
 	int udp_sock = 0;
 	fd_set set;
+	char is_ipv6 = 0;
 	struct hostent *hp;
-	struct sockaddr_in address;
+        struct sockaddr_in address;
+#ifdef INET6
+        struct sockaddr_in6 address6;
+#endif
 	struct timeval tv;
 
 	url = (gchar *) arg;
@@ -352,16 +358,21 @@
 		chost = mpg123_cfg.use_proxy ? mpg123_cfg.proxy_host : host;
 		cport = mpg123_cfg.use_proxy ? mpg123_cfg.proxy_port : port;
 
-		sock = socket(AF_INET, SOCK_STREAM, 0);
-		fcntl(sock, F_SETFL, O_NONBLOCK);
-		address.sin_family = AF_INET;
-
 		status = g_strdup_printf(_("LOOKING UP %s"), chost);
 		mpg123_ip.set_info_text(status);
 		g_free(status);
 
-		if (!(hp = gethostbyname(chost)))
-		{
+		hp = gethostbyname(chost);
+
+#ifdef INET6
+		if(!hp)
+			if((hp = gethostbyname2(chost, AF_INET6))!=NULL) {
+				address6.sin6_family = AF_INET6;		
+				address6.sin6_port = g_htons(cport);
+				is_ipv6 = 1;
+			}
+#endif
+		if(hp == NULL) {
 			status = g_strdup_printf(_("Couldn't look up host %s"), chost);
 			show_error_message(status);
 			g_free(status);
@@ -369,15 +380,47 @@
 			mpg123_ip.set_info_text(NULL);
 			eof = TRUE;
 		}
+		else {
+#ifdef INET6
+			if(address6.sin6_family == AF_INET6) {
+				sock = socket(AF_INET6, SOCK_STREAM, 0);
+				fcntl(sock, F_SETFL, O_NONBLOCK);
+				address6.sin6_family = AF_INET6;
+				memcpy(&address6.sin6_addr, hp->h_addr, hp->h_length);
+			}
+			else {
+#endif
+				sock = socket(AF_INET, SOCK_STREAM, 0);
+				fcntl(sock, F_SETFL, O_NONBLOCK);
+				address.sin_family = AF_INET;
+				memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list),
+					sizeof(address.sin_addr.s_addr));
+				address.sin_port = g_htons(cport);	
+#ifdef INET6
+			}
+#endif
+		}
 
 		if (!eof)
 		{
-			memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
-			address.sin_port = g_htons(cport);
-
 			status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
 			mpg123_ip.set_info_text(status);
 			g_free(status);
+#ifdef INET6
+			if(address6.sin6_family == AF_INET6) {
+				if(connect(sock,(struct sockaddr*)&address6,sizeof(struct sockaddr_in6))==-1){
+					if (errno != EINPROGRESS) {
+						status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
+						show_error_message(status);
+						g_free(status);
+
+						mpg123_ip.set_info_text(NULL);
+						eof = TRUE;
+					}
+				}	
+			}
+			else
+#endif
 			if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
 			{
 				if (errno != EINPROGRESS)
@@ -389,7 +432,8 @@
 					mpg123_ip.set_info_text(NULL);
 					eof = TRUE;
 				}
-			}
+                        }
+
 			while (going)
 			{
 				tv.tv_sec = 0;
@@ -422,7 +466,7 @@
 
 				if (mpg123_cfg.use_udp_channel)
 				{
-					udp_port = udp_establish_listener (&udp_sock);
+					udp_port = udp_establish_listener (&udp_sock,is_ipv6);
 					if (udp_port > 0) 
 						sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port);
 					else
@@ -630,7 +674,7 @@
 			xmms_usleep(10000);
 
 		if (mpg123_cfg.use_udp_channel && udp_sock != 0)
-			if (udp_check_for_data(udp_sock) < 0)
+			if (udp_check_for_data(udp_sock, is_ipv6) < 0)
 			{
 				g_message("closing udp");
 				close(udp_sock);
@@ -685,33 +729,59 @@
 /* Start UDP Channel specific stuff */
 
 /* Find a good local udp port and bind udp_sock to it, return the port */
-static int udp_establish_listener (gint *sock)
+static int udp_establish_listener (gint *sock, char is_ipv6)
 {
-	struct sockaddr_in sin;
-	socklen_t sinlen = sizeof (struct sockaddr_in);
+    struct sockaddr_in sin;
+    socklen_t sinlen = sizeof (struct sockaddr_in);
+#ifdef INET6
+    struct sockaddr_in6 sin6;
+    socklen_t sinlen6 = sizeof (struct sockaddr_in6);
+#endif
 	
 #ifdef DEBUG_UDP
 	fprintf (stderr,"Establishing udp listener\n");
 #endif
 	
-	if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
-	{
+#ifdef INET6
+	if(is_ipv6 == 1) {
+		if ((*sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+			g_log(NULL, G_LOG_LEVEL_CRITICAL,
+				"udp_establish_listener(): unable to create socket");
+			return -1;
+		}
+        	memset(&sin6, 0, sinlen6);
+        	sin6.sin6_family = AF_INET6;
+        	memset(&sin6.sin6_addr, 0, sizeof(sin6.sin6_addr));
+	}
+	else
+#endif	
+        if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
 		g_log(NULL, G_LOG_LEVEL_CRITICAL,
-		      "udp_establish_listener(): unable to create socket");
+	      		"udp_establish_listener(): unable to create socket");
 		return -1;
-	}
-
+       	}
 	memset(&sin, 0, sinlen);
 	sin.sin_family = AF_INET;
 	sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
 			
-	if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
-	{
-		g_log(NULL, G_LOG_LEVEL_CRITICAL,
-		      "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
-		close(*sock);
-		return -1;
+#ifdef INET6
+	if(is_ipv6 == 1) {
+		if (bind(*sock, (struct sockaddr *)&sin6, sinlen6) < 0){
+			g_log(NULL, G_LOG_LEVEL_CRITICAL,
+		      		"udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
+			close(*sock);
+			return -1;
+		}
+	}
+	else
+#endif
+	if(bind(*sock, (struct sockaddr *)&sin, sinlen) < 0){
+			g_log(NULL, G_LOG_LEVEL_CRITICAL,
+				"udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
+			close(*sock);
+			return(-1);
 	}
+
 	if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
 	{
 		g_log(NULL, G_LOG_LEVEL_CRITICAL,
@@ -720,43 +790,86 @@
 		return -1;
 	}
 
+#ifdef INET6
+	if(is_ipv6 == 1) {
+		memset(&sin6, 0, sinlen6);
+		if (getsockname(*sock, (struct sockaddr *)&sin6, &sinlen6) < 0){
+			g_log(NULL, G_LOG_LEVEL_CRITICAL,
+				"udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
+			close(*sock);
+			return(-1);
+		}
+	}
+	else {
+#endif
 	memset(&sin, 0, sinlen);
-	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
-	{
+	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0){
 		g_log(NULL, G_LOG_LEVEL_CRITICAL,
 		      "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
 		close(*sock);
 		return -1;
 	}
+#ifdef INET6
+	}
 
+	if(is_ipv6 == 1) {
 #ifdef DEBUG_UDP
-	fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+		fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
+#endif
+        	return g_ntohs(sin6.sin6_port);
+	}
+	else {
+#endif
+
+#ifdef DEBUG_UDP
+		fprintf (stderr,"Listening on local %s:%d\n",inet_ntoa(sin.sin6_addr), g_ntohs(sin.sin6_port));
+#endif
+        	return g_ntohs(sin.sin_port);
+#ifdef INET6
+	}
 #endif
-	
-	return g_ntohs(sin.sin_port);
 }
 
-static int udp_check_for_data(int sock)
+static int udp_check_for_data(int sock, char is_ipv6)
 {
 	char buf[1025], **lines;
 	char *valptr;
 	gchar *title;
 	gint len, i;
-	struct sockaddr_in from;
+#ifdef INET6
+	struct sockaddr_in6 from6;
+	socklen_t fromlen6;
+#endif
+        struct sockaddr_in from;
 	socklen_t fromlen;
 
-	fromlen = sizeof(struct sockaddr_in);
+#ifdef INET6
+	fromlen6 = sizeof(struct sockaddr_in6);
+#endif
+        fromlen = sizeof(struct sockaddr_in);
 	
-	if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
-	{
-		if (errno != EAGAIN)
-		{
+#ifdef INET6
+	if(is_ipv6 == 1) {
+		if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from6, &fromlen6)) < 0){
+			if (errno != EAGAIN) {
+				g_log(NULL, G_LOG_LEVEL_CRITICAL,
+			      		"udp_read_data(): Error reading from socket: %s", strerror(errno));
+				return -1;
+			}
+			return 0;
+		}
+	}
+	else
+#endif
+	if((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0){
+		if (errno != EAGAIN) {
 			g_log(NULL, G_LOG_LEVEL_CRITICAL,
-			      "udp_read_data(): Error reading from socket: %s", strerror(errno));
+				"udp_read_data(): Error reading from socket: %s", strerror(errno));
 			return -1;
-		}
 		return 0;
+		}
 	}
+
 	buf[len] = '\0';
 #ifdef DEBUG_UDP
 	fprintf (stderr,"Received: [%s]\n", buf);
@@ -821,8 +934,16 @@
 		{
 			gchar obuf[60];
 			sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr));
-			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
-			{
+#ifdef INET6
+			if(is_ipv6 == 1) {
+				if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from6, fromlen6) < 0){
+					g_log(NULL, G_LOG_LEVEL_CRITICAL,
+						"udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
+				}
+			}
+			else
+#endif
+			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0){
 				g_log(NULL, G_LOG_LEVEL_CRITICAL,
 				      "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
 			}
