Blame src/plugin_xmms/http.c

Packit Service 065837
/*  XMMS - Cross-platform multimedia player
Packit Service 065837
 *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
Packit Service 065837
 *
Packit Service 065837
 *  This program is free software; you can redistribute it and/or modify
Packit Service 065837
 *  it under the terms of the GNU General Public License as published by
Packit Service 065837
 *  the Free Software Foundation; either version 2 of the License, or
Packit Service 065837
 *  (at your option) any later version.
Packit Service 065837
 *
Packit Service 065837
 *  This program is distributed in the hope that it will be useful,
Packit Service 065837
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 065837
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 065837
 *  GNU General Public License for more details.
Packit Service 065837
 *
Packit Service 065837
 *  You should have received a copy of the GNU General Public License along
Packit Service 065837
 *  with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 065837
 *  with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 065837
 */
Packit Service 065837
/* modified for FLAC support by Steven Richman (2003) */
Packit Service 065837
Packit Service 065837
#ifdef HAVE_CONFIG_H
Packit Service 065837
#include "config.h"
Packit Service 065837
#endif
Packit Service 065837
Packit Service 065837
#include "plugin.h"
Packit Service 065837
Packit Service 065837
#include <sys/types.h>
Packit Service 065837
#include <sys/socket.h>
Packit Service 065837
#include <sys/time.h>
Packit Service 065837
#include <netinet/in.h>
Packit Service 065837
#include <arpa/inet.h>
Packit Service 065837
#include <netdb.h>
Packit Service 065837
#include <glib.h>
Packit Service 065837
#include <string.h>
Packit Service 065837
#include <fcntl.h>
Packit Service 065837
#include <unistd.h>
Packit Service 065837
#include <errno.h>
Packit Service 065837
#include <stdio.h>
Packit Service 065837
#include <stdlib.h>
Packit Service 065837
#include <inttypes.h>
Packit Service 065837
Packit Service 065837
#include <pthread.h>
Packit Service 065837
Packit Service 065837
#include <xmms/util.h>
Packit Service 065837
#include <xmms/plugin.h>
Packit Service 065837
Packit Service 065837
#include "FLAC/format.h"
Packit Service 065837
#include "configure.h"
Packit Service 065837
#include "locale_hack.h"
Packit Service 065837
Packit Service 065837
/* on FreeBSD we get socklen_t from <sys/socket.h> */
Packit Service 065837
#if (!defined HAVE_SOCKLEN_T) && !defined(__FreeBSD__)
Packit Service 065837
typedef unsigned int socklen_t;
Packit Service 065837
#endif
Packit Service 065837
Packit Service 065837
#define min(x,y) ((x)<(y)?(x):(y))
Packit Service 065837
#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
Packit Service 065837
#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
Packit Service 065837
Packit Service 065837
static gchar *icy_name = NULL;
Packit Service 065837
static gint icy_metaint = 0;
Packit Service 065837
Packit Service 065837
extern InputPlugin flac_ip;
Packit Service 065837
Packit Service 065837
#undef DEBUG_UDP
Packit Service 065837
Packit Service 065837
/* Static udp channel functions */
Packit Service 065837
static int udp_establish_listener (gint *sock);
Packit Service 065837
static int udp_check_for_data(gint sock);
Packit Service 065837
Packit Service 065837
static char *flac_http_get_title(char *url);
Packit Service 065837
Packit Service 065837
static gboolean prebuffering, going, eof = FALSE;
Packit Service 065837
static gint sock, rd_index, wr_index, buffer_length, prebuffer_length;
Packit Service 065837
static guint64 buffer_read = 0;
Packit Service 065837
static gchar *buffer;
Packit Service 065837
static guint64 offset;
Packit Service 065837
static pthread_t thread;
Packit Service 065837
static GtkWidget *error_dialog = NULL;
Packit Service 065837
Packit Service 065837
static FILE *output_file = NULL;
Packit Service 065837
Packit Service 065837
#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
Packit Service 065837
Packit Service 065837
/* Encode the string S of length LENGTH to base64 format and place it
Packit Service 065837
   to STORE.  STORE will be 0-terminated, and must point to a writable
Packit Service 065837
   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
Packit Service 065837
static void base64_encode (const gchar *s, gchar *store, gint length)
Packit Service 065837
{
Packit Service 065837
	/* Conversion table.  */
Packit Service 065837
	static gchar tbl[64] = {
Packit Service 065837
		'A','B','C','D','E','F','G','H',
Packit Service 065837
		'I','J','K','L','M','N','O','P',
Packit Service 065837
		'Q','R','S','T','U','V','W','X',
Packit Service 065837
		'Y','Z','a','b','c','d','e','f',
Packit Service 065837
		'g','h','i','j','k','l','m','n',
Packit Service 065837
		'o','p','q','r','s','t','u','v',
Packit Service 065837
		'w','x','y','z','0','1','2','3',
Packit Service 065837
		'4','5','6','7','8','9','+','/'
Packit Service 065837
	};
Packit Service 065837
	gint i;
Packit Service 065837
	guchar *p = (guchar *)store;
Packit Service 065837
Packit Service 065837
	/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
Packit Service 065837
	for (i = 0; i < length; i += 3)
Packit Service 065837
	{
Packit Service 065837
		*p++ = tbl[s[0] >> 2];
Packit Service 065837
		*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
Packit Service 065837
		*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
Packit Service 065837
		*p++ = tbl[s[2] & 0x3f];
Packit Service 065837
		s += 3;
Packit Service 065837
	}
Packit Service 065837
	/* Pad the result if necessary...  */
Packit Service 065837
	if (i == length + 1)
Packit Service 065837
		*(p - 1) = '=';
Packit Service 065837
	else if (i == length + 2)
Packit Service 065837
		*(p - 1) = *(p - 2) = '=';
Packit Service 065837
	/* ...and zero-terminate it.  */
Packit Service 065837
	*p = '\0';
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
/* Create the authentication header contents for the `Basic' scheme.
Packit Service 065837
   This is done by encoding the string `USER:PASS' in base64 and
Packit Service 065837
   prepending `HEADER: Basic ' to it.  */
Packit Service 065837
static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header)
Packit Service 065837
{
Packit Service 065837
	gchar *t1, *t2, *res;
Packit Service 065837
	gint len1 = strlen (user) + 1 + strlen (passwd);
Packit Service 065837
	gint len2 = BASE64_LENGTH (len1);
Packit Service 065837
Packit Service 065837
	t1 = g_strdup_printf("%s:%s", user, passwd);
Packit Service 065837
	t2 = g_malloc0(len2 + 1);
Packit Service 065837
	base64_encode (t1, t2, len1);
Packit Service 065837
	res = g_strdup_printf("%s: Basic %s\r\n", header, t2);
Packit Service 065837
	g_free(t2);
Packit Service 065837
	g_free(t1);
Packit Service 065837
Packit Service 065837
	return res;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename)
Packit Service 065837
{
Packit Service 065837
	gchar *h, *p, *pt, *f, *temp, *ptr;
Packit Service 065837
Packit Service 065837
	temp = g_strdup(url);
Packit Service 065837
	ptr = temp;
Packit Service 065837
Packit Service 065837
	if (!strncasecmp("http://", ptr, 7))
Packit Service 065837
		ptr += 7;
Packit Service 065837
	h = strchr(ptr, '@');
Packit Service 065837
	f = strchr(ptr, '/');
Packit Service 065837
	if (h != NULL && (!f || h < f))
Packit Service 065837
	{
Packit Service 065837
		*h = '\0';
Packit Service 065837
		p = strchr(ptr, ':');
Packit Service 065837
		if (p != NULL && p < h)
Packit Service 065837
		{
Packit Service 065837
			*p = '\0';
Packit Service 065837
			p++;
Packit Service 065837
			*pass = g_strdup(p);
Packit Service 065837
		}
Packit Service 065837
		else
Packit Service 065837
			*pass = NULL;
Packit Service 065837
		*user = g_strdup(ptr);
Packit Service 065837
		h++;
Packit Service 065837
		ptr = h;
Packit Service 065837
	}
Packit Service 065837
	else
Packit Service 065837
	{
Packit Service 065837
		*user = NULL;
Packit Service 065837
		*pass = NULL;
Packit Service 065837
		h = ptr;
Packit Service 065837
	}
Packit Service 065837
	pt = strchr(ptr, ':');
Packit Service 065837
	if (pt != NULL && (f == NULL || pt < f))
Packit Service 065837
	{
Packit Service 065837
		*pt = '\0';
Packit Service 065837
		*port = atoi(pt + 1);
Packit Service 065837
	}
Packit Service 065837
	else
Packit Service 065837
	{
Packit Service 065837
		if (f)
Packit Service 065837
			*f = '\0';
Packit Service 065837
		*port = 80;
Packit Service 065837
	}
Packit Service 065837
	*host = g_strdup(h);
Packit Service 065837
Packit Service 065837
	if (f)
Packit Service 065837
		*filename = g_strdup(f + 1);
Packit Service 065837
	else
Packit Service 065837
		*filename = NULL;
Packit Service 065837
	g_free(temp);
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
void flac_http_close(void)
Packit Service 065837
{
Packit Service 065837
	going = FALSE;
Packit Service 065837
Packit Service 065837
	pthread_join(thread, NULL);
Packit Service 065837
	g_free(icy_name);
Packit Service 065837
	icy_name = NULL;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
Packit Service 065837
static gint http_used(void)
Packit Service 065837
{
Packit Service 065837
	if (wr_index >= rd_index)
Packit Service 065837
		return wr_index - rd_index;
Packit Service 065837
	return buffer_length - (rd_index - wr_index);
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static gint http_free(void)
Packit Service 065837
{
Packit Service 065837
	if (rd_index > wr_index)
Packit Service 065837
		return (rd_index - wr_index) - 1;
Packit Service 065837
	return (buffer_length - (wr_index - rd_index)) - 1;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static void http_wait_for_data(gint bytes)
Packit Service 065837
{
Packit Service 065837
	while ((prebuffering || http_used() < bytes) && !eof && going)
Packit Service 065837
		xmms_usleep(10000);
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static void show_error_message(gchar *error)
Packit Service 065837
{
Packit Service 065837
	if(!error_dialog)
Packit Service 065837
	{
Packit Service 065837
		GDK_THREADS_ENTER();
Packit Service 065837
		error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE,
Packit Service 065837
						 NULL, NULL);
Packit Service 065837
		gtk_signal_connect(GTK_OBJECT(error_dialog),
Packit Service 065837
				   "destroy",
Packit Service 065837
				   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
Packit Service 065837
				   &error_dialog);
Packit Service 065837
		GDK_THREADS_LEAVE();
Packit Service 065837
	}
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
int flac_http_read(gpointer data, gint length)
Packit Service 065837
{
Packit Service 065837
	gint len, cnt, off = 0, meta_len, meta_off = 0, i;
Packit Service 065837
	gchar *meta_data, **tags, *temp, *title;
Packit Service 065837
	if (length > buffer_length) {
Packit Service 065837
		length = buffer_length;
Packit Service 065837
	}
Packit Service 065837
Packit Service 065837
	http_wait_for_data(length);
Packit Service 065837
Packit Service 065837
	if (!going)
Packit Service 065837
		return 0;
Packit Service 065837
	len = min(http_used(), length);
Packit Service 065837
Packit Service 065837
	while (len && http_used())
Packit Service 065837
	{
Packit Service 065837
		if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0))
Packit Service 065837
		{
Packit Service 065837
			meta_len = *((guchar *) buffer + rd_index) * 16;
Packit Service 065837
			rd_index = (rd_index + 1) % buffer_length;
Packit Service 065837
			if (meta_len > 0)
Packit Service 065837
			{
Packit Service 065837
				http_wait_for_data(meta_len);
Packit Service 065837
				meta_data = g_malloc0(meta_len);
Packit Service 065837
				if (http_used() >= meta_len)
Packit Service 065837
				{
Packit Service 065837
					while (meta_len)
Packit Service 065837
					{
Packit Service 065837
						cnt = min(meta_len, buffer_length - rd_index);
Packit Service 065837
						memcpy(meta_data + meta_off, buffer + rd_index, cnt);
Packit Service 065837
						rd_index = (rd_index + cnt) % buffer_length;
Packit Service 065837
						meta_len -= cnt;
Packit Service 065837
						meta_off += cnt;
Packit Service 065837
					}
Packit Service 065837
					tags = g_strsplit(meta_data, "';", 0);
Packit Service 065837
Packit Service 065837
					for (i = 0; tags[i]; i++)
Packit Service 065837
					{
Packit Service 065837
						if (!strncasecmp(tags[i], "StreamTitle=", 12))
Packit Service 065837
						{
Packit Service 065837
							temp = g_strdup(tags[i] + 13);
Packit Service 065837
							title = g_strdup_printf("%s (%s)", temp, icy_name);
Packit Service 065837
							set_track_info(title, -1);
Packit Service 065837
							g_free(title);
Packit Service 065837
							g_free(temp);
Packit Service 065837
						}
Packit Service 065837
Packit Service 065837
					}
Packit Service 065837
					g_strfreev(tags);
Packit Service 065837
Packit Service 065837
				}
Packit Service 065837
				g_free(meta_data);
Packit Service 065837
			}
Packit Service 065837
			if (!http_used())
Packit Service 065837
				http_wait_for_data(length - off);
Packit Service 065837
			cnt = min3(len, buffer_length - rd_index, http_used());
Packit Service 065837
		}
Packit Service 065837
		else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming))
Packit Service 065837
			cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint));
Packit Service 065837
		else
Packit Service 065837
			cnt = min3(len, buffer_length - rd_index, http_used());
Packit Service 065837
		if (output_file)
Packit Service 065837
			fwrite(buffer + rd_index, 1, cnt, output_file);
Packit Service 065837
Packit Service 065837
		memcpy((gchar *)data + off, buffer + rd_index, cnt);
Packit Service 065837
		rd_index = (rd_index + cnt) % buffer_length;
Packit Service 065837
		buffer_read += cnt;
Packit Service 065837
		len -= cnt;
Packit Service 065837
		off += cnt;
Packit Service 065837
	}
Packit Service 065837
	if (!off) {
Packit Service 065837
		fprintf(stderr, "returning zero\n");
Packit Service 065837
	}
Packit Service 065837
	return off;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static gboolean http_check_for_data(void)
Packit Service 065837
{
Packit Service 065837
Packit Service 065837
	fd_set set;
Packit Service 065837
	struct timeval tv;
Packit Service 065837
	gint ret;
Packit Service 065837
Packit Service 065837
	tv.tv_sec = 0;
Packit Service 065837
	tv.tv_usec = 20000;
Packit Service 065837
	FD_ZERO(&set);
Packit Service 065837
	FD_SET(sock, &set);
Packit Service 065837
	ret = select(sock + 1, &set, NULL, NULL, &tv;;
Packit Service 065837
	if (ret > 0)
Packit Service 065837
		return TRUE;
Packit Service 065837
	return FALSE;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
gint flac_http_read_line(gchar * buf, gint size)
Packit Service 065837
{
Packit Service 065837
	gint i = 0;
Packit Service 065837
Packit Service 065837
	while (going && i < size - 1)
Packit Service 065837
	{
Packit Service 065837
		if (http_check_for_data())
Packit Service 065837
		{
Packit Service 065837
			if (read(sock, buf + i, 1) <= 0)
Packit Service 065837
				return -1;
Packit Service 065837
			if (buf[i] == '\n')
Packit Service 065837
				break;
Packit Service 065837
			if (buf[i] != '\r')
Packit Service 065837
				i++;
Packit Service 065837
		}
Packit Service 065837
	}
Packit Service 065837
	if (!going)
Packit Service 065837
		return -1;
Packit Service 065837
	buf[i] = '\0';
Packit Service 065837
	return i;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
/* returns the file descriptor of the socket, or -1 on error */
Packit Service 065837
static int http_connect (gchar *url_, gboolean head, guint64 offset)
Packit Service 065837
{
Packit Service 065837
	gchar line[1024], *user, *pass, *host, *filename,
Packit Service 065837
	     *status, *url, *temp, *file;
Packit Service 065837
	gchar *chost;
Packit Service 065837
	gint cnt, error, port, cport;
Packit Service 065837
	socklen_t err_len;
Packit Service 065837
	gboolean redirect;
Packit Service 065837
	int udp_sock = 0;
Packit Service 065837
	fd_set set;
Packit Service 065837
	struct hostent *hp;
Packit Service 065837
	struct sockaddr_in address;
Packit Service 065837
	struct timeval tv;
Packit Service 065837
Packit Service 065837
	url = g_strdup (url_);
Packit Service 065837
Packit Service 065837
	do
Packit Service 065837
	{
Packit Service 065837
		redirect=FALSE;
Packit Service 065837
Packit Service 065837
		g_strstrip(url);
Packit Service 065837
Packit Service 065837
		parse_url(url, &user, &pass, &host, &port, &filename);
Packit Service 065837
Packit Service 065837
		if ((!filename || !*filename) && url[strlen(url) - 1] != '/')
Packit Service 065837
			temp = g_strconcat(url, "/", NULL);
Packit Service 065837
		else
Packit Service 065837
			temp = g_strdup(url);
Packit Service 065837
		g_free(url);
Packit Service 065837
		url = temp;
Packit Service 065837
Packit Service 065837
		chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host;
Packit Service 065837
		cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port;
Packit Service 065837
Packit Service 065837
		sock = socket(AF_INET, SOCK_STREAM, 0);
Packit Service 065837
		fcntl(sock, F_SETFL, O_NONBLOCK);
Packit Service 065837
		address.sin_family = AF_INET;
Packit Service 065837
Packit Service 065837
		status = g_strdup_printf(_("LOOKING UP %s"), chost);
Packit Service 065837
		flac_ip.set_info_text(status);
Packit Service 065837
		g_free(status);
Packit Service 065837
Packit Service 065837
		if (!(hp = gethostbyname(chost)))
Packit Service 065837
		{
Packit Service 065837
			status = g_strdup_printf(_("Couldn't look up host %s"), chost);
Packit Service 065837
			show_error_message(status);
Packit Service 065837
			g_free(status);
Packit Service 065837
Packit Service 065837
			flac_ip.set_info_text(NULL);
Packit Service 065837
			eof = TRUE;
Packit Service 065837
		}
Packit Service 065837
Packit Service 065837
		if (!eof)
Packit Service 065837
		{
Packit Service 065837
			memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
Packit Service 065837
			address.sin_port = (gint) g_htons(cport);
Packit Service 065837
Packit Service 065837
			status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
Packit Service 065837
			flac_ip.set_info_text(status);
Packit Service 065837
			g_free(status);
Packit Service 065837
			if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
Packit Service 065837
			{
Packit Service 065837
				if (errno != EINPROGRESS)
Packit Service 065837
				{
Packit Service 065837
					status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
Packit Service 065837
					show_error_message(status);
Packit Service 065837
					g_free(status);
Packit Service 065837
Packit Service 065837
					flac_ip.set_info_text(NULL);
Packit Service 065837
					eof = TRUE;
Packit Service 065837
				}
Packit Service 065837
			}
Packit Service 065837
			while (going)
Packit Service 065837
			{
Packit Service 065837
				tv.tv_sec = 0;
Packit Service 065837
				tv.tv_usec = 10000;
Packit Service 065837
				FD_ZERO(&set);
Packit Service 065837
				FD_SET(sock, &set);
Packit Service 065837
				if (select(sock + 1, NULL, &set, NULL, &tv) > 0)
Packit Service 065837
				{
Packit Service 065837
					err_len = sizeof (error);
Packit Service 065837
					getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
Packit Service 065837
					if (error)
Packit Service 065837
					{
Packit Service 065837
						status = g_strdup_printf(_("Couldn't connect to host %s"),
Packit Service 065837
									 chost);
Packit Service 065837
						show_error_message(status);
Packit Service 065837
						g_free(status);
Packit Service 065837
Packit Service 065837
						flac_ip.set_info_text(NULL);
Packit Service 065837
						eof = TRUE;
Packit Service 065837
Packit Service 065837
					}
Packit Service 065837
					break;
Packit Service 065837
				}
Packit Service 065837
			}
Packit Service 065837
			if (!eof)
Packit Service 065837
			{
Packit Service 065837
				gchar *auth = NULL, *proxy_auth = NULL;
Packit Service 065837
				gchar udpspace[30];
Packit Service 065837
				int udp_port;
Packit Service 065837
Packit Service 065837
				if (flac_cfg.stream.use_udp_channel)
Packit Service 065837
				{
Packit Service 065837
					udp_port = udp_establish_listener (&udp_sock);
Packit Service 065837
					if (udp_port > 0)
Packit Service 065837
						flac_snprintf (udpspace, sizeof (udpspace), "x-audiocast-udpport: %d\r\n", udp_port);
Packit Service 065837
					else
Packit Service 065837
						udp_sock = 0;
Packit Service 065837
				}
Packit Service 065837
Packit Service 065837
				if(user && pass)
Packit Service 065837
					auth = basic_authentication_encode(user, pass, "Authorization");
Packit Service 065837
Packit Service 065837
				if (flac_cfg.stream.use_proxy)
Packit Service 065837
				{
Packit Service 065837
					file = g_strdup(url);
Packit Service 065837
					if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass)
Packit Service 065837
					{
Packit Service 065837
						proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user,
Packit Service 065837
											 flac_cfg.stream.proxy_pass,
Packit Service 065837
											 "Proxy-Authorization");
Packit Service 065837
					}
Packit Service 065837
				}
Packit Service 065837
				else
Packit Service 065837
					file = g_strconcat("/", filename, NULL);
Packit Service 065837
Packit Service 065837
				temp = g_strdup_printf("GET %s HTTP/1.0\r\n"
Packit Service 065837
						       "Host: %s\r\n"
Packit Service 065837
						       "User-Agent: %s/%s\r\n"
Packit Service 065837
						       "%s%s%s%s",
Packit Service 065837
						       file, host, "Reference FLAC Player", FLAC__VERSION_STRING,
Packit Service 065837
						       proxy_auth ? proxy_auth : "", auth ? auth : "",
Packit Service 065837
						       flac_cfg.stream.cast_title_streaming ?  "Icy-MetaData:1\r\n" : "",
Packit Service 065837
						       flac_cfg.stream.use_udp_channel ? udpspace : "");
Packit Service 065837
				if (offset && !head) {
Packit Service 065837
					gchar *temp_dead = temp;
Packit Service 065837
					temp = g_strdup_printf ("%sRange: %" PRIu64 "-\r\n", temp, offset);
Packit Service 065837
					fputs (temp, stderr);
Packit Service 065837
					g_free (temp_dead);
Packit Service 065837
				}
Packit Service 065837
Packit Service 065837
				g_free(file);
Packit Service 065837
				if(proxy_auth)
Packit Service 065837
					g_free(proxy_auth);
Packit Service 065837
				if(auth)
Packit Service 065837
					g_free(auth);
Packit Service 065837
				write(sock, temp, strlen(temp));
Packit Service 065837
				write(sock, "\r\n", 2);
Packit Service 065837
				g_free(temp);
Packit Service 065837
				flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY"));
Packit Service 065837
				while (going && !eof)
Packit Service 065837
				  {
Packit Service 065837
					if (http_check_for_data())
Packit Service 065837
					{
Packit Service 065837
						if (flac_http_read_line(line, 1024))
Packit Service 065837
						{
Packit Service 065837
							status = strchr(line, ' ');
Packit Service 065837
							if (status)
Packit Service 065837
							{
Packit Service 065837
								if (status[1] == '2')
Packit Service 065837
									break;
Packit Service 065837
								else if(status[1] == '3' && status[2] == '0' && status[3] == '2')
Packit Service 065837
								{
Packit Service 065837
									while(going)
Packit Service 065837
									{
Packit Service 065837
										if(http_check_for_data())
Packit Service 065837
										{
Packit Service 065837
											if((cnt = flac_http_read_line(line, 1024)) != -1)
Packit Service 065837
											{
Packit Service 065837
												if(!cnt)
Packit Service 065837
													break;
Packit Service 065837
												if(!strncmp(line, "Location:", 9))
Packit Service 065837
												{
Packit Service 065837
													g_free(url);
Packit Service 065837
													url = g_strdup(line+10);
Packit Service 065837
												}
Packit Service 065837
											}
Packit Service 065837
											else
Packit Service 065837
											{
Packit Service 065837
												eof=TRUE;
Packit Service 065837
												flac_ip.set_info_text(NULL);
Packit Service 065837
												break;
Packit Service 065837
											}
Packit Service 065837
										}
Packit Service 065837
									}
Packit Service 065837
									redirect=TRUE;
Packit Service 065837
									break;
Packit Service 065837
								}
Packit Service 065837
								else
Packit Service 065837
								{
Packit Service 065837
									status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status);
Packit Service 065837
									show_error_message(status);
Packit Service 065837
									g_free(status);
Packit Service 065837
									break;
Packit Service 065837
								}
Packit Service 065837
							}
Packit Service 065837
						}
Packit Service 065837
						else
Packit Service 065837
						{
Packit Service 065837
							eof = TRUE;
Packit Service 065837
							flac_ip.set_info_text(NULL);
Packit Service 065837
						}
Packit Service 065837
					}
Packit Service 065837
				}
Packit Service 065837
Packit Service 065837
				while (going && !redirect)
Packit Service 065837
				{
Packit Service 065837
					if (http_check_for_data())
Packit Service 065837
					{
Packit Service 065837
						if ((cnt = flac_http_read_line(line, 1024)) != -1)
Packit Service 065837
						{
Packit Service 065837
							if (!cnt)
Packit Service 065837
								break;
Packit Service 065837
							if (!strncmp(line, "icy-name:", 9))
Packit Service 065837
								icy_name = g_strdup(line + 9);
Packit Service 065837
							else if (!strncmp(line, "x-audiocast-name:", 17))
Packit Service 065837
								icy_name = g_strdup(line + 17);
Packit Service 065837
							if (!strncmp(line, "icy-metaint:", 12))
Packit Service 065837
								icy_metaint = atoi(line + 12);
Packit Service 065837
							if (!strncmp(line, "x-audiocast-udpport:", 20)) {
Packit Service 065837
#ifdef DEBUG_UDP
Packit Service 065837
								fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20));
Packit Service 065837
#endif
Packit Service 065837
								/*udp_serverport = atoi (line + 20);*/
Packit Service 065837
							}
Packit Service 065837
Packit Service 065837
						}
Packit Service 065837
						else
Packit Service 065837
						{
Packit Service 065837
							eof = TRUE;
Packit Service 065837
							flac_ip.set_info_text(NULL);
Packit Service 065837
							break;
Packit Service 065837
						}
Packit Service 065837
					}
Packit Service 065837
				}
Packit Service 065837
			}
Packit Service 065837
		}
Packit Service 065837
Packit Service 065837
		if(redirect)
Packit Service 065837
		{
Packit Service 065837
			if (output_file)
Packit Service 065837
			{
Packit Service 065837
				fclose(output_file);
Packit Service 065837
				output_file = NULL;
Packit Service 065837
			}
Packit Service 065837
			close(sock);
Packit Service 065837
		}
Packit Service 065837
Packit Service 065837
		g_free(user);
Packit Service 065837
		g_free(pass);
Packit Service 065837
		g_free(host);
Packit Service 065837
		g_free(filename);
Packit Service 065837
	} while(redirect);
Packit Service 065837
Packit Service 065837
	g_free(url);
Packit Service 065837
	return eof ? -1 : sock;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static void *http_buffer_loop(void *arg)
Packit Service 065837
{
Packit Service 065837
	gchar *status, *url, *temp, *file;
Packit Service 065837
	gint cnt, written;
Packit Service 065837
	int udp_sock = 0;
Packit Service 065837
Packit Service 065837
	url = (gchar *) arg;
Packit Service 065837
	sock = http_connect (url, false, offset);
Packit Service 065837
Packit Service 065837
	if (sock >= 0 && flac_cfg.stream.save_http_stream) {
Packit Service 065837
		gchar *output_name;
Packit Service 065837
		file = flac_http_get_title(url);
Packit Service 065837
		output_name = file;
Packit Service 065837
		if (!strncasecmp(output_name, "http://", 7))
Packit Service 065837
			output_name += 7;
Packit Service 065837
		temp = strrchr(output_name, '.');
Packit Service 065837
		if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac")))
Packit Service 065837
			*temp = '\0';
Packit Service 065837
Packit Service 065837
		while ((temp = strchr(output_name, '/')))
Packit Service 065837
			*temp = '_';
Packit Service 065837
		output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name);
Packit Service 065837
Packit Service 065837
		g_free(file);
Packit Service 065837
Packit Service 065837
		output_file = fopen(output_name, "wb");
Packit Service 065837
		g_free(output_name);
Packit Service 065837
	}
Packit Service 065837
Packit Service 065837
	while (going)
Packit Service 065837
	{
Packit Service 065837
Packit Service 065837
		if (!http_used() && !flac_ip.output->buffer_playing())
Packit Service 065837
			prebuffering = TRUE;
Packit Service 065837
		if (http_free() > 0 && !eof)
Packit Service 065837
		{
Packit Service 065837
			if (http_check_for_data())
Packit Service 065837
			{
Packit Service 065837
				cnt = min(http_free(), buffer_length - wr_index);
Packit Service 065837
				if (cnt > 1024)
Packit Service 065837
					cnt = 1024;
Packit Service 065837
				written = read(sock, buffer + wr_index, cnt);
Packit Service 065837
				if (written <= 0)
Packit Service 065837
				{
Packit Service 065837
					eof = TRUE;
Packit Service 065837
					if (prebuffering)
Packit Service 065837
					{
Packit Service 065837
						prebuffering = FALSE;
Packit Service 065837
Packit Service 065837
						flac_ip.set_info_text(NULL);
Packit Service 065837
					}
Packit Service 065837
Packit Service 065837
				}
Packit Service 065837
				else
Packit Service 065837
					wr_index = (wr_index + written) % buffer_length;
Packit Service 065837
			}
Packit Service 065837
Packit Service 065837
			if (prebuffering)
Packit Service 065837
			{
Packit Service 065837
				if (http_used() > prebuffer_length)
Packit Service 065837
				{
Packit Service 065837
					prebuffering = FALSE;
Packit Service 065837
					flac_ip.set_info_text(NULL);
Packit Service 065837
				}
Packit Service 065837
				else
Packit Service 065837
				{
Packit Service 065837
					status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024);
Packit Service 065837
					flac_ip.set_info_text(status);
Packit Service 065837
					g_free(status);
Packit Service 065837
				}
Packit Service 065837
Packit Service 065837
			}
Packit Service 065837
		}
Packit Service 065837
		else
Packit Service 065837
			xmms_usleep(10000);
Packit Service 065837
Packit Service 065837
		if (flac_cfg.stream.use_udp_channel && udp_sock != 0)
Packit Service 065837
			if (udp_check_for_data(udp_sock) < 0)
Packit Service 065837
			{
Packit Service 065837
				close(udp_sock);
Packit Service 065837
				udp_sock = 0;
Packit Service 065837
			}
Packit Service 065837
	}
Packit Service 065837
	if (output_file)
Packit Service 065837
	{
Packit Service 065837
		fclose(output_file);
Packit Service 065837
		output_file = NULL;
Packit Service 065837
	}
Packit Service 065837
	if (sock >= 0) {
Packit Service 065837
		close(sock);
Packit Service 065837
	}
Packit Service 065837
	if (udp_sock != 0)
Packit Service 065837
		close(udp_sock);
Packit Service 065837
Packit Service 065837
	g_free(buffer);
Packit Service 065837
	g_free(url);
Packit Service 065837
Packit Service 065837
	pthread_exit(NULL);
Packit Service 065837
	return NULL; /* avoid compiler warning */
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
int flac_http_open(const gchar * _url, guint64 _offset)
Packit Service 065837
{
Packit Service 065837
	gchar *url;
Packit Service 065837
Packit Service 065837
	url = g_strdup(_url);
Packit Service 065837
Packit Service 065837
	rd_index = 0;
Packit Service 065837
	wr_index = 0;
Packit Service 065837
	buffer_length = flac_cfg.stream.http_buffer_size * 1024;
Packit Service 065837
	prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100;
Packit Service 065837
	buffer_read = 0;
Packit Service 065837
	icy_metaint = 0;
Packit Service 065837
	prebuffering = TRUE;
Packit Service 065837
	going = TRUE;
Packit Service 065837
	eof = FALSE;
Packit Service 065837
	buffer = g_malloc(buffer_length);
Packit Service 065837
	offset = _offset;
Packit Service 065837
Packit Service 065837
	pthread_create(&thread, NULL, http_buffer_loop, url);
Packit Service 065837
Packit Service 065837
	return 0;
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
char *flac_http_get_title(char *url)
Packit Service 065837
{
Packit Service 065837
	if (icy_name)
Packit Service 065837
		return g_strdup(icy_name);
Packit Service 065837
	if (g_basename(url) && strlen(g_basename(url)) > 0)
Packit Service 065837
		return g_strdup(g_basename(url));
Packit Service 065837
	return g_strdup(url);
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
/* Start UDP Channel specific stuff */
Packit Service 065837
Packit Service 065837
/* Find a good local udp port and bind udp_sock to it, return the port */
Packit Service 065837
static int udp_establish_listener(int *sock)
Packit Service 065837
{
Packit Service 065837
	struct sockaddr_in sin;
Packit Service 065837
	socklen_t sinlen = sizeof (struct sockaddr_in);
Packit Service 065837
Packit Service 065837
#ifdef DEBUG_UDP
Packit Service 065837
	fprintf (stderr,"Establishing udp listener\n");
Packit Service 065837
#endif
Packit Service 065837
Packit Service 065837
	if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
Packit Service 065837
	{
Packit Service 065837
		g_log(NULL, G_LOG_LEVEL_CRITICAL,
Packit Service 065837
		      "udp_establish_listener(): unable to create socket");
Packit Service 065837
		return -1;
Packit Service 065837
	}
Packit Service 065837
Packit Service 065837
	memset(&sin, 0, sinlen);
Packit Service 065837
	sin.sin_family = AF_INET;
Packit Service 065837
	sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
Packit Service 065837
Packit Service 065837
	if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
Packit Service 065837
	{
Packit Service 065837
		g_log(NULL, G_LOG_LEVEL_CRITICAL,
Packit Service 065837
		      "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
Packit Service 065837
		close(*sock);
Packit Service 065837
		return -1;
Packit Service 065837
	}
Packit Service 065837
	if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
Packit Service 065837
	{
Packit Service 065837
		g_log(NULL, G_LOG_LEVEL_CRITICAL,
Packit Service 065837
		      "udp_establish_listener():  Failed to set flags: %s", strerror(errno));
Packit Service 065837
		close(*sock);
Packit Service 065837
		return -1;
Packit Service 065837
	}
Packit Service 065837
Packit Service 065837
	memset(&sin, 0, sinlen);
Packit Service 065837
	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
Packit Service 065837
	{
Packit Service 065837
		g_log(NULL, G_LOG_LEVEL_CRITICAL,
Packit Service 065837
		      "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
Packit Service 065837
		close(*sock);
Packit Service 065837
		return -1;
Packit Service 065837
	}
Packit Service 065837
Packit Service 065837
#ifdef DEBUG_UDP
Packit Service 065837
	fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
Packit Service 065837
#endif
Packit Service 065837
Packit Service 065837
	return g_ntohs(sin.sin_port);
Packit Service 065837
}
Packit Service 065837
Packit Service 065837
static int udp_check_for_data(int sock)
Packit Service 065837
{
Packit Service 065837
	char buf[1025], **lines;
Packit Service 065837
	char *valptr;
Packit Service 065837
	gchar *title;
Packit Service 065837
	gint len, i;
Packit Service 065837
	struct sockaddr_in from;
Packit Service 065837
	socklen_t fromlen;
Packit Service 065837
Packit Service 065837
	fromlen = sizeof(struct sockaddr_in);
Packit Service 065837
Packit Service 065837
	if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
Packit Service 065837
	{
Packit Service 065837
		if (errno != EAGAIN)
Packit Service 065837
		{
Packit Service 065837
			g_log(NULL, G_LOG_LEVEL_CRITICAL,
Packit Service 065837
			      "udp_read_data(): Error reading from socket: %s", strerror(errno));
Packit Service 065837
			return -1;
Packit Service 065837
		}
Packit Service 065837
		return 0;
Packit Service 065837
	}
Packit Service 065837
	buf[len] = '\0';
Packit Service 065837
#ifdef DEBUG_UDP
Packit Service 065837
	fprintf (stderr,"Received: [%s]\n", buf);
Packit Service 065837
#endif
Packit Service 065837
	lines = g_strsplit(buf, "\n", 0);
Packit Service 065837
	if (!lines)
Packit Service 065837
		return 0;
Packit Service 065837
Packit Service 065837
	for (i = 0; lines[i]; i++)
Packit Service 065837
	{
Packit Service 065837
		while ((lines[i][strlen(lines[i]) - 1] == '\n') ||
Packit Service 065837
		       (lines[i][strlen(lines[i]) - 1] == '\r'))
Packit Service 065837
			lines[i][strlen(lines[i]) - 1] = '\0';
Packit Service 065837
Packit Service 065837
		valptr = strchr(lines[i], ':');
Packit Service 065837
Packit Service 065837
		if (!valptr)
Packit Service 065837
			continue;
Packit Service 065837
		else
Packit Service 065837
			valptr++;
Packit Service 065837
Packit Service 065837
		g_strstrip(valptr);
Packit Service 065837
		if (!strlen(valptr))
Packit Service 065837
			continue;
Packit Service 065837
Packit Service 065837
		if (strstr(lines[i], "x-audiocast-streamtitle") != NULL)
Packit Service 065837
		{
Packit Service 065837
			title = g_strdup_printf ("%s (%s)", valptr, icy_name);
Packit Service 065837
			if (going)
Packit Service 065837
				set_track_info(title, -1);
Packit Service 065837
			g_free (title);
Packit Service 065837
		}
Packit Service 065837
Packit Service 065837
#if 0
Packit Service 065837
		else if (strstr(lines[i], "x-audiocast-streamlength") != NULL)
Packit Service 065837
		{
Packit Service 065837
			if (atoi(valptr) != -1)
Packit Service 065837
				set_track_info(NULL, atoi(valptr));
Packit Service 065837
		}
Packit Service 065837
#endif
Packit Service 065837
Packit Service 065837
		else if (strstr(lines[i], "x-audiocast-streammsg") != NULL)
Packit Service 065837
		{
Packit Service 065837
			/* set_track_info(title, -1); */
Packit Service 065837
/*  			xmms_show_message(_("Message"), valptr, _("Ok"), */
Packit Service 065837
/*  					  FALSE, NULL, NULL); */
Packit Service 065837
			g_message("Stream_message: %s", valptr);
Packit Service 065837
		}
Packit Service 065837
Packit Service 065837
#if 0
Packit Service 065837
		/* Use this to direct your webbrowser.. yeah right.. */
Packit Service 065837
		else if (strstr(lines[i], "x-audiocast-streamurl") != NULL)
Packit Service 065837
		{
Packit Service 065837
			if (lasturl && g_strcmp (valptr, lasturl))
Packit Service 065837
			{
Packit Service 065837
				c_message (stderr, "Song URL: %s\n", valptr);
Packit Service 065837
				g_free (lasturl);
Packit Service 065837
				lasturl = g_strdup (valptr);
Packit Service 065837
			}
Packit Service 065837
		}
Packit Service 065837
#endif
Packit Service 065837
		else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL)
Packit Service 065837
		{
Packit Service 065837
			gchar obuf[60];
Packit Service 065837
			flac_snprintf(obuf, sizeof (obuf), "x-audiocast-ack: %ld \r\n", atol(valptr));
Packit Service 065837
			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
Packit Service 065837
			{
Packit Service 065837
				g_log(NULL, G_LOG_LEVEL_WARNING,
Packit Service 065837
				      "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
Packit Service 065837
			}
Packit Service 065837
#ifdef DEBUG_UDP
Packit Service 065837
			else
Packit Service 065837
				fprintf(stderr,"Sent ack: %s", obuf);
Packit Service 065837
			fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port));
Packit Service 065837
#endif
Packit Service 065837
		}
Packit Service 065837
	}
Packit Service 065837
	g_strfreev(lines);
Packit Service 065837
	return 0;
Packit Service 065837
}