changeset 10625:620cc649f519

ftp support. The change on connect2Server is needed bcs we need 2 different level of verbosity for control and data connections.
author albeu
date Fri, 15 Aug 2003 19:13:23 +0000
parents cdfd4a43c406
children fd97f3727f15
files configure libmpdemux/Makefile libmpdemux/asf_mmst_streaming.c libmpdemux/asf_streaming.c libmpdemux/network.c libmpdemux/network.h libmpdemux/stream.c libmpdemux/stream_ftp.c libmpdemux/stream_netstream.c
diffstat 9 files changed, 507 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/configure	Fri Aug 15 18:45:35 2003 +0000
+++ b/configure	Fri Aug 15 19:13:23 2003 +0000
@@ -172,6 +172,7 @@
   --disable-inet6        Disable IPv6 support [autodetect]
   --disable-gethostbyname2
                          gethostbyname() is not provided by the C library [autodetect]
+  --disable-ftp          Disable ftp support [enabled]
 Codecs:
   --enable-gif		 enable gif support [autodetect]
   --enable-png		 enable png input/output support [autodetect]
@@ -1139,6 +1140,7 @@
 _fribidiconfig='fribidi-config'
 _inet6=auto
 _gethostbyname2=auto
+_ftp=yes
 for ac_option do
   case "$ac_option" in
   # Skip 1st pass
@@ -1336,6 +1338,8 @@
   --disable-freetype)   _freetype=no    ;;
   --enable-unrarlib)	_unrarlib=yes	;;
   --disable-unrarlib)	_unrarlib=no	;;
+  --enable-ftp)         _ftp=yes        ;;
+  --disable-ftp)        _ftp=no         ;;
 
   --enable-fribidi)     _fribidi=yes    ;;
   --disable-fribidi)    _fribidi=no     ;;
@@ -4943,6 +4947,16 @@
 fi
 echores "$_network"
 
+echocheck "ftp"
+if test "$_ftp" != no ; then
+  _def_ftp='#define HAVE_FTP 1'
+  _inputmodules="ftp $_inputmodules"
+else
+  _noinputmodules="ftp $_noinputmodules"
+  _def_ftp='#undef HAVE_FTP'
+fi
+echores "$_ftp"
+
 # endian testing
 echocheck "byte order"
 if test "$_big_endian" = auto ; then
@@ -5914,6 +5928,9 @@
 /* enable network */
 $_def_network
 
+/* enable ftp support */
+$_def_ftp
+
 /* enable winsock2 instead of Unix functions*/
 $_def_winsock2
 
--- a/libmpdemux/Makefile	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/Makefile	Fri Aug 15 19:13:23 2003 +0000
@@ -3,7 +3,7 @@
 
 include ../config.mak
 
-SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c
+SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_ty.c demux_ty_osd.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c stream_file.c stream_netstream.c stream_vcd.c stream_null.c stream_ftp.c tv.c tvi_dummy.c tvi_v4l.c tvi_v4l2.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c demux_rawvideo.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c cue_read.c extension.c demux_gif.c demux_ts.c demux_realaud.c
 ifeq ($(XMMS_PLUGINS),yes)
 SRCS += demux_xmms.c
 endif 
--- a/libmpdemux/asf_mmst_streaming.c	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/asf_mmst_streaming.c	Fri Aug 15 19:13:23 2003 +0000
@@ -447,7 +447,7 @@
   path = strchr(url1->file,'/') + 1;
 
   url1->port=1755;
-  s = connect2Server( url1->hostname, url1->port );
+  s = connect2Server( url1->hostname, url1->port, 1);
   if( s<0 ) {
 	  return s;
   }
--- a/libmpdemux/asf_streaming.c	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/asf_streaming.c	Fri Aug 15 19:13:23 2003 +0000
@@ -656,7 +656,7 @@
 		} else {
 			if( url->port==0 ) url->port = 80;
 		}
-		fd = connect2Server( url->hostname, url->port );
+		fd = connect2Server( url->hostname, url->port, 1);
 		if( fd<0 ) return fd;
 
 		http_hdr = asf_http_request( stream->streaming_ctrl );
--- a/libmpdemux/network.c	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/network.c	Fri Aug 15 19:13:23 2003 +0000
@@ -184,7 +184,7 @@
 // return -1 is unable to connect to a particular port
 
 int
-connect2Server_with_af(char *host, int port, int af) {
+connect2Server_with_af(char *host, int port, int af,int verb) {
 	int socket_server_fd;
 	int err, err_len;
 	int ret,count = 0;
@@ -236,7 +236,7 @@
 	if ( inet_addr(host)==INADDR_NONE )
 #endif
 	{
-		mp_msg(MSGT_NETWORK,MSGL_STATUS,"Resolving %s for %s...\n", host, af2String(af));
+		if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,"Resolving %s for %s...\n", host, af2String(af));
 		
 #ifdef HAVE_GETHOSTBYNAME2
 		hp=(struct hostent*)gethostbyname2( host, af );
@@ -244,7 +244,7 @@
 		hp=(struct hostent*)gethostbyname( host );
 #endif
 		if( hp==NULL ) {
-			mp_msg(MSGT_NETWORK,MSGL_ERR,"Couldn't resolve name for %s: %s\n", af2String(af), host);
+			if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,"Couldn't resolve name for %s: %s\n", af2String(af), host);
 			return -2;
 		}
 		
@@ -280,7 +280,7 @@
 #else
 	inet_ntop(af, our_s_addr, buf, 255);
 #endif
-	mp_msg(MSGT_NETWORK,MSGL_STATUS,"Connecting to server %s[%s]:%d ...\n", host, buf , port );
+	if(verb) mp_msg(MSGT_NETWORK,MSGL_STATUS,"Connecting to server %s[%s]:%d ...\n", host, buf , port );
 
 	// Turn the socket as non blocking so we can timeout on the connection
 #ifndef HAVE_WINSOCK2
@@ -295,7 +295,7 @@
 #else
 		if( (WSAGetLastError() != WSAEINPROGRESS) && (WSAGetLastError() != WSAEWOULDBLOCK) ) {
 #endif
-			mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server with %s\n", af2String(af));
+			if(verb) mp_msg(MSGT_NETWORK,MSGL_ERR,"Failed to connect to server with %s\n", af2String(af));
 			closesocket(socket_server_fd);
 			return -1;
 		}
@@ -350,19 +350,19 @@
 
 
 int
-connect2Server(char *host, int  port) {
+connect2Server(char *host, int  port, int verb) {
 #ifdef HAVE_AF_INET6
 	int r;
 	int s = -2;
 
-	r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6);	
+	r = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET:AF_INET6,verb);	
 	if (r > -1) return r;
 
-	s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET);
+	s = connect2Server_with_af(host, port, network_prefer_ipv4 ? AF_INET6:AF_INET,verb);
 	if (s == -2) return r;
 	return s;
 #else	
-	return connect2Server_with_af(host, port, AF_INET);
+	return connect2Server_with_af(host, port, AF_INET,verb);
 #endif
 
 	
@@ -452,11 +452,11 @@
 
 	if( proxy ) {
 		if( url->port==0 ) url->port = 8080;			// Default port for the proxy server
-		fd = connect2Server( url->hostname, url->port );
+		fd = connect2Server( url->hostname, url->port,1 );
 		url_free( server_url );
 	} else {
 		if( server_url->port==0 ) server_url->port = 80;	// Default port for the web server
-		fd = connect2Server( server_url->hostname, server_url->port );
+		fd = connect2Server( server_url->hostname, server_url->port,1 );
 	}
 	if( fd<0 ) {
 		return -1; 
@@ -785,7 +785,7 @@
 					return -1;
 			}
 		} else {
-			mp_msg(MSGT_NETWORK,MSGL_ERR,"Unknown protocol '%s'\n", url->protocol );
+			mp_msg(MSGT_NETWORK,MSGL_V,"Unknown protocol '%s'\n", url->protocol );
 			return -1;
 		}
 	} while( redirect );
@@ -916,7 +916,7 @@
 	if( stream==NULL ) return -1;
 
 	fd = connect2Server( stream->streaming_ctrl->url->hostname,
-	    stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070 );
+	    stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 7070,1 );
 	printf("PNM:// fd=%d\n",fd);
 	if(fd<0) return -1;
 	
@@ -957,7 +957,7 @@
 		redirected = 0;
 
 		fd = connect2Server( stream->streaming_ctrl->url->hostname,
-			port = (stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 554) );
+			port = (stream->streaming_ctrl->url->port ? stream->streaming_ctrl->url->port : 554),1 );
 		if(fd<0) return -1;
 		
 		mrl = malloc(sizeof(char)*(strlen(stream->streaming_ctrl->url->hostname)+strlen(stream->streaming_ctrl->url->file)+16));
--- a/libmpdemux/network.h	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/network.h	Fri Aug 15 19:13:23 2003 +0000
@@ -51,7 +51,7 @@
 int nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl );
 int nop_streaming_seek( int fd, off_t pos, streaming_ctrl_t *stream_ctrl );
 
-int connect2Server(char *host, int port);
+int connect2Server(char *host, int port,int verb);
 
 int http_send_request(URL_t *url);
 HTTP_header_t *http_read_response(int fd);
--- a/libmpdemux/stream.c	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/stream.c	Fri Aug 15 19:13:23 2003 +0000
@@ -61,6 +61,9 @@
 #ifdef HAS_DVBIN_SUPPORT
 extern stream_info_t stream_info_dvb;
 #endif
+#ifdef HAVE_FTP
+extern stream_info_t stream_info_ftp;
+#endif
 
 extern stream_info_t stream_info_null;
 extern stream_info_t stream_info_file;
@@ -78,7 +81,9 @@
 #ifdef HAS_DVBIN_SUPPORT
   &stream_info_dvb,
 #endif
-
+#ifdef HAVE_FTP
+  &stream_info_ftp,
+#endif
   &stream_info_null,
   &stream_info_file,
   NULL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libmpdemux/stream_ftp.c	Fri Aug 15 19:13:23 2003 +0000
@@ -0,0 +1,465 @@
+
+#include "config.h"
+
+#ifdef HAVE_FTP
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "mp_msg.h"
+#include "stream.h"
+#include "help_mp.h"
+#include "../m_option.h"
+#include "../m_struct.h"
+
+static struct stream_priv_s {
+  char* user;
+  char* pass;
+  char* host;
+  int port;
+  char* filename;
+
+  char *cput,*cget;
+  int handle;
+  int cavail,cleft;
+  char *buf;
+} stream_priv_dflts = {
+  "anonymous","no@spam",
+  NULL,
+  21,
+  NULL,
+  NULL,
+  NULL,
+
+  0,
+  0,0,
+  NULL
+};
+
+#define BUFSIZE 2048
+
+#define ST_OFF(f) M_ST_OFF(struct stream_priv_s,f)
+/// URL definition
+static m_option_t stream_opts_fields[] = {
+  {"username", ST_OFF(user), CONF_TYPE_STRING, 0, 0 ,0, NULL},
+  {"password", ST_OFF(pass), CONF_TYPE_STRING, 0, 0 ,0, NULL},
+  {"hostname", ST_OFF(host), CONF_TYPE_STRING, 0, 0 ,0, NULL},
+  {"port", ST_OFF(port), CONF_TYPE_INT, 0, 0 ,65635, NULL},
+  {"filename", ST_OFF(filename), CONF_TYPE_STRING, 0, 0 ,0, NULL},
+  { NULL, NULL, 0, 0, 0, 0,  NULL }
+};
+static struct m_struct_st stream_opts = {
+  "ftp",
+  sizeof(struct stream_priv_s),
+  &stream_priv_dflts,
+  stream_opts_fields
+};
+
+#define TELNET_IAC      255             /* interpret as command: */
+#define TELNET_IP       244             /* interrupt process--permanently */
+#define TELNET_SYNCH    242             /* for telfunc calls */
+
+/*
+ * read a line of text
+ *
+ * return -1 on error or bytecount
+ */
+static int readline(char *buf,int max,struct stream_priv_s *ctl)
+{
+    int x,retval = 0;
+    char *end,*bp=buf;
+    int eof = 0;
+ 
+    do {
+      if (ctl->cavail > 0) {
+	x = (max >= ctl->cavail) ? ctl->cavail : max-1;
+	end = memccpy(bp,ctl->cget,'\n',x);
+	if (end != NULL)
+	  x = end - bp;
+	retval += x;
+	bp += x;
+	*bp = '\0';
+	max -= x;
+	ctl->cget += x;
+	ctl->cavail -= x;
+	if (end != NULL) {
+	  bp -= 2;
+	  if (strcmp(bp,"\r\n") == 0) {
+	    *bp++ = '\n';
+	    *bp++ = '\0';
+	    --retval;
+	  }
+	  break;
+	}
+      }
+      if (max == 1) {
+	*buf = '\0';
+	break;
+      }
+      if (ctl->cput == ctl->cget) {
+	ctl->cput = ctl->cget = ctl->buf;
+	ctl->cavail = 0;
+	ctl->cleft = BUFSIZE;
+      }
+      if(eof) {
+	if (retval == 0)
+	  retval = -1;
+	break;
+      }
+      if ((x = recv(ctl->handle,ctl->cput,ctl->cleft,0)) == -1) {
+	mp_msg(MSGT_STREAM,MSGL_ERR, "[ftp] read error: %s\n",strerror(errno));
+	retval = -1;
+	break;
+      }
+      if (x == 0)
+	eof = 1;
+      ctl->cleft -= x;
+      ctl->cavail += x;
+      ctl->cput += x;
+    } while (1);
+    
+    return retval;
+}
+
+/*
+ * read a response from the server
+ *
+ * return 0 if first char doesn't match
+ * return 1 if first char matches
+ */
+static int readresp(struct stream_priv_s* ctl,char* rsp)
+{
+    static char response[256];
+    char match[5];
+    int r;
+
+    if (readline(response,256,ctl) == -1)
+      return 0;
+ 
+    r = atoi(response)/100;
+    if(rsp) strcpy(rsp,response);
+
+    mp_msg(MSGT_STREAM,MSGL_V, "[ftp] < %s",response);
+
+    if (response[3] == '-') {
+      strncpy(match,response,3);
+      match[3] = ' ';
+      match[4] = '\0';
+      do {
+	if (readline(response,256,ctl) == -1) {
+	  mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Control socket read failed\n");
+	  return 0;
+	}
+	mp_msg(MSGT_OPEN,MSGL_V, "[ftp] < %s",response);
+      }	while (strncmp(response,match,4));
+    }
+    return r;
+}
+
+
+static int FtpSendCmd(const char *cmd, struct stream_priv_s *nControl,char* rsp)
+{
+  int l = strlen(cmd);
+
+  mp_msg(MSGT_STREAM,MSGL_V, "[ftp] > %s",cmd);
+  while(l > 0) {
+    int s = send(nControl->handle,cmd,l,0);
+
+    if(s <= 0) {
+      mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] write error: %s\n",strerror(errno));
+      return 0;
+    }
+    
+    cmd += s;
+    l -= s;
+  }
+    
+  return readresp(nControl,rsp);
+}
+
+static int FtpOpenPort(struct stream_priv_s* p) {
+  int resp,fd;
+  char rsp_txt[256];
+  char* par,str[128];
+  int num[6];
+
+  resp = FtpSendCmd("PASV\r\n",p,rsp_txt);
+  if(resp != 2) {
+    mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'PASV' failed: %s\n",rsp_txt);
+    return 0;
+  }
+  
+  par = strchr(rsp_txt,'(');
+  
+  if(!par || !par[0] || !par[1]) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] invalid server response: %s ??\n",rsp_txt);
+    return 0;
+  }
+
+  sscanf(par+1,"%u,%u,%u,%u,%u,%u",&num[0],&num[1],&num[2],
+	 &num[3],&num[4],&num[5]);
+  snprintf(str,127,"%d.%d.%d.%d",num[0],num[1],num[2],num[3]);
+  fd = connect2Server(str,(num[4]<<8)+num[5],0);
+
+  if(fd <= 0) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] failed to create data connection\n");
+    return 0;
+  }
+
+  return fd;
+}
+
+static int fill_buffer(stream_t *s, char* buffer, int max_len){
+  fd_set fds;
+  struct timeval tv;
+  int r;
+
+  // Check if there is something to read. This avoid hang
+  // forever if the network stop responding.
+  FD_ZERO(&fds);
+  FD_SET(s->fd,&fds);
+  tv.tv_sec = 15;
+  tv.tv_usec = 0;
+
+  if(select(s->fd+1, &fds, NULL, NULL, &tv) < 1) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] read timed out\n");
+    return -1;
+  }
+
+  r = recv(s->fd,buffer,max_len,0);
+  return (r <= 0) ? -1 : r;
+}
+
+static int seek(stream_t *s,off_t newpos) {
+  struct stream_priv_s* p = s->priv;
+  int resp;
+  char str[256],rsp_txt[256];
+  fd_set fds;
+  struct timeval tv;
+
+  if(s->pos > s->end_pos) {
+    s->eof=1;
+    return 0;
+  }
+
+  FD_ZERO(&fds);
+  FD_SET(p->handle,&fds);
+  tv.tv_sec = tv.tv_usec = 0;
+
+  // Check to see if the server doesn't alredy terminated the transfert
+  if(select(p->handle+1, &fds, NULL, NULL, &tv) > 0) {
+    if(readresp(p,rsp_txt) != 2)
+      mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] Warning the server didn't finished the transfert correctly: %s\n",rsp_txt);
+    close(s->fd);
+    s->fd = -1;
+  }
+
+  // Close current download
+  if(s->fd >= 0) {
+    static const char pre_cmd[]={TELNET_IAC,TELNET_IP,TELNET_IAC,TELNET_SYNCH};
+    //int fl;
+    
+    // First close the fd
+    close(s->fd);
+    s->fd = 0;
+    
+    // Send send the telnet sequence needed to make the server react
+    
+    // Dunno if this is really needed, lftp have it. I let
+    // it here in case it turn out to be needed on some other OS
+    //fl=fcntl(p->handle,F_GETFL);
+    //fcntl(p->handle,F_SETFL,fl&~O_NONBLOCK);
+
+    // send only first byte as OOB due to OOB braindamage in many unices
+    send(p->handle,pre_cmd,1,MSG_OOB);
+    send(p->handle,pre_cmd+1,sizeof(pre_cmd)-1,0);
+    
+    //fcntl(p->handle,F_SETFL,fl);
+
+    // Get the 426 Transfer aborted
+    // Or the 226 Transfer complete
+    resp = readresp(p,rsp_txt);
+    if(resp != 4 && resp != 2) {
+      mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Server didn't abort correctly: %s\n",rsp_txt);
+      s->eof = 1;
+      return 0;
+    }
+    // Send the ABOR command
+    // Ignore the return code as sometimes it fail with "nothing to abort"
+    FtpSendCmd("ABOR\n\r",p,rsp_txt);
+  }
+
+  // Open a new connection
+  s->fd = FtpOpenPort(p);
+
+  if(!s->fd) return 0;
+
+  if(newpos > 0) {
+#ifdef _LARGEFILE_SOURCE
+    snprintf(str,255,"REST %lld\r\n",newpos);
+#else
+    snprintf(str,255,"REST %u\r\n",newpos);
+#endif 
+
+    resp = FtpSendCmd(str,p,rsp_txt);
+    if(resp != 3) {
+      mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+      newpos = 0;
+    }
+  }
+
+  // Get the file
+  snprintf(str,255,"RETR %s\r\n",p->filename);
+  resp = FtpSendCmd(str,p,rsp_txt);
+
+  if(resp != 1) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+    return 0;
+  }
+
+  s->pos = newpos;
+  return 1;
+}
+
+
+static void close_f(stream_t *s) {
+  struct stream_priv_s* p = s->priv;
+
+  if(!p) return;
+
+  if(s->fd > 0) {
+    close(s->fd);
+    s->fd = 0;
+  }
+
+  FtpSendCmd("QUIT\r\n",p,NULL);
+
+  if(p->handle) close(p->handle);
+  if(p->buf) free(p->buf);
+
+  m_struct_free(&stream_opts,p);
+}
+
+
+
+static int open_f(stream_t *stream,int mode, void* opts, int* file_format) {
+  int len = 0,resp;
+  struct stream_priv_s* p = (struct stream_priv_s*)opts;
+  char str[256],rsp_txt[256];
+
+  if(mode != STREAM_READ) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Unknown open mode %d\n",mode);
+    m_struct_free(&stream_opts,opts);
+    return STREAM_UNSUPORTED;
+  }
+
+  if(!p->filename || !p->host) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] Bad url\n");
+    m_struct_free(&stream_opts,opts);
+    return STREAM_ERROR;
+  }
+
+  // Open the control connection
+  p->handle = connect2Server(p->host,p->port,1);
+  
+  if(p->handle < 0) {
+    m_struct_free(&stream_opts,opts);
+    return STREAM_ERROR;
+  }
+
+  // We got a connection, let's start serious things
+  stream->fd = -1;
+  stream->priv = p;
+  p->buf = malloc(BUFSIZE);
+
+  if (readresp(p, NULL) == 0) {
+    close_f(stream);
+    m_struct_free(&stream_opts,opts);
+    return STREAM_ERROR;
+  }
+
+  // Login
+  snprintf(str,255,"USER %s\r\n",p->user);
+  resp = FtpSendCmd(str,p,rsp_txt);
+
+  // password needed
+  if(resp == 3) {
+    snprintf(str,255,"PASS %s\r\n",p->pass);
+    resp = FtpSendCmd(str,p,rsp_txt);
+    if(resp != 2) {
+      mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+      close_f(stream);
+      return STREAM_ERROR;
+    }
+  } else if(resp != 2) {
+    mp_msg(MSGT_OPEN,MSGL_ERR, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+    close_f(stream);
+    return STREAM_ERROR;
+  }
+    
+  // Set the transfert type
+  resp = FtpSendCmd("TYPE I\r\n",p,rsp_txt);
+  if(resp != 2) {
+    mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command 'TYPE I' failed: %s\n",rsp_txt);
+    close_f(stream);
+    return STREAM_ERROR;
+  }
+
+  // Get the filesize
+  snprintf(str,255,"SIZE %s\r\n",p->filename);
+  resp = FtpSendCmd(str,p,rsp_txt);
+  if(resp != 2) {
+    mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+  } else {
+    int dummy;
+    sscanf(rsp_txt,"%d %d",&dummy,&len);
+  }
+
+  // Start the data connection
+  stream->fd = FtpOpenPort(p);
+  if(stream->fd <= 0) {
+    close_f(stream);
+    return STREAM_ERROR;
+  }
+
+  // Get the file
+  snprintf(str,255,"RETR %s\r\n",p->filename);
+  resp = FtpSendCmd(str,p,rsp_txt);
+
+  if(resp != 1) {
+    mp_msg(MSGT_OPEN,MSGL_WARN, "[ftp] command '%s' failed: %s\n",str,rsp_txt);
+    close_f(stream);
+    return STREAM_ERROR;
+  }
+  
+
+  if(len > 0) {
+    stream->seek = seek;
+    stream->end_pos = len;
+  }
+
+  stream->priv = p;
+  stream->fill_buffer = fill_buffer;
+  stream->close = close_f;
+
+  return STREAM_OK;
+}
+
+stream_info_t stream_info_ftp = {
+  "File Transfer Protocol",
+  "ftp",
+  "Albeu",
+  "reuse a bit of code from ftplib written by Thomas Pfau",
+  open_f,
+  { "ftp", NULL },
+  &stream_opts,
+  1 // Urls are an option string
+};
+
+#endif
--- a/libmpdemux/stream_netstream.c	Fri Aug 15 18:45:35 2003 +0000
+++ b/libmpdemux/stream_netstream.c	Fri Aug 15 19:13:23 2003 +0000
@@ -252,7 +252,7 @@
     return STREAM_ERROR;
   }
 
-  f = connect2Server(p->host,p->port);
+  f = connect2Server(p->host,p->port,1);
   if(f < 0) {
     mp_msg(MSGT_OPEN,MSGL_ERR, "Connection to %s:%d failed\n",p->host,p->port);
     m_struct_free(&stream_opts,opts);