1/*  XMMS - Cross-platform multimedia player
2 *  Copyright (C) 1998-2000  Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
3 *
4 *  This program is free software; you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License as published by
6 *  the Free Software Foundation; either version 2 of the License, or
7 *  (at your option) any later version.
8 *
9 *  This program is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *  GNU General Public License for more details.
13 *
14 *  You should have received a copy of the GNU General Public License
15 *  along with this program; if not, write to the Free Software
16 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18/* modified for FLAC support by Steven Richman (2003) */
19
20#if HAVE_CONFIG_H
21#  include <config.h>
22#endif
23
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <sys/time.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <netdb.h>
30#include <glib.h>
31#include <string.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37
38#include <pthread.h>
39
40#include <xmms/util.h>
41#include <xmms/plugin.h>
42
43#include "FLAC/format.h"
44#include "configure.h"
45#include "locale_hack.h"
46#include "plugin.h"
47
48/* on FreeBSD we get socklen_t from <sys/socket.h> */
49#if (!defined HAVE_SOCKLEN_T) && !defined(__FreeBSD__)
50typedef unsigned int socklen_t;
51#endif
52
53#define min(x,y) ((x)<(y)?(x):(y))
54#define min3(x,y,z) (min(x,y)<(z)?min(x,y):(z))
55#define min4(x,y,z,w) (min3(x,y,z)<(w)?min3(x,y,z):(w))
56
57static gchar *icy_name = NULL;
58static gint icy_metaint = 0;
59
60extern InputPlugin flac_ip;
61
62#undef DEBUG_UDP
63
64/* Static udp channel functions */
65static int udp_establish_listener (gint *sock);
66static int udp_check_for_data(gint sock);
67
68static char *flac_http_get_title(char *url);
69
70static gboolean prebuffering, going, eof = FALSE;
71static gint sock, rd_index, wr_index, buffer_length, prebuffer_length;
72static guint64 buffer_read = 0;
73static gchar *buffer;
74static guint64 offset;
75static pthread_t thread;
76static GtkWidget *error_dialog = NULL;
77
78static FILE *output_file = NULL;
79
80#define BASE64_LENGTH(len) (4 * (((len) + 2) / 3))
81
82/* Encode the string S of length LENGTH to base64 format and place it
83   to STORE.  STORE will be 0-terminated, and must point to a writable
84   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
85static void base64_encode (const gchar *s, gchar *store, gint length)
86{
87	/* Conversion table.  */
88	static gchar tbl[64] = {
89		'A','B','C','D','E','F','G','H',
90		'I','J','K','L','M','N','O','P',
91		'Q','R','S','T','U','V','W','X',
92		'Y','Z','a','b','c','d','e','f',
93		'g','h','i','j','k','l','m','n',
94		'o','p','q','r','s','t','u','v',
95		'w','x','y','z','0','1','2','3',
96		'4','5','6','7','8','9','+','/'
97	};
98	gint i;
99	guchar *p = (guchar *)store;
100
101	/* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
102	for (i = 0; i < length; i += 3)
103	{
104		*p++ = tbl[s[0] >> 2];
105		*p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
106		*p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
107		*p++ = tbl[s[2] & 0x3f];
108		s += 3;
109	}
110	/* Pad the result if necessary...  */
111	if (i == length + 1)
112		*(p - 1) = '=';
113	else if (i == length + 2)
114		*(p - 1) = *(p - 2) = '=';
115	/* ...and zero-terminate it.  */
116	*p = '\0';
117}
118
119/* Create the authentication header contents for the `Basic' scheme.
120   This is done by encoding the string `USER:PASS' in base64 and
121   prepending `HEADER: Basic ' to it.  */
122static gchar *basic_authentication_encode (const gchar *user, const gchar *passwd, const gchar *header)
123{
124	gchar *t1, *t2, *res;
125	gint len1 = strlen (user) + 1 + strlen (passwd);
126	gint len2 = BASE64_LENGTH (len1);
127
128	t1 = g_strdup_printf("%s:%s", user, passwd);
129	t2 = g_malloc0(len2 + 1);
130	base64_encode (t1, t2, len1);
131	res = g_strdup_printf("%s: Basic %s\r\n", header, t2);
132	g_free(t2);
133	g_free(t1);
134
135	return res;
136}
137
138static void parse_url(const gchar * url, gchar ** user, gchar ** pass, gchar ** host, int *port, gchar ** filename)
139{
140	gchar *h, *p, *pt, *f, *temp, *ptr;
141
142	temp = g_strdup(url);
143	ptr = temp;
144
145	if (!strncasecmp("http://", ptr, 7))
146		ptr += 7;
147	h = strchr(ptr, '@');
148	f = strchr(ptr, '/');
149	if (h != NULL && (!f || h < f))
150	{
151		*h = '\0';
152		p = strchr(ptr, ':');
153		if (p != NULL && p < h)
154		{
155			*p = '\0';
156			p++;
157			*pass = g_strdup(p);
158		}
159		else
160			*pass = NULL;
161		*user = g_strdup(ptr);
162		h++;
163		ptr = h;
164	}
165	else
166	{
167		*user = NULL;
168		*pass = NULL;
169		h = ptr;
170	}
171	pt = strchr(ptr, ':');
172	if (pt != NULL && (f == NULL || pt < f))
173	{
174		*pt = '\0';
175		*port = atoi(pt + 1);
176	}
177	else
178	{
179		if (f)
180			*f = '\0';
181		*port = 80;
182	}
183	*host = g_strdup(h);
184
185	if (f)
186		*filename = g_strdup(f + 1);
187	else
188		*filename = NULL;
189	g_free(temp);
190}
191
192void flac_http_close(void)
193{
194	going = FALSE;
195
196	pthread_join(thread, NULL);
197	g_free(icy_name);
198	icy_name = NULL;
199}
200
201
202static gint http_used(void)
203{
204	if (wr_index >= rd_index)
205		return wr_index - rd_index;
206	return buffer_length - (rd_index - wr_index);
207}
208
209static gint http_free(void)
210{
211	if (rd_index > wr_index)
212		return (rd_index - wr_index) - 1;
213	return (buffer_length - (wr_index - rd_index)) - 1;
214}
215
216static void http_wait_for_data(gint bytes)
217{
218	while ((prebuffering || http_used() < bytes) && !eof && going)
219		xmms_usleep(10000);
220}
221
222static void show_error_message(gchar *error)
223{
224	if(!error_dialog)
225	{
226		GDK_THREADS_ENTER();
227		error_dialog = xmms_show_message(_("Error"), error, _("Ok"), FALSE,
228						 NULL, NULL);
229		gtk_signal_connect(GTK_OBJECT(error_dialog),
230				   "destroy",
231				   GTK_SIGNAL_FUNC(gtk_widget_destroyed),
232				   &error_dialog);
233		GDK_THREADS_LEAVE();
234	}
235}
236
237int flac_http_read(gpointer data, gint length)
238{
239	gint len, cnt, off = 0, meta_len, meta_off = 0, i;
240	gchar *meta_data, **tags, *temp, *title;
241	if (length > buffer_length) {
242		length = buffer_length;
243	}
244
245	http_wait_for_data(length);
246
247	if (!going)
248		return 0;
249	len = min(http_used(), length);
250
251	while (len && http_used())
252	{
253		if ((flac_cfg.stream.cast_title_streaming) && (icy_metaint > 0) && (buffer_read % icy_metaint) == 0 && (buffer_read > 0))
254		{
255			meta_len = *((guchar *) buffer + rd_index) * 16;
256			rd_index = (rd_index + 1) % buffer_length;
257			if (meta_len > 0)
258			{
259				http_wait_for_data(meta_len);
260				meta_data = g_malloc0(meta_len);
261				if (http_used() >= meta_len)
262				{
263					while (meta_len)
264					{
265						cnt = min(meta_len, buffer_length - rd_index);
266						memcpy(meta_data + meta_off, buffer + rd_index, cnt);
267						rd_index = (rd_index + cnt) % buffer_length;
268						meta_len -= cnt;
269						meta_off += cnt;
270					}
271					tags = g_strsplit(meta_data, "';", 0);
272
273					for (i = 0; tags[i]; i++)
274					{
275						if (!strncasecmp(tags[i], "StreamTitle=", 12))
276						{
277							temp = g_strdup(tags[i] + 13);
278							title = g_strdup_printf("%s (%s)", temp, icy_name);
279							set_track_info(title, -1);
280							g_free(title);
281							g_free(temp);
282						}
283
284					}
285					g_strfreev(tags);
286
287				}
288				g_free(meta_data);
289			}
290			if (!http_used())
291				http_wait_for_data(length - off);
292			cnt = min3(len, buffer_length - rd_index, http_used());
293		}
294		else if ((icy_metaint > 0) && (flac_cfg.stream.cast_title_streaming))
295			cnt = min4(len, buffer_length - rd_index, http_used(), icy_metaint - (gint) (buffer_read % icy_metaint));
296		else
297			cnt = min3(len, buffer_length - rd_index, http_used());
298		if (output_file)
299			fwrite(buffer + rd_index, 1, cnt, output_file);
300
301		memcpy((gchar *)data + off, buffer + rd_index, cnt);
302		rd_index = (rd_index + cnt) % buffer_length;
303		buffer_read += cnt;
304		len -= cnt;
305		off += cnt;
306	}
307	if (!off) {
308		fprintf(stderr, "returning zero\n");
309	}
310	return off;
311}
312
313static gboolean http_check_for_data(void)
314{
315
316	fd_set set;
317	struct timeval tv;
318	gint ret;
319
320	tv.tv_sec = 0;
321	tv.tv_usec = 20000;
322	FD_ZERO(&set);
323	FD_SET(sock, &set);
324	ret = select(sock + 1, &set, NULL, NULL, &tv);
325	if (ret > 0)
326		return TRUE;
327	return FALSE;
328}
329
330gint flac_http_read_line(gchar * buf, gint size)
331{
332	gint i = 0;
333
334	while (going && i < size - 1)
335	{
336		if (http_check_for_data())
337		{
338			if (read(sock, buf + i, 1) <= 0)
339				return -1;
340			if (buf[i] == '\n')
341				break;
342			if (buf[i] != '\r')
343				i++;
344		}
345	}
346	if (!going)
347		return -1;
348	buf[i] = '\0';
349	return i;
350}
351
352/* returns the file descriptor of the socket, or -1 on error */
353static int http_connect (gchar *url_, gboolean head, guint64 offset)
354{
355	gchar line[1024], *user, *pass, *host, *filename,
356	     *status, *url, *temp, *file;
357	gchar *chost;
358	gint cnt, error, port, cport;
359	socklen_t err_len;
360	gboolean redirect;
361	int udp_sock = 0;
362	fd_set set;
363	struct hostent *hp;
364	struct sockaddr_in address;
365	struct timeval tv;
366
367	url = g_strdup (url_);
368
369	do
370	{
371		redirect=FALSE;
372
373		g_strstrip(url);
374
375		parse_url(url, &user, &pass, &host, &port, &filename);
376
377		if ((!filename || !*filename) && url[strlen(url) - 1] != '/')
378			temp = g_strconcat(url, "/", NULL);
379		else
380			temp = g_strdup(url);
381		g_free(url);
382		url = temp;
383
384		chost = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_host : host;
385		cport = flac_cfg.stream.use_proxy ? flac_cfg.stream.proxy_port : port;
386
387		sock = socket(AF_INET, SOCK_STREAM, 0);
388		fcntl(sock, F_SETFL, O_NONBLOCK);
389		address.sin_family = AF_INET;
390
391		status = g_strdup_printf(_("LOOKING UP %s"), chost);
392		flac_ip.set_info_text(status);
393		g_free(status);
394
395		if (!(hp = gethostbyname(chost)))
396		{
397			status = g_strdup_printf(_("Couldn't look up host %s"), chost);
398			show_error_message(status);
399			g_free(status);
400
401			flac_ip.set_info_text(NULL);
402			eof = TRUE;
403		}
404
405		if (!eof)
406		{
407			memcpy(&address.sin_addr.s_addr, *(hp->h_addr_list), sizeof (address.sin_addr.s_addr));
408			address.sin_port = (gint) g_htons(cport);
409
410			status = g_strdup_printf(_("CONNECTING TO %s:%d"), chost, cport);
411			flac_ip.set_info_text(status);
412			g_free(status);
413			if (connect(sock, (struct sockaddr *) &address, sizeof (struct sockaddr_in)) == -1)
414			{
415				if (errno != EINPROGRESS)
416				{
417					status = g_strdup_printf(_("Couldn't connect to host %s"), chost);
418					show_error_message(status);
419					g_free(status);
420
421					flac_ip.set_info_text(NULL);
422					eof = TRUE;
423				}
424			}
425			while (going)
426			{
427				tv.tv_sec = 0;
428				tv.tv_usec = 10000;
429				FD_ZERO(&set);
430				FD_SET(sock, &set);
431				if (select(sock + 1, NULL, &set, NULL, &tv) > 0)
432				{
433					err_len = sizeof (error);
434					getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &err_len);
435					if (error)
436					{
437						status = g_strdup_printf(_("Couldn't connect to host %s"),
438									 chost);
439						show_error_message(status);
440						g_free(status);
441
442						flac_ip.set_info_text(NULL);
443						eof = TRUE;
444
445					}
446					break;
447				}
448			}
449			if (!eof)
450			{
451				gchar *auth = NULL, *proxy_auth = NULL;
452				gchar udpspace[30];
453				int udp_port;
454
455				if (flac_cfg.stream.use_udp_channel)
456				{
457					udp_port = udp_establish_listener (&udp_sock);
458					if (udp_port > 0)
459						sprintf (udpspace, "x-audiocast-udpport: %d\r\n", udp_port);
460					else
461						udp_sock = 0;
462				}
463
464				if(user && pass)
465					auth = basic_authentication_encode(user, pass, "Authorization");
466
467				if (flac_cfg.stream.use_proxy)
468				{
469					file = g_strdup(url);
470					if(flac_cfg.stream.proxy_use_auth && flac_cfg.stream.proxy_user && flac_cfg.stream.proxy_pass)
471					{
472						proxy_auth = basic_authentication_encode(flac_cfg.stream.proxy_user,
473											 flac_cfg.stream.proxy_pass,
474											 "Proxy-Authorization");
475					}
476				}
477				else
478					file = g_strconcat("/", filename, NULL);
479
480				temp = g_strdup_printf("GET %s HTTP/1.0\r\n"
481						       "Host: %s\r\n"
482						       "User-Agent: %s/%s\r\n"
483						       "%s%s%s%s",
484						       file, host, "Reference FLAC Player", FLAC__VERSION_STRING,
485						       proxy_auth ? proxy_auth : "", auth ? auth : "",
486						       flac_cfg.stream.cast_title_streaming ?  "Icy-MetaData:1\r\n" : "",
487						       flac_cfg.stream.use_udp_channel ? udpspace : "");
488				if (offset && !head) {
489					gchar *temp_dead = temp;
490					temp = g_strdup_printf ("%sRange: %llu-\r\n", temp, offset);
491					fprintf (stderr, "%s", temp);
492					g_free (temp_dead);
493				}
494
495				g_free(file);
496				if(proxy_auth)
497					g_free(proxy_auth);
498				if(auth)
499					g_free(auth);
500				write(sock, temp, strlen(temp));
501				write(sock, "\r\n", 2);
502				g_free(temp);
503				flac_ip.set_info_text(_("CONNECTED: WAITING FOR REPLY"));
504				while (going && !eof)
505				  {
506					if (http_check_for_data())
507					{
508						if (flac_http_read_line(line, 1024))
509						{
510							status = strchr(line, ' ');
511							if (status)
512							{
513								if (status[1] == '2')
514									break;
515								else if(status[1] == '3' && status[2] == '0' && status[3] == '2')
516								{
517									while(going)
518									{
519										if(http_check_for_data())
520										{
521											if((cnt = flac_http_read_line(line, 1024)) != -1)
522											{
523												if(!cnt)
524													break;
525												if(!strncmp(line, "Location:", 9))
526												{
527													g_free(url);
528													url = g_strdup(line+10);
529												}
530											}
531											else
532											{
533												eof=TRUE;
534												flac_ip.set_info_text(NULL);
535												break;
536											}
537										}
538									}
539									redirect=TRUE;
540									break;
541								}
542								else
543								{
544									status = g_strdup_printf(_("Couldn't connect to host %s\nServer reported: %s"), chost, status);
545									show_error_message(status);
546									g_free(status);
547									break;
548								}
549							}
550						}
551						else
552						{
553							eof = TRUE;
554							flac_ip.set_info_text(NULL);
555						}
556					}
557				}
558
559				while (going && !redirect)
560				{
561					if (http_check_for_data())
562					{
563						if ((cnt = flac_http_read_line(line, 1024)) != -1)
564						{
565							if (!cnt)
566								break;
567							if (!strncmp(line, "icy-name:", 9))
568								icy_name = g_strdup(line + 9);
569							else if (!strncmp(line, "x-audiocast-name:", 17))
570								icy_name = g_strdup(line + 17);
571							if (!strncmp(line, "icy-metaint:", 12))
572								icy_metaint = atoi(line + 12);
573							if (!strncmp(line, "x-audiocast-udpport:", 20)) {
574#ifdef DEBUG_UDP
575								fprintf (stderr, "Server wants udp messages on port %d\n", atoi (line + 20));
576#endif
577								/*udp_serverport = atoi (line + 20);*/
578							}
579
580						}
581						else
582						{
583							eof = TRUE;
584							flac_ip.set_info_text(NULL);
585							break;
586						}
587					}
588				}
589			}
590		}
591
592		if(redirect)
593		{
594			if (output_file)
595			{
596				fclose(output_file);
597				output_file = NULL;
598			}
599			close(sock);
600		}
601
602		g_free(user);
603		g_free(pass);
604		g_free(host);
605		g_free(filename);
606	} while(redirect);
607
608	g_free(url);
609	return eof ? -1 : sock;
610}
611
612static void *http_buffer_loop(void *arg)
613{
614	gchar *status, *url, *temp, *file;
615	gint cnt, written;
616	int udp_sock = 0;
617
618	url = (gchar *) arg;
619	sock = http_connect (url, false, offset);
620
621	if (sock >= 0 && flac_cfg.stream.save_http_stream) {
622		gchar *output_name;
623		file = flac_http_get_title(url);
624		output_name = file;
625		if (!strncasecmp(output_name, "http://", 7))
626			output_name += 7;
627		temp = strrchr(output_name, '.');
628		if (temp && (!strcasecmp(temp, ".fla") || !strcasecmp(temp, ".flac")))
629			*temp = '\0';
630
631		while ((temp = strchr(output_name, '/')))
632			*temp = '_';
633		output_name = g_strdup_printf("%s/%s.flac", flac_cfg.stream.save_http_path, output_name);
634
635		g_free(file);
636
637		output_file = fopen(output_name, "wb");
638		g_free(output_name);
639	}
640
641	while (going)
642	{
643
644		if (!http_used() && !flac_ip.output->buffer_playing())
645			prebuffering = TRUE;
646		if (http_free() > 0 && !eof)
647		{
648			if (http_check_for_data())
649			{
650				cnt = min(http_free(), buffer_length - wr_index);
651				if (cnt > 1024)
652					cnt = 1024;
653				written = read(sock, buffer + wr_index, cnt);
654				if (written <= 0)
655				{
656					eof = TRUE;
657					if (prebuffering)
658					{
659						prebuffering = FALSE;
660
661						flac_ip.set_info_text(NULL);
662					}
663
664				}
665				else
666					wr_index = (wr_index + written) % buffer_length;
667			}
668
669			if (prebuffering)
670			{
671				if (http_used() > prebuffer_length)
672				{
673					prebuffering = FALSE;
674					flac_ip.set_info_text(NULL);
675				}
676				else
677				{
678					status = g_strdup_printf(_("PRE-BUFFERING: %dKB/%dKB"), http_used() / 1024, prebuffer_length / 1024);
679					flac_ip.set_info_text(status);
680					g_free(status);
681				}
682
683			}
684		}
685		else
686			xmms_usleep(10000);
687
688		if (flac_cfg.stream.use_udp_channel && udp_sock != 0)
689			if (udp_check_for_data(udp_sock) < 0)
690			{
691				close(udp_sock);
692				udp_sock = 0;
693			}
694	}
695	if (output_file)
696	{
697		fclose(output_file);
698		output_file = NULL;
699	}
700	if (sock >= 0) {
701		close(sock);
702	}
703	if (udp_sock != 0)
704		close(udp_sock);
705
706	g_free(buffer);
707	g_free(url);
708
709	pthread_exit(NULL);
710	return NULL; /* avoid compiler warning */
711}
712
713int flac_http_open(const gchar * _url, guint64 _offset)
714{
715	gchar *url;
716
717	url = g_strdup(_url);
718
719	rd_index = 0;
720	wr_index = 0;
721	buffer_length = flac_cfg.stream.http_buffer_size * 1024;
722	prebuffer_length = (buffer_length * flac_cfg.stream.http_prebuffer) / 100;
723	buffer_read = 0;
724	icy_metaint = 0;
725	prebuffering = TRUE;
726	going = TRUE;
727	eof = FALSE;
728	buffer = g_malloc(buffer_length);
729	offset = _offset;
730
731	pthread_create(&thread, NULL, http_buffer_loop, url);
732
733	return 0;
734}
735
736char *flac_http_get_title(char *url)
737{
738	if (icy_name)
739		return g_strdup(icy_name);
740	if (g_basename(url) && strlen(g_basename(url)) > 0)
741		return g_strdup(g_basename(url));
742	return g_strdup(url);
743}
744
745/* Start UDP Channel specific stuff */
746
747/* Find a good local udp port and bind udp_sock to it, return the port */
748static int udp_establish_listener(int *sock)
749{
750	struct sockaddr_in sin;
751	socklen_t sinlen = sizeof (struct sockaddr_in);
752
753#ifdef DEBUG_UDP
754	fprintf (stderr,"Establishing udp listener\n");
755#endif
756
757	if ((*sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
758	{
759		g_log(NULL, G_LOG_LEVEL_CRITICAL,
760		      "udp_establish_listener(): unable to create socket");
761		return -1;
762	}
763
764	memset(&sin, 0, sinlen);
765	sin.sin_family = AF_INET;
766	sin.sin_addr.s_addr = g_htonl(INADDR_ANY);
767
768	if (bind(*sock, (struct sockaddr *)&sin, sinlen) < 0)
769	{
770		g_log(NULL, G_LOG_LEVEL_CRITICAL,
771		      "udp_establish_listener():  Failed to bind socket to localhost: %s", strerror(errno));
772		close(*sock);
773		return -1;
774	}
775	if (fcntl(*sock, F_SETFL, O_NONBLOCK) < 0)
776	{
777		g_log(NULL, G_LOG_LEVEL_CRITICAL,
778		      "udp_establish_listener():  Failed to set flags: %s", strerror(errno));
779		close(*sock);
780		return -1;
781	}
782
783	memset(&sin, 0, sinlen);
784	if (getsockname(*sock, (struct sockaddr *)&sin, &sinlen) < 0)
785	{
786		g_log(NULL, G_LOG_LEVEL_CRITICAL,
787		      "udp_establish_listener():  Failed to retrieve socket info: %s", strerror(errno));
788		close(*sock);
789		return -1;
790	}
791
792#ifdef DEBUG_UDP
793	fprintf (stderr,"Listening on local %s:%d\n", inet_ntoa(sin.sin_addr), g_ntohs(sin.sin_port));
794#endif
795
796	return g_ntohs(sin.sin_port);
797}
798
799static int udp_check_for_data(int sock)
800{
801	char buf[1025], **lines;
802	char *valptr;
803	gchar *title;
804	gint len, i;
805	struct sockaddr_in from;
806	socklen_t fromlen;
807
808	fromlen = sizeof(struct sockaddr_in);
809
810	if ((len = recvfrom(sock, buf, 1024, 0, (struct sockaddr *)&from, &fromlen)) < 0)
811	{
812		if (errno != EAGAIN)
813		{
814			g_log(NULL, G_LOG_LEVEL_CRITICAL,
815			      "udp_read_data(): Error reading from socket: %s", strerror(errno));
816			return -1;
817		}
818		return 0;
819	}
820	buf[len] = '\0';
821#ifdef DEBUG_UDP
822	fprintf (stderr,"Received: [%s]\n", buf);
823#endif
824	lines = g_strsplit(buf, "\n", 0);
825	if (!lines)
826		return 0;
827
828	for (i = 0; lines[i]; i++)
829	{
830		while ((lines[i][strlen(lines[i]) - 1] == '\n') ||
831		       (lines[i][strlen(lines[i]) - 1] == '\r'))
832			lines[i][strlen(lines[i]) - 1] = '\0';
833
834		valptr = strchr(lines[i], ':');
835
836		if (!valptr)
837			continue;
838		else
839			valptr++;
840
841		g_strstrip(valptr);
842		if (!strlen(valptr))
843			continue;
844
845		if (strstr(lines[i], "x-audiocast-streamtitle") != NULL)
846		{
847			title = g_strdup_printf ("%s (%s)", valptr, icy_name);
848			if (going)
849				set_track_info(title, -1);
850			g_free (title);
851		}
852
853#if 0
854		else if (strstr(lines[i], "x-audiocast-streamlength") != NULL)
855		{
856			if (atoi(valptr) != -1)
857				set_track_info(NULL, atoi(valptr));
858		}
859#endif
860
861		else if (strstr(lines[i], "x-audiocast-streammsg") != NULL)
862		{
863			/* set_track_info(title, -1); */
864/*  			xmms_show_message(_("Message"), valptr, _("Ok"), */
865/*  					  FALSE, NULL, NULL); */
866			g_message("Stream_message: %s", valptr);
867		}
868
869#if 0
870		/* Use this to direct your webbrowser.. yeah right.. */
871		else if (strstr(lines[i], "x-audiocast-streamurl") != NULL)
872		{
873			if (lasturl && g_strcmp (valptr, lasturl))
874			{
875				c_message (stderr, "Song URL: %s\n", valptr);
876				g_free (lasturl);
877				lasturl = g_strdup (valptr);
878			}
879		}
880#endif
881		else if (strstr(lines[i], "x-audiocast-udpseqnr:") != NULL)
882		{
883			gchar obuf[60];
884			sprintf(obuf, "x-audiocast-ack: %ld \r\n", atol(valptr));
885			if (sendto(sock, obuf, strlen(obuf), 0, (struct sockaddr *) &from, fromlen) < 0)
886			{
887				g_log(NULL, G_LOG_LEVEL_WARNING,
888				      "udp_check_for_data(): Unable to send ack to server: %s", strerror(errno));
889			}
890#ifdef DEBUG_UDP
891			else
892				fprintf(stderr,"Sent ack: %s", obuf);
893			fprintf (stderr,"Remote: %s:%d\n", inet_ntoa(from.sin_addr), g_ntohs(from.sin_port));
894#endif
895		}
896	}
897	g_strfreev(lines);
898	return 0;
899}
900