changeset 1407:b94847e68f33 trunk

[svn] Newer libmms, from their CVS. Needs to be hooked up properly as it wants more arguments to its functions.
author chainsaw
date Sat, 15 Jul 2006 16:39:37 -0700
parents f40d0496fda5
children 8accd819fa5e
files ChangeLog Plugins/Input/wma/libffwma/mms.c Plugins/Input/wma/libffwma/mms.h Plugins/Input/wma/libffwma/mmsio.h
diffstat 4 files changed, 1468 insertions(+), 611 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sat Jul 15 16:05:21 2006 -0700
+++ b/ChangeLog	Sat Jul 15 16:39:37 2006 -0700
@@ -1,3 +1,11 @@
+2006-07-15 23:05:21 +0000  Tony Vroon <chainsaw@gentoo.org>
+  revision [1726]
+  Volume fix (using a lookup table) from upstream CVS.
+
+  Changes:        Modified:
+  +16 -0          trunk/Plugins/Input/adplug/core/amd.cpp  
+
+
 2006-07-14 21:07:10 +0000  Giacomo Lozito <james@develia.org>
   revision [1724]
   - libconsole: added an option to ignore length information from spc tags
--- a/Plugins/Input/wma/libffwma/mms.c	Sat Jul 15 16:05:21 2006 -0700
+++ b/Plugins/Input/wma/libffwma/mms.c	Sat Jul 15 16:39:37 2006 -0700
@@ -1,14 +1,14 @@
-/* 
- * Copyright (C) 2000-2001 major mms
+/*
+ * Copyright (C) 2002-2004 the xine project
  * 
- * This file is part of libmms
+ * This file is part of LibMMS, an MMS protocol handling library.
  * 
- * libmms is free software; you can redistribute it and/or modify
+ * xine is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the ree Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  * 
- * libmms is distributed in the hope that it will be useful,
+ * xine is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
@@ -17,18 +17,23 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  *
- * utility functions to handle communication with an mms server
+ * $Id: mms.c,v 1.21 2006/07/13 12:32:20 shawarma Exp $
+ *
+ * MMS over TCP protocol
+ *   based on work from major mms
+ *   utility functions to handle communication with an mms server
+ *
+ * TODO:
+ *   error messages
+ *   enable seeking !
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <glib.h>
-
 #include <unistd.h>
 #include <stdio.h>
-#include <assert.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netdb.h>
@@ -38,776 +43,1509 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <time.h>
 
-#include "avcodec.h"
+#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_CODESET)
+#define USE_ICONV
+#include <iconv.h>
+#include <locale.h>
+#include <langinfo.h>
+#endif
+
+/********** logging **********/
+#define LOG_MODULE "mms"
+#define LOG_VERBOSE
+#ifdef DEBUG
+# define lprintf printf
+#else
+# define lprintf(x...)
+#endif
+
+
 #include "bswap.h"
 #include "mms.h"
+#include "asfheader.h"
+#include "uri.h"
 
-#define LOG
 
 /* 
  * mms specific types 
  */
 
-#define MMS_PORT 1755
+#define MMST_PORT 1755
 
 #define BUF_SIZE 102400
 
-#define CMD_HEADER_LEN   48
+#define CMD_HEADER_LEN   40
+#define CMD_PREFIX_LEN    8
 #define CMD_BODY_LEN   1024
 
+#define ASF_HEADER_LEN 8192
+
+
+#define MMS_PACKET_ERR        0
+#define MMS_PACKET_COMMAND    1
+#define MMS_PACKET_ASF_HEADER 2
+#define MMS_PACKET_ASF_PACKET 3
+
+#define ASF_HEADER_PACKET_ID_TYPE 2
+#define ASF_MEDIA_PACKET_ID_TYPE  4
+
+
+typedef struct mms_buffer_s mms_buffer_t;
+struct mms_buffer_s {
+  uint8_t *buffer;
+  int pos;
+};
+
+typedef struct mms_packet_header_s mms_packet_header_t;
+struct mms_packet_header_s {
+  uint32_t  packet_len;
+  uint8_t   flags;
+  uint8_t   packet_id_type;
+  uint32_t  packet_seq;
+};
+
+
 struct mms_s {
 
+  /* FIXME: de-xine-ification */
+  void *custom_data;
+  
   int           s;
-
+  
+  /* url parsing */
+  char         *url;
+  char         *proto;
   char         *host;
-  char         *path;
-  char         *file;
-  char         *url;
+  int           port;
+  char         *user;
+  char         *password;
+  char         *uri;
 
   /* command to send */
-  char          scmd[CMD_HEADER_LEN+CMD_BODY_LEN];
+  char          scmd[CMD_HEADER_LEN + CMD_BODY_LEN];
   char         *scmd_body; /* pointer to &scmd[CMD_HEADER_LEN] */
   int           scmd_len; /* num bytes written in header */
-
+  
   char          str[1024]; /* scratch buffer to built strings */
-
+  
   /* receive buffer */
-  char          buf[BUF_SIZE];
+  uint8_t       buf[BUF_SIZE];
   int           buf_size;
   int           buf_read;
-
-  uint8_t       asf_header[8192];
-  int           asf_header_len;
-  int           asf_header_read;
+  
+  uint8_t       asf_header[ASF_HEADER_LEN];
+  uint32_t      asf_header_len;
+  uint32_t      asf_header_read;
   int           seq_num;
   int           num_stream_ids;
-  int           stream_ids[20];
-  int           packet_length;
-
+  int           stream_ids[ASF_MAX_NUM_STREAMS];
+  int           stream_types[ASF_MAX_NUM_STREAMS];
+  off_t         start_packet_seq; /* for live streams != 0, need to keep it around */
+  int           need_discont; /* whether we need to set start_packet_seq */
+  uint32_t      asf_packet_len;
+  uint64_t      file_len;
+  char          guid[37];
+  uint32_t      bitrates[ASF_MAX_NUM_STREAMS];
+  uint32_t      bitrates_pos[ASF_MAX_NUM_STREAMS];
+  int           bandwidth;
+  
+  int           has_audio;
+  int           has_video;
+  int           live_flag;
+  off_t         current_pos;
+  int           eos;
 };
 
-/* network/socket utility functions */
-
-static int host_connect_attempt(struct in_addr ia, int port) {
+static int fallback_io_select(void *data, int socket, int state, int timeout_msec)
+{
+  fd_set set;
+  struct timeval tv = { timeout_msec / 1000, (timeout_msec % 1000) * 1000};
+  FD_ZERO(&set);
+  FD_SET(socket, &set);
+  return select(1, (state == MMS_IO_READ_READY) ? &set : NULL,
+		       (state == MMS_IO_WRITE_READY) ? &set : NULL, NULL, &tv);
+}
 
-  int                s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-  struct sockaddr_in sin;
+static off_t fallback_io_read(void *data, int socket, char *buf, off_t num)
+{
+  off_t len = 0, ret;
+/*   lprintf("%d\n", fallback_io_select(data, socket, MMS_IO_READ_READY, 1000)); */
+  errno = 0;
+  while (len < num)
+  {
+    ret = (off_t)read(socket, buf + len, num - len);
+    if(ret == 0)
+      break; /* EOF */
+    if(ret < 0)
+      switch(errno)
+      {
+	  case EAGAIN:
+	    lprintf("len == %lld\n", (long long int) len);
+	    break;
+	  default:
+	    lprintf("len == %lld\n", (long long int) len);
+	    perror(NULL);
+	    /* if already read something, return it, we will fail next time */
+	    return len ? len : ret; 
+      }
+    len += ret;
+  }
+  lprintf("ret len == %lld\nnum == %lld\n", (long long int) len, (long long int) num);
+  return len;
+}
+
+static off_t fallback_io_write(void *data, int socket, char *buf, off_t num)
+{
+  return (off_t)write(socket, buf, num);
+}
+
+static int fallback_io_tcp_connect(void *data, const char *host, int port)
+{
   
-  if (s==-1) {
-    printf ("libmms: socket(): %s\n", strerror(errno));
+  struct hostent *h;
+  int i, s;
+  
+  h = gethostbyname(host);
+  if (h == NULL) {
+/*     fprintf(stderr, "unable to resolve host: %s\n", host); */
+    return -1;
+  }
+
+  s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  
+  if (s == -1) {
+/*     fprintf(stderr, "failed to create socket: %s", strerror(errno)); */
+    return -1;
+  }
+
+  if (fcntl (s, F_SETFL, fcntl (s, F_GETFL) & ~O_NONBLOCK) == -1) {
+/*     _x_message(stream, XINE_MSG_CONNECTION_REFUSED, "can't put socket in non-blocking mode", strerror(errno), NULL); */
     return -1;
   }
 
-  sin.sin_family = AF_INET;	
-  sin.sin_addr   = ia;
-  sin.sin_port   = htons(port);
-  
-  if (connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1 
-      && errno != EINPROGRESS) {
-    printf ("libmms: connect(): %s\n", strerror(errno));
-    close(s);
-    return -1;
-  }	
-	
-  return s;
-}
-
-static int host_connect(const char *host, int port) {
+  for (i = 0; h->h_addr_list[i]; i++) {
+    struct in_addr ia;
+    struct sockaddr_in sin;
+ 
+    memcpy (&ia, h->h_addr_list[i], 4);
+    sin.sin_family = AF_INET;
+    sin.sin_addr   = ia;
+    sin.sin_port   = htons(port);
+    
+    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) ==-1 && errno != EINPROGRESS) {
 
-  struct hostent *h;
-  int i, s;
-  
-  h=gethostbyname(host);
-  if (h==NULL) {
-    printf ("libmms: unable to resolve '%s'.\n", host);
-    return -1;
+      /* FIXME: de-xine-ification */
+/*       _x_message(stream, XINE_MSG_CONNECTION_REFUSED, strerror(errno), NULL); */
+      close(s);
+      continue;
+    }
+    
+    return s;
   }
-	
-  for (i=0; h->h_addr_list[i]; i++) {
-    struct in_addr ia;
-    memcpy (&ia, h->h_addr_list[i],4);
-    s = host_connect_attempt(ia, port);
-    if(s != -1)
-      return s;
-  }
-  printf ("libmms: unable to connect to '%s'.\n", host);
   return -1;
 }
 
-static void put_32 (mms_t *this, uint32_t value) {
+
+static mms_io_t fallback_io =
+  {
+    &fallback_io_select,
+    NULL,
+    &fallback_io_read,
+    NULL,
+    &fallback_io_write,
+    NULL,
+    &fallback_io_tcp_connect,
+    NULL,
+  };
+
+static mms_io_t default_io =   {
+    &fallback_io_select,
+    NULL,
+    &fallback_io_read,
+    NULL,
+    &fallback_io_write,
+    NULL,
+    &fallback_io_tcp_connect,
+    NULL,
+  };
+
+
+#define io_read(io, args...) ((io) ? (io)->read(io->read_data , ## args) : default_io.read(NULL , ## args))
+#define io_write(io, args...) ((io) ? (io)->write(io->write_data , ## args) : default_io.write(NULL , ## args))
+#define io_select(io, args...) ((io) ? (io)->select(io->select_data , ## args) : default_io.select(NULL , ## args))
+#define io_connect(io, args...) ((io) ? (io)->connect(io->connect_data , ## args) : default_io.connect(NULL , ## args))
+  
+const mms_io_t* mms_get_default_io_impl()
+{
+  return &default_io;
+}
 
-  this->scmd[this->scmd_len  ] = value % 256;
-  value = value >> 8;
-  this->scmd[this->scmd_len+1] = value % 256 ;
-  value = value >> 8;
-  this->scmd[this->scmd_len+2] = value % 256 ;
-  value = value >> 8;
-  this->scmd[this->scmd_len+3] = value % 256 ;
+void mms_set_default_io_impl(const mms_io_t *io)
+{
+  if(io->select)
+  {
+    default_io.select = io->select;
+    default_io.select_data = io->select_data;
+  } else
+  {
+    default_io.select = fallback_io.select;
+    default_io.select_data = fallback_io.select_data;
+  }
+  if(io->read)
+  {
+    default_io.read = io->read;
+    default_io.read_data = io->read_data;
+  } else
+  {
+    default_io.read = fallback_io.read;
+    default_io.read_data = fallback_io.read_data;
+  }
+  if(io->write)
+  {
+    default_io.write = io->write;
+    default_io.write_data = io->write_data;
+  } else
+  {
+    default_io.write = fallback_io.write;
+    default_io.write_data = fallback_io.write_data;
+  }
+  if(io->connect)
+  {
+    default_io.connect = io->connect;
+    default_io.connect_data = io->connect_data;
+  } else
+  {
+    default_io.connect = fallback_io.connect;
+    default_io.connect_data = fallback_io.connect_data;
+  }
+}
 
-  this->scmd_len += 4;
+static void mms_buffer_init (mms_buffer_t *mms_buffer, uint8_t *buffer) {
+  mms_buffer->buffer = buffer;
+  mms_buffer->pos = 0;
+}
+
+static void mms_buffer_put_8 (mms_buffer_t *mms_buffer, uint8_t value) {
+
+  mms_buffer->buffer[mms_buffer->pos]     = value          & 0xff;
+
+  mms_buffer->pos += 1;
 }
 
-static int send_data (int s, char *buf, int len) {
-  int total;
+#if 0
+static void mms_buffer_put_16 (mms_buffer_t *mms_buffer, uint16_t value) {
+
+  mms_buffer->buffer[mms_buffer->pos]     = value          & 0xff;
+  mms_buffer->buffer[mms_buffer->pos + 1] = (value  >> 8)  & 0xff;
+
+  mms_buffer->pos += 2;
+}
+#endif
 
-  total=0;
-  while (total<len){ 
-    int n;
+static void mms_buffer_put_32 (mms_buffer_t *mms_buffer, uint32_t value) {
+
+  mms_buffer->buffer[mms_buffer->pos]     = value          & 0xff;
+  mms_buffer->buffer[mms_buffer->pos + 1] = (value  >> 8)  & 0xff;
+  mms_buffer->buffer[mms_buffer->pos + 2] = (value  >> 16) & 0xff;
+  mms_buffer->buffer[mms_buffer->pos + 3] = (value  >> 24) & 0xff;
+
+  mms_buffer->pos += 4;
+}
 
-    n = write (s, &buf[total], len-total);
-    if (n > 0)
-      total += n;
-    else if (n<0 && errno!=EAGAIN) 
-      return total;
+static int get_guid (unsigned char *buffer, int offset) {
+  int i;
+  GUID g;
+  
+  g.Data1 = LE_32(buffer + offset);
+  g.Data2 = LE_16(buffer + offset + 4);
+  g.Data3 = LE_16(buffer + offset + 6);
+  for(i = 0; i < 8; i++) {
+    g.Data4[i] = buffer[offset + 8 + i];
   }
-  return total;
+  
+  for (i = 1; i < GUID_END; i++) {
+    if (!memcmp(&g, &guids[i].guid, sizeof(GUID))) {
+      lprintf("GUID: %s\n", guids[i].name);
+      return i;
+    }
+  }
+  
+  lprintf("unknown GUID: 0x%x, 0x%x, 0x%x, "
+	   "{ 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx, 0x%hx }\n",
+	   g.Data1, g.Data2, g.Data3,
+	   g.Data4[0], g.Data4[1], g.Data4[2], g.Data4[3], 
+	   g.Data4[4], g.Data4[5], g.Data4[6], g.Data4[7]);
+
+  return GUID_ERROR;
 }
 
-static uint32_t get_32 (char *cmd, int offset) {
 
-  uint32_t ret;
+static void print_command (char *data, int len) {
 
-  ret = cmd[offset] ;
-  ret |= cmd[offset+1]<<8 ;
-  ret |= cmd[offset+2]<<16 ;
-  ret |= cmd[offset+3]<<24 ;
+#ifdef DEBUG
+  int i;
+  int dir = LE_32 (data + 36) >> 16;
+  int comm = LE_32 (data + 36) & 0xFFFF;
 
-  return ret;
-}
+  lprintf ("----------------------------------------------\n");
+  if (dir == 3) {
+    lprintf ("send command 0x%02x, %d bytes\n", comm, len);
+  } else {
+    lprintf ("receive command 0x%02x, %d bytes\n", comm, len);
+  }
+  lprintf ("  start sequence %08x\n", LE_32 (data +  0));
+  lprintf ("  command id     %08x\n", LE_32 (data +  4));
+  lprintf ("  length         %8x \n", LE_32 (data +  8));
+  lprintf ("  protocol       %08x\n", LE_32 (data + 12));
+  lprintf ("  len8           %8x \n", LE_32 (data + 16));
+  lprintf ("  sequence #     %08x\n", LE_32 (data + 20));
+  lprintf ("  len8  (II)     %8x \n", LE_32 (data + 32));
+  lprintf ("  dir | comm     %08x\n", LE_32 (data + 36));
+  if (len >= 4)
+    lprintf ("  prefix1        %08x\n", LE_32 (data + 40));
+  if (len >= 8)
+    lprintf ("  prefix2        %08x\n", LE_32 (data + 44));
 
-static void send_command (mms_t *this, int command, uint32_t switches, 
-			  uint32_t extra, int length) {
-  
-  int        len8;
-  int        i;
+  for (i = (CMD_HEADER_LEN + CMD_PREFIX_LEN); i < (CMD_HEADER_LEN + CMD_PREFIX_LEN + len); i += 1) {
+    unsigned char c = data[i];
+    
+    if ((c >= 32) && (c < 128))
+      lprintf ("%c", c);
+    else
+      lprintf (" %02x ", c);
+    
+  }
+  if (len > CMD_HEADER_LEN)
+    lprintf ("\n");
+  lprintf ("----------------------------------------------\n");
+#endif
+}  
 
-  len8 = (length + (length%8)) / 8;
+
+
+static int send_command (mms_io_t *io, mms_t *this, int command,
+                         uint32_t prefix1, uint32_t prefix2,
+                         int length) {
+  int    len8;
+  off_t  n;
+  mms_buffer_t command_buffer;
+
+  len8 = (length + 7) / 8;
 
   this->scmd_len = 0;
 
-  put_32 (this, 0x00000001); /* start sequence */
-  put_32 (this, 0xB00BFACE); /* #-)) */
-  put_32 (this, length + 32);
-  put_32 (this, 0x20534d4d); /* protocol type "MMS " */
-  put_32 (this, len8 + 4);
-  put_32 (this, this->seq_num); this->seq_num++;
-  put_32 (this, 0x0);        /* unknown */
-  put_32 (this, 0x0);
-  put_32 (this, len8+2);
-  put_32 (this, 0x00030000 | command); /* dir | command */
-  put_32 (this, switches);
-  put_32 (this, extra);
+  mms_buffer_init(&command_buffer, this->scmd);
+  mms_buffer_put_32 (&command_buffer, 0x00000001);   /* start sequence */
+  mms_buffer_put_32 (&command_buffer, 0xB00BFACE);   /* #-)) */
+  mms_buffer_put_32 (&command_buffer, len8 * 8 + 32);
+  mms_buffer_put_32 (&command_buffer, 0x20534d4d);   /* protocol type "MMS " */
+  mms_buffer_put_32 (&command_buffer, len8 + 4);
+  mms_buffer_put_32 (&command_buffer, this->seq_num);
+  this->seq_num++;
+  mms_buffer_put_32 (&command_buffer, 0x0);          /* timestamp */
+  mms_buffer_put_32 (&command_buffer, 0x0);
+  mms_buffer_put_32 (&command_buffer, len8 + 2);
+  mms_buffer_put_32 (&command_buffer, 0x00030000 | command); /* dir | command */
+  /* end of the 40 byte command header */
+  
+  mms_buffer_put_32 (&command_buffer, prefix1);
+  mms_buffer_put_32 (&command_buffer, prefix2);
+
+  if (length & 7)
+	  memset(this->scmd + length + CMD_HEADER_LEN + CMD_PREFIX_LEN, 0, 8 - (length & 7));
+
+  n = io_write(io,  this->s, this->scmd, len8 * 8 + CMD_HEADER_LEN + CMD_PREFIX_LEN);
+  if (n != (len8 * 8 + CMD_HEADER_LEN + CMD_PREFIX_LEN)) {
+    return 0;
+  }
+
+  print_command (this->scmd, length);
+
+  return 1;
+}
+
+#ifdef USE_ICONV
+static iconv_t string_utf16_open() {
+    return iconv_open("UTF-16LE", nl_langinfo(CODESET));
+}
 
-  /* memcpy (&cmd->buf[48], data, length); */
+static void string_utf16_close(iconv_t url_conv) {
+    if (url_conv != (iconv_t)-1) {
+      iconv_close(url_conv);
+    }
+}
+
+static void string_utf16(iconv_t url_conv, char *dest, char *src, int len) {
+    memset(dest, 0, 2 * len);
+
+    if (url_conv == (iconv_t)-1) {
+      int i;
 
-  if (send_data (this->s, this->scmd, length+48) != (length+48)) {
-    printf ("libmms: send error\n");
+      for (i = 0; i < len; i++) {
+        dest[i * 2] = src[i];
+        dest[i * 2 + 1] = 0;
+      }
+      dest[i * 2] = 0;
+      dest[i * 2 + 1] = 0;
+    }
+    else {
+      size_t len1, len2;
+      char *ip, *op;
+
+      len1 = len; len2 = 1000;
+      ip = src; op = dest;
+      iconv(url_conv, &ip, &len1, &op, &len2);
+    }
+}
+
+#else
+static void string_utf16(int unused, char *dest, char *src, int len) {
+  int i;
+
+  memset (dest, 0, 2 * len);
+
+  for (i = 0; i < len; i++) {
+    dest[i * 2] = src[i];
+    dest[i * 2 + 1] = 0;
   }
 
-#ifdef LOG
-  printf ("\nlibmms: ***************************************************\ncommand sent, %d bytes\n", length+48);
+  dest[i * 2] = 0;
+  dest[i * 2 + 1] = 0;
+}
+#endif
+
 
-  printf ("start sequence %08x\n", get_32 (this->scmd,  0));
-  printf ("command id     %08x\n", get_32 (this->scmd,  4));
-  printf ("length         %8x \n", get_32 (this->scmd,  8));
-  printf ("len8           %8x \n", get_32 (this->scmd, 16));
-  printf ("sequence #     %08x\n", get_32 (this->scmd, 20));
-  printf ("len8  (II)     %8x \n", get_32 (this->scmd, 32));
-  printf ("dir | comm     %08x\n", get_32 (this->scmd, 36));
-  printf ("switches       %08x\n", get_32 (this->scmd, 40));
+/*
+ * return packet type
+ */
+static int get_packet_header (mms_io_t *io, mms_t *this, mms_packet_header_t *header) {
+  size_t len;
+  int packet_type;
 
-  printf ("ascii contents>");
-  for (i=48; i<(length+48); i+=2) {
-    unsigned char c = this->scmd[i];
+  header->packet_len     = 0;
+  header->packet_seq     = 0;
+  header->flags          = 0;
+  header->packet_id_type = 0;
+  len = io_read(io,  this->s, this->buf, 8);
+  if (len != 8)
+    goto error;
 
-    if ((c>=32) && (c<=128))
-      printf ("%c", c);
-    else
-      printf (".");
+  if (LE_32(this->buf + 4) == 0xb00bface) {
+    /* command packet */
+    header->flags = this->buf[3];
+    len = io_read(io,  this->s, this->buf + 8, 4);
+    if (len != 4)
+      goto error;
+    
+    header->packet_len = LE_32(this->buf + 8) + 4;
+    if (header->packet_len > BUF_SIZE - 12) {
+        header->packet_len = 0;
+        goto error;
+    }
+    lprintf("mms command\n");
+    packet_type = MMS_PACKET_COMMAND;
+  } else {
+    header->packet_seq     = LE_32(this->buf);
+    header->packet_id_type = this->buf[4];
+    header->flags          = this->buf[5];
+    header->packet_len     = (LE_16(this->buf + 6) - 8) & 0xffff;
+    if (header->packet_id_type == ASF_HEADER_PACKET_ID_TYPE) {
+      lprintf("asf header\n");
+      packet_type = MMS_PACKET_ASF_HEADER;
+    } else {
+      lprintf("asf packet\n");
+      packet_type = MMS_PACKET_ASF_PACKET;
+    }
   }
-  printf ("\n");
-
-  printf ("libmms: complete hexdump of package follows:\n");
-  for (i=0; i<(length+48); i++) {
-    unsigned char c = this->scmd[i];
+  
+  return packet_type;
+  
+error:
+  lprintf("read error, len=%d\n", len);
+  perror("Could not read packet header");
+  return MMS_PACKET_ERR;
+}
 
-    printf ("%02x", c);
+
+static int get_packet_command (mms_io_t *io, mms_t *this, uint32_t packet_len) {
+
 
-    if ((i % 16) == 15)
-      printf ("\nlibmms: ");
+  int  command = 0;
+  size_t len;
+  
+  /* always enter this loop */
+  lprintf("packet_len: %d bytes\n", packet_len);
+
+  len = io_read(io,  this->s, this->buf + 12, packet_len) ;
+  if (len != packet_len) {
+    return 0;
+  }
 
-    if ((i % 2) == 1)
-      printf (" ");
+  print_command (this->buf, len);
+  
+  /* check protocol type ("MMS ") */
+  if (LE_32(this->buf + 12) != 0x20534D4D) {
+    lprintf("unknown protocol type: %c%c%c%c (0x%08X)\n",
+            this->buf[12], this->buf[13], this->buf[14], this->buf[15],
+            LE_32(this->buf + 12));  
+    return 0;
+  }
 
-  }
-  printf ("\n");
-#endif
+  command = LE_32 (this->buf + 36) & 0xFFFF;
+  lprintf("command = 0x%2x\n", command);
+    
+  return command;
 }
 
-static void string_utf16(char *dest, char *src, int len) {
-  int i;
-
-  memset (dest, 0, 1000);
+static int get_answer (mms_io_t *io, mms_t *this) {
+  int command = 0;
+  mms_packet_header_t header;
 
-  for (i=0; i<len; i++) {
-    dest[i*2] = src[i];
-    dest[i*2+1] = 0;
+  switch (get_packet_header (io, this, &header)) {
+    case MMS_PACKET_ERR:
+  /* FIXME: de-xine-ification */
+      lprintf( "***LOG:*** -- "
+	      "libmms: failed to read mms packet header\n");
+      break;
+    case MMS_PACKET_COMMAND:
+      command = get_packet_command (io, this, header.packet_len);
+      
+      if (command == 0x1b) {
+    
+        if (!send_command (io, this, 0x1b, 0, 0, 0)) {
+  /* FIXME: de-xine-ification */
+          lprintf( "***LOG:*** -- "
+		  "libmms: failed to send command\n");
+          return 0;
+        }
+        /* FIXME: limit recursion */
+        command = get_answer (io, this);
+      }
+      break;
+    case MMS_PACKET_ASF_HEADER:
+  /* FIXME: de-xine-ification */
+      lprintf( "***LOG:*** -- "
+	      "libmms: unexpected asf header packet\n");
+      break;
+    case MMS_PACKET_ASF_PACKET:
+  /* FIXME: de-xine-ification */
+      lprintf( "***LOG:*** -- "
+"libmms: unexpected asf packet\n");
+      break;
   }
-
-  dest[i*2] = 0;
-  dest[i*2+1] = 0;
+  
+  return command;
 }
 
-static void print_answer (char *data, int len) {
+
+static int get_asf_header (mms_io_t *io, mms_t *this) {
+
+  off_t len;
+  int stop = 0;
+  
+  this->asf_header_read = 0;
+  this->asf_header_len = 0;
+
+  while (!stop) {
+    mms_packet_header_t header;
+    int command;
 
-#ifdef LOG
+    switch (get_packet_header (io, this, &header)) {
+      case MMS_PACKET_ERR:
+  /* FIXME: de-xine-ification */
+        lprintf( "***LOG:*** -- "
+	       "libmms: failed to read mms packet header\n");
+        return 0;
+        break;
+      case MMS_PACKET_COMMAND:
+        command = get_packet_command (io, this, header.packet_len);
+      
+        if (command == 0x1b) {
+    
+          if (!send_command (io, this, 0x1b, 0, 0, 0)) {
+  /* FIXME: de-xine-ification */
+            lprintf( "***LOG:*** -- "
+		   "libmms: failed to send command\n");
+            return 0;
+          }
+          command = get_answer (io, this);
+        } else {
+  /* FIXME: de-xine-ification */
+          lprintf( "***LOG:*** -- "
+		 "libmms: unexpected command packet\n");
+        }
+        break;
+      case MMS_PACKET_ASF_HEADER:
+      case MMS_PACKET_ASF_PACKET:
+        if (header.packet_len + this->asf_header_len > ASF_HEADER_LEN) {
+            lprintf( "***LOG:*** -- "
+                     "libmms: asf packet too large\n");
+            return 0;
+        }
+        len = io_read(io,  this->s,
+                              this->asf_header + this->asf_header_len, header.packet_len);
+        if (len != header.packet_len) {
+  /* FIXME: de-xine-ification */
+          lprintf( "***LOG:*** -- "
+		 "libmms: get_asf_header failed\n");
+           return 0;
+        }
+        this->asf_header_len += header.packet_len;
+        lprintf("header flags: %d\n", header.flags);
+        if ((header.flags == 0X08) || (header.flags == 0X0C))
+          stop = 1;
+        break;
+    }
+  }
+  lprintf ("get header packet succ\n");
+  return 1;
+}
+
+static void interp_asf_header (mms_t *this) {
+
   int i;
 
-  printf ("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\nanswer received, %d bytes\n", len);
+  this->asf_packet_len = 0;
+  this->num_stream_ids = 0;
+  /*
+   * parse header
+   */
+   
+  i = 30;
+  while (i < this->asf_header_len) {
+    
+    int guid;
+    uint64_t length;
+
+    guid = get_guid(this->asf_header, i);
+    i += 16;
+        
+    length = LE_64(this->asf_header + i);
+    i += 8;
+
+    switch (guid) {
+    
+      case GUID_ASF_FILE_PROPERTIES:
 
-  printf ("start sequence %08x\n", get_32 (data, 0));
-  printf ("command id     %08x\n", get_32 (data, 4));
-  printf ("length         %8x \n", get_32 (data, 8));
-  printf ("len8           %8x \n", get_32 (data, 16));
-  printf ("sequence #     %08x\n", get_32 (data, 20));
-  printf ("len8  (II)     %8x \n", get_32 (data, 32));
-  printf ("dir | comm     %08x\n", get_32 (data, 36));
-  printf ("switches       %08x\n", get_32 (data, 40));
+        this->asf_packet_len = LE_32(this->asf_header + i + 92 - 24);
+        if (this->asf_packet_len > BUF_SIZE) {
+          this->asf_packet_len = 0;
+          lprintf( "***LOG:*** -- "
+                   "libmms: asf packet len too large\n");
+          break;
+        }
+        this->file_len       = LE_64(this->asf_header + i + 40 - 24);
+        lprintf ("file object, packet length = %d (%d)\n",
+                 this->asf_packet_len, LE_32(this->asf_header + i + 96 - 24));
+        break;
 
-  for (i=48; i<len; i+=2) {
-    unsigned char c = data[i];
+      case GUID_ASF_STREAM_PROPERTIES:
+        {
+	  uint16_t flags;
+          uint16_t stream_id;
+          int      type;
+          int      encrypted;
+
+          guid = get_guid(this->asf_header, i);
+          switch (guid) {
+            case GUID_ASF_AUDIO_MEDIA:
+              type = ASF_STREAM_TYPE_AUDIO;
+              this->has_audio = 1;
+              break;
     
-    if ((c>=32) && (c<128))
-      printf ("%c", c);
-    else
-      printf (" %02x ", c);
-    
-  }
-  printf ("\n");
-#endif
+            case GUID_ASF_VIDEO_MEDIA:
+	    case GUID_ASF_JFIF_MEDIA:
+	    case GUID_ASF_DEGRADABLE_JPEG_MEDIA:
+              type = ASF_STREAM_TYPE_VIDEO;
+              this->has_video = 1;
+              break;
+          
+            case GUID_ASF_COMMAND_MEDIA:
+              type = ASF_STREAM_TYPE_CONTROL;
+              break;
+        
+            default:
+              type = ASF_STREAM_TYPE_UNKNOWN;
+          }
 
-}  
+          flags = LE_16(this->asf_header + i + 48);
+	  stream_id = flags & 0x7F;
+	  encrypted = flags >> 15;
+
+          lprintf ("stream object, stream id: %d, type: %d, encrypted: %d\n",
+		   stream_id, type, encrypted);
 
-static void get_answer (mms_t *this) {
+	  if (this->num_stream_ids < ASF_MAX_NUM_STREAMS && stream_id < ASF_MAX_NUM_STREAMS) {
+	    this->stream_types[stream_id] = type;
+	    this->stream_ids[this->num_stream_ids] = stream_id;
+	    this->num_stream_ids++;
+	  } else {
+	    lprintf ("too many streams, skipping\n");
+	  }
+        }
+        break;
 
-  int   command = 0x1b;
+      case GUID_ASF_STREAM_BITRATE_PROPERTIES:
+        {
+          uint16_t streams = LE_16(this->asf_header + i);
+          uint16_t stream_id;
+          int j;
 
-  while (command == 0x1b) {
-    int len;
+          lprintf ("stream bitrate properties\n");
+          lprintf ("streams %d\n", streams); 
 
-    len = read (this->s, this->buf, BUF_SIZE) ;
-    if (!len) {
-      printf ("\nalert! eof\n");
-      return;
+          for(j = 0; j < streams; j++) {
+            stream_id = LE_16(this->asf_header + i + 2 + j * 6);
+            lprintf ("stream id %d\n", stream_id); 
+            this->bitrates[stream_id] = LE_32(this->asf_header + i + 4 + j * 6);
+            this->bitrates_pos[stream_id] = i + 4 + j * 6;
+            lprintf ("stream id %d, bitrate %d\n", stream_id, 
+                     this->bitrates[stream_id]);
+          }
+        }
+        break;
+    
+      default:
+        lprintf ("unknown object\n");
+        break;
     }
 
-    print_answer (this->buf, len);
+    lprintf ("length    : %lld\n", length);
 
-    command = get_32 (this->buf, 36) & 0xFFFF;
-
-    if (command == 0x1b) 
-      send_command (this, 0x1b, 0, 0, 0);
+    if (length > 24) {
+      i += length - 24;
+    }
   }
 }
 
-static int receive (int s, char *buf, size_t count) {
-
-  ssize_t  len, total;
-
-  total = 0;
-
-  while (total < count) {
-
-    len = read (s, &buf[total], count-total);
-
-    if (len<0) {
-      perror ("read error:");
-      return 0;
-    }
-
-    total += len;
-
-#ifdef LOG
-    if (len != 0) {
-      printf ("[%d/%d]", total, count);
-      fflush (stdout);
-    }
-#endif
-
-  }
-
-  return 1;
+const static char *const mmst_proto_s[] = { "mms", "mmst", NULL };
 
-}
-
-static void get_header (mms_t *this) {
-
-  char  pre_header[8];
-  int            i;
-
-  this->asf_header_len = 0;
-
-  while (1) {
+static int mmst_valid_proto (char *proto) {
+  int i = 0;
 
-    if (!receive (this->s, pre_header, 8)) {
-      printf ("libmms: pre-header read failed\n");
-      return ;
-    }
-
-#ifdef LOG    
-    for (i=0; i<8; i++)
-      printf ("libmms: pre_header[%d] = %02x (%d)\n",
-	      i, pre_header[i], pre_header[i]);
-#endif    
-
-    if (pre_header[4] == 0x02) {
-      
-      int packet_len;
-      
-      packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
+  lprintf("mmst_valid_proto\n");
 
-#ifdef LOG    
-      printf ("libmms: asf header packet detected, len=%d\n",
-	      packet_len);
-#endif
-
-      if (!receive (this->s, (char*)&this->asf_header[this->asf_header_len], packet_len)) {
-	printf ("libmms: header data read failed\n");
-	return;
-      }
-
-      this->asf_header_len += packet_len;
-
-      if ( (this->asf_header[this->asf_header_len-1] == 1) 
-	   && (this->asf_header[this->asf_header_len-2]==1)) {
-
-	printf ("libmms: get header packet finished\n");
-
-	return;
-
-      } 
-
-    } else {
-
-      int packet_len, command;
+  if (!proto)
+    return 0;
 
-      if (!receive (this->s, (char *) &packet_len, 4)) {
-	printf ("packet_len read failed\n");
-	return;
-      }
-      
-      packet_len = get_32 ((char *)&packet_len, 0) + 4;
-      
-#ifdef LOG    
-      printf ("command packet detected, len=%d\n",
-	      packet_len);
-#endif
-      
-      if (!receive (this->s, this->buf, packet_len)) {
-	printf ("command data read failed\n");
-	return ;
-      }
-      
-      command = get_32 (this->buf, 24) & 0xFFFF;
-      
-#ifdef LOG    
-      printf ("command: %02x\n", command);
-#endif
-      
-      if (command == 0x1b) 
-	send_command (this, 0x1b, 0, 0, 0);
-      
+  while(mmst_proto_s[i]) {
+    if (!strcasecmp(proto, mmst_proto_s[i])) {
+      return 1;
     }
-
-    printf ("mms: get header packet succ\n");
+    i++;
   }
+  return 0;
 }
 
-static void interp_header (mms_t *this) {
-
-  int i;
-
-  this->packet_length = 0;
-
-  /*
-   * parse header
-   */
+/* FIXME: de-xine-ification */
 
-  i = 30;
-  while (i<this->asf_header_len) {
-    
-    uint64_t guid_1, guid_2, length;
+/* static void report_progress (void *data, int p) {
 
-    guid_2 = (uint64_t)this->asf_header[i] | ((uint64_t)this->asf_header[i+1]<<8) 
-      | ((uint64_t)this->asf_header[i+2]<<16) | ((uint64_t)this->asf_header[i+3]<<24)
-      | ((uint64_t)this->asf_header[i+4]<<32) | ((uint64_t)this->asf_header[i+5]<<40)
-      | ((uint64_t)this->asf_header[i+6]<<48) | ((uint64_t)this->asf_header[i+7]<<56);
-    i += 8;
+  xine_event_t             event;
+  xine_progress_data_t     prg;
 
-    guid_1 = (uint64_t)this->asf_header[i] | ((uint64_t)this->asf_header[i+1]<<8) 
-      | ((uint64_t)this->asf_header[i+2]<<16) | ((uint64_t)this->asf_header[i+3]<<24)
-      | ((uint64_t)this->asf_header[i+4]<<32) | ((uint64_t)this->asf_header[i+5]<<40)
-      | ((uint64_t)this->asf_header[i+6]<<48) | ((uint64_t)this->asf_header[i+7]<<56);
-    i += 8;
-    
-#ifdef LOG    
-    printf ("guid found: %016llx%016llx\n", guid_1, guid_2);
-#endif
-
-    length = (uint64_t)this->asf_header[i] | ((uint64_t)this->asf_header[i+1]<<8) 
-      | ((uint64_t)this->asf_header[i+2]<<16) | ((uint64_t)this->asf_header[i+3]<<24)
-      | ((uint64_t)this->asf_header[i+4]<<32) | ((uint64_t)this->asf_header[i+5]<<40)
-      | ((uint64_t)this->asf_header[i+6]<<48) | ((uint64_t)this->asf_header[i+7]<<56);
-
-    i += 8;
-
-    if ( (guid_1 == 0x6cce6200aa00d9a6) && (guid_2 == 0x11cf668e75b22630) ) {
-      printf ("header object\n");
-    } else if ((guid_1 == 0x6cce6200aa00d9a6) && (guid_2 == 0x11cf668e75b22636)) {
-      printf ("data object\n");
-    } else if ((guid_1 == 0x6553200cc000e48e) && (guid_2 == 0x11cfa9478cabdca1)) {
-
-      this->packet_length = get_32((char*)this->asf_header, i+92-24);
-
-#ifdef LOG    
-      printf ("file object, packet length = %d (%d)\n",
-	      this->packet_length, get_32((char*)this->asf_header, i+96-24));
-#endif
+  prg.description = _("Connecting MMS server (over tcp)...");
+  prg.percent = p;
+  
+  event.type = XINE_EVENT_PROGRESS;
+  event.data = &prg;
+  event.data_length = sizeof (xine_progress_data_t);
+  
+  xine_event_send (stream, &event);
+} */
 
 
-    } else if ((guid_1 == 0x6553200cc000e68e) && (guid_2 == 0x11cfa9b7b7dc0791)) {
-
-      int stream_id = this->asf_header[i+48] | this->asf_header[i+49] << 8;
-
-#ifdef LOG    
-      printf ("stream object, stream id: %d\n", stream_id);
-#endif
-
-      this->stream_ids[this->num_stream_ids] = stream_id;
-      this->num_stream_ids++;
-      
-
-      /*
-	} else if ((guid_1 == 0x) && (guid_2 == 0x)) {
-	printf ("??? object\n");
-      */
-    } else {
-      printf ("unknown object\n");
-    }
-
-#ifdef LOG    
-    printf ("length    : %lld\n", length);
-#endif
-
-    i += length-24;
-
-  }
-}
-
-
-mms_t *mms_connect (const char *url_) {
-
-  mms_t *this;
-  char  *url, *host, *hostend;
-  char  *path, *file;
-  int    hostlen, s, len, i;
-
-  /* parse url*/
-
-  if (strncasecmp (url_, "mms://",6)) {
-    printf ("libmms: invalid url >%s< (should be mms:// - style)\n", url_);
-    return NULL;
-  }
-
-  url = strdup (url_);
-
-  /* extract hostname */
-
-  hostend = strchr(&url[6],'/');
-  if (!hostend) {
-    printf ("libmms: invalid url >%s<, failed to find hostend\n", url);
-    return NULL;
-  }
-  hostlen = hostend - url - 6;
-  host = av_malloc (hostlen+1);
-  strncpy (host, &url[6], hostlen);
-  host[hostlen]=0;
-
-  /* extract path and file */
-
-  path = url+hostlen+7;
-  file = strrchr (url, '/');
+/*
+ * returns 1 on error
+ */
+static int mms_tcp_connect(mms_io_t *io, mms_t *this) {
+  int progress, res;
+  
+  if (!this->port) this->port = MMST_PORT;
 
   /* 
    * try to connect 
    */
-
-  s = host_connect (host, MMS_PORT);
-  if (s == -1) {
-    printf ("libmms: failed to connect\n");
-    free (host);
-    free (url);
-    return NULL;
+  lprintf("try to connect to %s on port %d \n", this->host, this->port);
+  this->s = io_connect(io,  this->host, this->port);
+  if (this->s == -1) {
+  /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+	    "failed to connect '%s'\n", this->host);
+    return 1;
   }
 
-  this = (mms_t*) av_malloc (sizeof (mms_t));
+  /* connection timeout 15s */
+  progress = 0;
+  do {
+    /*FIXME: de-xine-ification */
+/*     report_progress(this->stream, progress); */
+    res = io_select(io,  this->s, MMS_IO_WRITE_READY, 500);
+    progress += 1;
+  } while ((res == MMS_IO_STATUS_TIMEOUT) && (progress < 30));
+  if (res != MMS_IO_STATUS_READY) {
+    return 1;
+  }
+  lprintf ("connected\n");
+  return 0;
+}
+
+static void mms_gen_guid(char guid[]) {
+  static char digit[16] = "0123456789ABCDEF";
+  int i = 0;
+
+  srand(time(NULL));
+  for (i = 0; i < 36; i++) {
+    guid[i] = digit[(int) ((16.0*rand())/(RAND_MAX+1.0))];
+  }
+  guid[8] = '-'; guid[13] = '-'; guid[18] = '-'; guid[23] = '-';
+  guid[36] = '\0';
+}
+
+/*
+ * return 0 on error
+ */
+int static mms_choose_best_streams(mms_io_t *io, mms_t *this) {
+  int     i;
+  int     video_stream = 0;
+  int     audio_stream = 0;
+  int     max_arate    = 0;
+  int     min_vrate    = 0;
+  int     min_bw_left  = 0;
+  int     stream_id;
+  int     bandwitdh_left;
+  int     res;
+
+  /* command 0x33 */
+  /* choose the best quality for the audio stream */
+  /* i've never seen more than one audio stream */
+  lprintf("num_stream_ids=%d\n", this->num_stream_ids);
+  for (i = 0; i < this->num_stream_ids; i++) {
+    stream_id = this->stream_ids[i];
+    switch (this->stream_types[stream_id]) {
+      case ASF_STREAM_TYPE_AUDIO:
+        if (this->bitrates[stream_id] > max_arate) {
+          audio_stream = stream_id;
+          max_arate = this->bitrates[stream_id];
+        }
+        break;
+      default:
+        break;
+    }
+  }
+  
+  /* choose a video stream adapted to the user bandwidth */
+  bandwitdh_left = this->bandwidth - max_arate;
+  if (bandwitdh_left < 0) {
+    bandwitdh_left = 0;
+  }
+  lprintf("bandwitdh %d, left %d\n", this->bandwidth, bandwitdh_left);
+
+  min_bw_left = bandwitdh_left;
+  for (i = 0; i < this->num_stream_ids; i++) {
+    stream_id = this->stream_ids[i];
+    switch (this->stream_types[stream_id]) {
+      case ASF_STREAM_TYPE_VIDEO:
+        if (((bandwitdh_left - this->bitrates[stream_id]) < min_bw_left) &&
+            (bandwitdh_left >= this->bitrates[stream_id])) {
+          video_stream = stream_id;
+          min_bw_left = bandwitdh_left - this->bitrates[stream_id];
+        }
+        break;
+      default:
+        break;
+    }
+  }  
 
-  this->url             = url;
-  this->host            = host;
-  this->path            = path;
-  this->file            = file;
-  this->s               = s;
+  /* choose the lower bitrate of */
+  if (!video_stream && this->has_video) {
+    for (i = 0; i < this->num_stream_ids; i++) {
+      stream_id = this->stream_ids[i];
+      switch (this->stream_types[stream_id]) {
+        case ASF_STREAM_TYPE_VIDEO:
+          if ((this->bitrates[stream_id] < min_vrate) ||
+              (!min_vrate)) {
+            video_stream = stream_id;
+            min_vrate = this->bitrates[stream_id];
+          }
+          break;
+        default:
+          break;
+      }
+    }
+  }
+    
+  lprintf("selected streams: audio %d, video %d\n", audio_stream, video_stream);
+  lprintf("disabling other streams\n");
+  memset (this->scmd_body, 0, 40);
+  for (i = 1; i < this->num_stream_ids; i++) {
+    this->scmd_body [ (i - 1) * 6 + 2 ] = 0xFF;
+    this->scmd_body [ (i - 1) * 6 + 3 ] = 0xFF;
+    this->scmd_body [ (i - 1) * 6 + 4 ] = this->stream_ids[i] ;
+    this->scmd_body [ (i - 1) * 6 + 5 ] = this->stream_ids[i] >> 8;
+    if ((this->stream_ids[i] == audio_stream) ||
+        (this->stream_ids[i] == video_stream)) {
+      this->scmd_body [ (i - 1) * 6 + 6 ] = 0x00;
+      this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00;
+    } else {
+      lprintf("disabling stream %d\n", this->stream_ids[i]);
+      this->scmd_body [ (i - 1) * 6 + 6 ] = 0x02;
+      this->scmd_body [ (i - 1) * 6 + 7 ] = 0x00;
+      
+      /* forces the asf demuxer to not choose this stream */
+      if (this->bitrates_pos[this->stream_ids[i]]) {
+        this->asf_header[this->bitrates_pos[this->stream_ids[i]]]     = 0;
+        this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 1] = 0;
+        this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 2] = 0;
+        this->asf_header[this->bitrates_pos[this->stream_ids[i]] + 3] = 0;
+      }
+    }
+  }
+
+  if (!send_command (io, this, 0x33, this->num_stream_ids, 
+                     0xFFFF | this->stream_ids[0] << 16, 
+                     this->num_stream_ids * 6 + 2)) {
+  /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+	     "libmms: mms_choose_best_streams failed\n");
+    return 0;
+  }
+
+  if ((res = get_answer (io, this)) != 0x21) {
+    /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+	     "libmms: unexpected response: %02x (0x21)\n", res);
+  }
+
+  return 1;
+}
+
+/*
+ * TODO: error messages
+ *       network timing request
+ */
+/* FIXME: got somewhat broken during xine_stream_t->(void*) conversion */
+mms_t *mms_connect (mms_io_t *io, void *data, const char *url, int bandwidth) {
+#ifdef USE_ICONV
+  iconv_t url_conv;
+#else
+  int     url_conv = 0;
+#endif
+  mms_t  *this;
+  int     res;
+  GURI   *uri;
+  
+  if (!url)
+    return NULL;
+
+  /* FIXME: needs proper error-signalling work */
+  this = (mms_t*) malloc (sizeof (mms_t));
+
+  this->custom_data     = data;
+  this->url             = strdup (url);
+  this->s               = -1;
   this->seq_num         = 0;
-  this->scmd_body       = &this->scmd[CMD_HEADER_LEN];
+  this->scmd_body       = this->scmd + CMD_HEADER_LEN + CMD_PREFIX_LEN;
   this->asf_header_len  = 0;
   this->asf_header_read = 0;
   this->num_stream_ids  = 0;
-  this->packet_length   = 0;
+  this->asf_packet_len  = 0;
+  this->start_packet_seq= 0;
+  this->need_discont    = 1;
   this->buf_size        = 0;
   this->buf_read        = 0;
+  this->has_audio       = 0;
+  this->has_video       = 0;
+  this->bandwidth       = bandwidth;
+  this->current_pos     = 0;
+  this->eos             = 0;
 
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 0); */
+  
+  uri = gnet_uri_new(this->url);
+  if(!uri) {
+    lprintf ("invalid url\n");
+    goto fail;
+  }
+  this->proto = uri->scheme;
+  this->user = uri->user;
+  this->host = uri->hostname;
+  this->port = uri->port;
+  this->password = uri->passwd;
+  this->uri = uri->path;
+  
+  if (!mmst_valid_proto(this->proto)) {
+    lprintf ("unsupported protocol\n");
+    goto fail;
+  }
+  
+  if (mms_tcp_connect(io, this)) {
+    goto fail;
+  }
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 30); */
+  
+#ifdef USE_ICONV
+  url_conv = string_utf16_open();
+#endif
   /*
    * let the negotiations begin...
    */
 
-  /* cmd1 */
+  /* command 0x1 */
+  lprintf("send command 0x01\n");
+  mms_gen_guid(this->guid);
+  sprintf (this->str, "\x1c\x03NSPlayer/7.0.0.1956; {%s}; Host: %s",
+    this->guid, this->host);
+  string_utf16 (url_conv, this->scmd_body, this->str, strlen(this->str) + 2);
+
+  if (!send_command (io, this, 1, 0, 0x0004000b, strlen(this->str) * 2 + 8)) {
+  /* FIXME: de-xine-ification */
+    lprintf( "***LOG:*** -- "
+	    "libmms: failed to send command 0x01\n");
+    goto fail;
+  }
   
-  sprintf (this->str, "\034\003NSPlayer/7.0.0.1956; {33715801-BAB3-9D85-24E9-03B90328270A}; Host: %s",
-	   this->host);
-  string_utf16 (this->scmd_body, this->str, strlen(this->str)+2);
+  if ((res = get_answer (io, this)) != 0x01) {
+  /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+	     "libmms: unexpected response: %02x (0x01)\n", res);
+    lprintf("answer: %d\n", res);
+    goto fail;
+  }
+  
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 40); */
 
-  send_command (this, 1, 0, 0x0004000b, strlen(this->str) * 2+8);
+  /* TODO: insert network timing request here */
+  /* command 0x2 */
+  lprintf("send command 0x02\n");
+  string_utf16 (url_conv, &this->scmd_body[8], "\002\000\\\\192.168.0.129\\TCP\\1037\0000", 28);
+  memset (this->scmd_body, 0, 8);
+  if (!send_command (io, this, 2, 0, 0, 28 * 2 + 8)) {
+  /* FIXME: de-xine-ification */
+    lprintf( "***LOG:*** -- "
+	    "libmms: failed to send command 0x02\n");
+
+    goto fail;
+  }
 
-  len = read (this->s, this->buf, BUF_SIZE) ;
-  if (len>0)
-    print_answer (this->buf, len);
-  else {
-    printf ("libmms: read failed: %s\n", strerror(errno));
-
+  switch (res = get_answer (io, this)) {
+    case 0x02:
+      /* protocol accepted */
+      break;
+    case 0x03:
+  /* FIXME: de-xine-ification */
+      lprintf( "***LOG:*** -- "
+	      "libmms: protocol failed\n");
+      goto fail;
+      break;
+    default:
+      lprintf("unexpected response: %02x (0x02 or 0x03)\n", res);
+      goto fail;
   }
 
-  /* cmd2 */
-
-  string_utf16 (&this->scmd_body[8], "\002\000\\\\192.168.0.129\\TCP\\1037\0000", 
-		28);
-  memset (this->scmd_body, 0, 8);
-  send_command (this, 2, 0, 0, 28*2+8);
-
-  len = read (this->s, this->buf, BUF_SIZE) ;
-  if (len)
-    print_answer (this->buf, len);
-
-  /* 0x5 */
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 50); */
 
-  string_utf16 (&this->scmd_body[8], path, strlen(path));
-  memset (this->scmd_body, 0, 8);
-  send_command (this, 5, 0, 0, strlen(path)*2+12);
-
-  get_answer (this);
+  /* command 0x5 */
+  {
+    mms_buffer_t command_buffer;
+    
+    lprintf("send command 0x05\n");
+    mms_buffer_init(&command_buffer, this->scmd_body);
+    mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x00000000); /* ?? */
+    string_utf16 (url_conv, this->scmd_body + command_buffer.pos, this->uri, strlen(this->uri));
+    if (!send_command (io, this, 5, 1, 0xffffffff, strlen(this->uri) * 2 + 12))
+      goto fail;
+  }
+  
+  switch (res = get_answer (io, this)) {
+    case 0x06:
+      {
+        int xx, yy;
+        /* no authentication required */
+      
+        /* Warning: sdp is not right here */
+        xx = this->buf[62];
+        yy = this->buf[63];
+        this->live_flag = ((xx == 0) && ((yy & 0xf) == 2));
+        lprintf("live: live_flag=%d, xx=%d, yy=%d\n", this->live_flag, xx, yy);
+      }
+      break;
+    case 0x1A:
+      /* authentication request, not yet supported */
+  /* FIXME: de-xine-ification */
+      lprintf ( "***LOG:*** -- "
+	       "libmms: authentication request, not yet supported\n");
+      goto fail;
+      break;
+    default:
+  /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+	     "libmms: unexpected response: %02x (0x06 or 0x1A)\n", res);
+      goto fail;
+  }
 
-  /* 0x15 */
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 60); */
 
-  memset (this->scmd_body, 0, 40);
-  this->scmd_body[32] = 2;
-
-  send_command (this, 0x15, 1, 0, 40);
+  /* command 0x15 */
+  lprintf("send command 0x15\n");
+  {
+    mms_buffer_t command_buffer;
+    mms_buffer_init(&command_buffer, this->scmd_body);
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x00800000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0x40AC2000);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, ASF_HEADER_PACKET_ID_TYPE);   /* Header Packet ID type */
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* ?? */
+    if (!send_command (io, this, 0x15, 1, 0, command_buffer.pos)) {
+  /* FIXME: de-xine-ification */
+      lprintf ( "***LOG:*** -- "
+	       "libmms: failed to send command 0x15\n");
+      goto fail;
+    }
+  }
+  
+  if ((res = get_answer (io, this)) != 0x11) {
+  /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+             "libmms: unexpected response: %02x (0x11)\n", res);
+    goto fail;
+  }
 
   this->num_stream_ids = 0;
 
-  get_header (this);
-  interp_header (this);
-
-  /* 0x33 */
-
-  memset (this->scmd_body, 0, 40);
+  if (!get_asf_header (io, this))
+    goto fail;
 
-  for (i=1; i<this->num_stream_ids; i++) {
-    this->scmd_body [ (i-1) * 6 + 2 ] = 0xFF;
-    this->scmd_body [ (i-1) * 6 + 3 ] = 0xFF;
-    this->scmd_body [ (i-1) * 6 + 4 ] = this->stream_ids[i];
-    this->scmd_body [ (i-1) * 6 + 5 ] = 0x00;
-  }
-
-  send_command (this, 0x33, this->num_stream_ids, 
-		0xFFFF | this->stream_ids[0] << 16, 
-		(this->num_stream_ids-1)*6+2);
-
-  get_answer (this);
-
-  /* 0x07 */
+  interp_asf_header (this);
 
-  memset (this->scmd_body, 0, 40);
-
-  for (i=8; i<16; i++)
-    this->scmd_body[i] = 0xFF;
-
-  this->scmd_body[20] = 0x04;
-
-  send_command (this, 0x07, 1, 
-		0xFFFF | this->stream_ids[0] << 16, 
-		24);
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 70); */
 
-  return this;
-}
-
-static int get_media_packet (mms_t *this) {
-
-  char  pre_header[8];
-  int            i;
-
-  if (!receive (this->s, pre_header, 8)) {
-    printf ("pre-header read failed\n");
-    return 0;
+  if (!mms_choose_best_streams(io, this)) {
+  /* FIXME: de-xine-ification */
+    lprintf ( "***LOG:*** -- "
+	     "libmms: mms_choose_best_streams failed");
+    goto fail;
   }
 
-#ifdef LOG
-  for (i=0; i<8; i++)
-    printf ("pre_header[%d] = %02x (%d)\n",
-	    i, pre_header[i], pre_header[i]);
-#endif
-
-  if (pre_header[4] == 0x04) {
-
-    int packet_len;
-
-    packet_len = (pre_header[7] << 8 | pre_header[6]) - 8;
-
-#ifdef LOG
-    printf ("asf media packet detected, len=%d\n",
-	    packet_len);
-#endif
-
-    if (!receive (this->s, this->buf, packet_len)) {
-      printf ("media data read failed\n");
-      return 0;
-    }
-
-    /* implicit padding (with "random" data)*/
-    this->buf_size = this->packet_length;
-
-  } else {
-
-    int packet_len, command;
-
-    if (!receive (this->s, (char *)&packet_len, 4)) {
-      printf ("packet_len read failed\n");
-      return 0;
-    }
+  /* FIXME de-xine-ification */
+/*   report_progress (stream, 80); */
 
-    packet_len = get_32 ((char *)&packet_len, 0) + 4;
-
-#ifdef LOG
-    printf ("command packet detected, len=%d\n",
-	    packet_len);
-#endif
-
-    if (!receive (this->s, this->buf, packet_len)) {
-      printf ("command data read failed\n");
-      return 0;
-    }
-
-    if ( (pre_header[7] != 0xb0) || (pre_header[6] != 0x0b)
-	 || (pre_header[5] != 0xfa) || (pre_header[4] != 0xce) ) {
-
-      printf ("missing signature\n");
-      exit (1);
-
-    }
-
-    command = get_32 (this->buf, 24) & 0xFFFF;
-
-#ifdef LOG
-    printf ("command: %02x\n", command);
-#endif
-
-    if (command == 0x1b) 
-      send_command (this, 0x1b, 0, 0, 0);
-    else if (command == 0x1e) {
-
-      printf ("libmms: everything done. Thank you for downloading a media file containing proprietary and patentend technology.\n");
-
-      return 0;
-    } else if (command != 0x05) {
-      printf ("unknown command %02x\n", command);
-      exit (1);
+  /* command 0x07 */
+  {
+    mms_buffer_t command_buffer;
+    mms_buffer_init(&command_buffer, this->scmd_body);
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* 64 byte float timestamp */
+    mms_buffer_put_32 (&command_buffer, 0x00000000);                  
+    mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
+    mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* first packet sequence */
+    mms_buffer_put_8  (&command_buffer, 0xFF);                        /* max stream time limit (3 bytes) */
+    mms_buffer_put_8  (&command_buffer, 0xFF);
+    mms_buffer_put_8  (&command_buffer, 0xFF);
+    mms_buffer_put_8  (&command_buffer, 0x00);                        /* stream time limit flag */
+    mms_buffer_put_32 (&command_buffer, ASF_MEDIA_PACKET_ID_TYPE);    /* asf media packet id type */
+    if (!send_command (io, this, 0x07, 1, 0x0001FFFF, command_buffer.pos)) {
+  /* FIXME: de-xine-ification */
+      lprintf ( "***LOG:*** -- "
+	       "libmms: failed to send command 0x07\n");
+      goto fail;
     }
   }
 
-#ifdef LOG
-  printf ("get media packet succ\n");
+/*   report_progress (stream, 100); */
+
+#ifdef USE_ICONV
+  string_utf16_close(url_conv);
 #endif
 
+  lprintf("mms_connect: passed\n" );
+ 
+  return this;
+
+fail:
+  if (this->s != -1)
+    close (this->s);
+  if (this->url)
+    free(this->url);
+  if (this->proto)
+    free(this->proto);
+  if (this->host)
+    free(this->host);
+  if (this->user)
+    free(this->user);
+  if (this->password)
+    free(this->password);
+  if (this->uri)
+    free(this->uri);
+
+  free (this);
+  return NULL;
+}
+
+static int get_media_packet (mms_io_t *io, mms_t *this) {
+  mms_packet_header_t header;
+  off_t len;
+  
+  switch (get_packet_header (io, this, &header)) {
+    case MMS_PACKET_ERR:
+  /* FIXME: de-xine-ification */
+      lprintf( "***LOG:*** -- "
+	      "libmms: failed to read mms packet header\n");
+      return 0;
+      break;
+    
+    case MMS_PACKET_COMMAND:
+      {
+        int command;
+        command = get_packet_command (io, this, header.packet_len);
+      
+        switch (command) {
+          case 0x1e:
+            {
+              uint32_t error_code;
+
+              /* Warning: sdp is incomplete. Do not stop if error_code==1 */
+              error_code = LE_32(this->buf + CMD_HEADER_LEN);
+              lprintf ("End of the current stream. Continue=%d\n", error_code);
+
+              if (error_code == 0) {
+                this->eos = 1;
+                return 0;
+              }
+              
+            }
+            break;
+  
+          case 0x20:
+            {
+              lprintf ("new stream.\n");
+              /* asf header */
+              if (!get_asf_header (io, this)) {
+		/* FIXME: de-xine-ification */
+                lprintf ( "***LOG:*** -- "
+			 "failed to read new ASF header\n");
+                return 0;
+              }
+
+              interp_asf_header (this);
+
+              if (!mms_choose_best_streams(io, this))
+                return 0;
+
+              /* send command 0x07 */
+              /* TODO: ugly */
+              /* command 0x07 */
+              {
+                mms_buffer_t command_buffer;
+                mms_buffer_init(&command_buffer, this->scmd_body);
+                mms_buffer_put_32 (&command_buffer, 0x00000000);                  /* 64 byte float timestamp */
+                mms_buffer_put_32 (&command_buffer, 0x00000000);                  
+                mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* ?? */
+                mms_buffer_put_32 (&command_buffer, 0xFFFFFFFF);                  /* first packet sequence */
+                mms_buffer_put_8  (&command_buffer, 0xFF);                        /* max stream time limit (3 bytes) */
+                mms_buffer_put_8  (&command_buffer, 0xFF);
+                mms_buffer_put_8  (&command_buffer, 0xFF);
+                mms_buffer_put_8  (&command_buffer, 0x00);                        /* stream time limit flag */
+                mms_buffer_put_32 (&command_buffer, ASF_MEDIA_PACKET_ID_TYPE);    /* asf media packet id type */
+                if (!send_command (io, this, 0x07, 1, 0x0001FFFF, command_buffer.pos)) {
+		  /* FIXME: de-xine-ification */
+                  lprintf ( "***LOG:*** -- "
+			   "libmms: failed to send command 0x07\n");
+                  return 0;
+                }
+              }
+              this->current_pos = 0;
+            }
+            break;
+
+          case 0x1b:
+            {
+              if (!send_command (io, this, 0x1b, 0, 0, 0)) {
+		/* FIXME: de-xine-ification */
+                lprintf( "***LOG:*** -- "
+			"libmms: failed to send command\n");
+                return 0;
+              }
+            }
+            break;
+          
+          case 0x05:
+            break;
+  
+          default:
+	    /* FIXME: de-xine-ification */
+	    lprintf ( "***LOG:*** -- "
+                     "unexpected mms command %02x\n", command);
+        }
+        this->buf_size = 0;
+      }
+      break;
+
+    case MMS_PACKET_ASF_HEADER:
+      /* FIXME: de-xine-ification */
+      lprintf( "***LOG:*** -- "
+	      "libmms: unexpected asf header packet\n");
+      this->buf_size = 0;
+      break;
+
+    case MMS_PACKET_ASF_PACKET:
+      {
+        /* media packet */
+
+	/* FIXME: probably needs some more sophisticated logic, but
+	   until we do seeking, this should work */
+	if(this->need_discont)
+	{
+	  this->need_discont = 0;
+	  this->start_packet_seq = header.packet_seq;
+	}
+	
+        lprintf ("asf media packet detected, packet_len=%d, packet_seq=%d\n",
+                 header.packet_len, header.packet_seq);
+        if (header.packet_len > this->asf_packet_len) {
+	  /* FIXME: de-xine-ification */
+	  lprintf ( "***LOG:*** -- "
+                   "libmms: invalid asf packet len: %d bytes\n", header.packet_len);
+          return 0;
+        }
+    
+        /* simulate a seek */
+        this->current_pos = (off_t)this->asf_header_len +
+	  ((off_t)header.packet_seq - this->start_packet_seq) * (off_t)this->asf_packet_len;
+
+        len = io_read(io,  this->s, this->buf, header.packet_len);
+        if (len != header.packet_len) {
+	  /* FIXME: de-xine-ification */
+          lprintf ( "***LOG:*** -- "
+		   "libmms: read failed\n");
+          return 0;
+        }
+
+        /* explicit padding with 0 */
+        lprintf("padding: %d bytes\n", this->asf_packet_len - header.packet_len);
+	{
+	  char *base  = (char *)(this->buf);
+	  char *start = base + header.packet_len;
+	  char *end   = start + this->asf_packet_len - header.packet_len;
+	  if ((start > base) && (start < (base+BUF_SIZE-1)) &&
+	      (start < end)  && (end < (base+BUF_SIZE-1))) {
+	    memset(this->buf + header.packet_len, 0, this->asf_packet_len - header.packet_len);
+ 	  }
+	  if (this->asf_packet_len > BUF_SIZE) {
+            this->buf_size = BUF_SIZE;
+          } else {
+            this->buf_size = this->asf_packet_len;
+          }
+	}
+      }
+      break;
+  }
+  
+  lprintf ("get media packet succ\n");
+
   return 1;
 }
 
-int mms_read (mms_t *this, char *data, int len) {
+
+int mms_peek_header (mms_t *this, char *data, int maxsize) {
+
+  int len;
 
+  len = (this->asf_header_len < maxsize) ? this->asf_header_len : maxsize;
+
+  memcpy(data, this->asf_header, len);
+  return len;
+}
+
+int mms_read (mms_io_t *io, mms_t *this, char *data, int len) {
   int total;
 
   total = 0;
-
-  while (total < len) {
-
-#ifdef LOG
-    printf ("libmms: read, got %d / %d bytes\n", total, len);
-#endif
+  while (total < len && !this->eos) {
 
     if (this->asf_header_read < this->asf_header_len) {
-
-      int n, bytes_left ;
+      int n, bytes_left;
 
       bytes_left = this->asf_header_len - this->asf_header_read ;
 
-      if (len<bytes_left)
-	n = len;
+      if ((len - total) < bytes_left)
+        n = len-total;
       else
-	n = bytes_left;
+        n = bytes_left;
 
       memcpy (&data[total], &this->asf_header[this->asf_header_read], n);
 
       this->asf_header_read += n;
       total += n;
+      this->current_pos += n;
     } else {
 
-      int n, bytes_left ;
+      int n, bytes_left;
 
       bytes_left = this->buf_size - this->buf_read;
-
-      while (!bytes_left) {
-	
-	this->buf_read = 0;
+      if (bytes_left == 0) {
+        this->buf_size = this->buf_read = 0;
+        if (!get_media_packet (io, this)) {
+  /* FIXME: de-xine-ification */
+          lprintf ( "***LOG:*** -- "
+		   "libmms: get_media_packet failed\n");
+          return total;
+        }
+        bytes_left = this->buf_size;
+      }
 
-	if (!get_media_packet (this)) {
-	  printf ("libmms: get_media_packet failed\n");
-	  return total;
-	}
-	bytes_left = this->buf_size - this->buf_read;
-      }
-      
-
-      if (len<bytes_left)
-	n = len;
+      if ((len - total) < bytes_left)
+        n = len - total;
       else
-	n = bytes_left;
+        n = bytes_left;
 
       memcpy (&data[total], &this->buf[this->buf_read], n);
 
       this->buf_read += n;
       total += n;
+      this->current_pos += n;
     }
   }
-
   return total;
 }
 
+
 void mms_close (mms_t *this) {
 
-  if (this->s >= 0) {
-    close(this->s);
-  }
+  if (this->s != -1)
+    close (this->s);
+  if (this->url)
+    free(this->url);
+  if (this->proto)
+    free(this->proto);
+  if (this->host)
+    free(this->host);
+  if (this->user)
+    free(this->user);
+  if (this->password)
+    free(this->password);
+  if (this->uri)
+    free(this->uri);
 
-  free (this->host);
-  free (this->url);
   free (this);
 }
+
+uint32_t mms_get_length (mms_t *this) {
+  return this->file_len;
+}
+
+off_t mms_get_current_pos (mms_t *this) {
+  return this->current_pos;
+}
--- a/Plugins/Input/wma/libffwma/mms.h	Sat Jul 15 16:05:21 2006 -0700
+++ b/Plugins/Input/wma/libffwma/mms.h	Sat Jul 15 16:39:37 2006 -0700
@@ -1,34 +1,65 @@
-/* 
- * Copyright (C) 2000-2001 major mms
- * 
- * This file is part of libmms
- * 
- * xine-mms is free software; you can redistribute it and/or modify
+/*
+ * Copyright (C) 2002-2003 the xine project
+ *
+ * This file is part of xine, a free video player.
+ *
+ * xine is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
- * xine-mms is distributed in the hope that it will be useful,
+ *
+ * xine is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
  *
+ * $Id: mms.h,v 1.11 2006/06/06 09:49:15 shawarma Exp $
+ *
  * libmms public header
  */
+
+/* TODO/dexineification:
+ * + functions needed:
+ * 	- _x_io_*()
+ * 	- xine_malloc() [?]
+ * 	- xine_fast_memcpy() [?]
+ */
+
 #ifndef HAVE_MMS_H
 #define HAVE_MMS_H
 
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/* #include "xine_internal.h" */
+
+#include "bswap.h"
+#include "mmsio.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
 typedef struct mms_s mms_t;
 
-mms_t *mms_connect (const char *url);
+mms_t*   mms_connect (mms_io_t *io, void *data, const char *url, int bandwidth);
+
+int      mms_read (mms_io_t *io, mms_t *instance, char *data, int len);
+uint32_t mms_get_length (mms_t *instance);
+void     mms_close (mms_t *instance);
 
-int mms_read (mms_t *this, char *data, int len);
+int      mms_peek_header (mms_t *instance, char *data, int maxsize);
+
+off_t    mms_get_current_pos (mms_t *instance);
 
-void mms_close (mms_t *this);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
 #endif
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Input/wma/libffwma/mmsio.h	Sat Jul 15 16:39:37 2006 -0700
@@ -0,0 +1,80 @@
+#ifndef __MMS_IO_H__
+#define __MMS_IO_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef off_t (*mms_io_write_func)(void *data, int socket, char *buf, off_t num);
+typedef off_t (*mms_io_read_func)(void *data, int socket, char *buf, off_t num);
+
+/* select states */
+#define MMS_IO_READ_READY    1
+#define MMS_IO_WRITE_READY   2
+
+enum
+  {
+    MMS_IO_STATUS_READY, 		/* IO can be safely performed */
+    MMS_IO_STATUS_ERROR,		/* There was IO error */
+    MMS_IO_STATUS_ABORTED,		/* IO command was (somehow)
+	   aborted. This is not error, but invalidates IO for further operations*/
+    MMS_IO_STATUS_TIMEOUT		/* Timeout was exceeded */
+  };
+
+/*
+ * Waits for a file descriptor/socket to change status.
+ *
+ * users can use this handler to provide their own implementations,
+ * for example abortable ones
+ *
+ * params :
+ *   data          whatever parameter may be needed by implementation
+ *   fd            file/socket descriptor
+ *   state         MMS_IO_READ_READY, MMS_IO_WRITE_READY
+ *   timeout_sec   timeout in seconds
+ *
+ *
+ * return value :
+ *   MMS_IO_READY     the file descriptor is ready for cmd
+ *   MMS_IO_ERROR     an i/o error occured
+ *   MMS_IO_ABORTED   command aborted
+ *   MMS_IO_TIMEOUT   the file descriptor is not ready after timeout_msec milliseconds
+ * every other return value is interpreted same as MMS_IO_ABORTED
+ */
+typedef int (*mms_io_select_func)(void *data, int fd, int state, int timeout_msec);
+
+/*
+ * open a tcp connection
+ *
+ * params :
+ *   stream        needed for reporting errors but may be NULL
+ *   host          address of target
+ *   port          port on target
+ *
+ * returns a socket descriptor or -1 if an error occured
+ */
+typedef int (*mms_io_tcp_connect_func)(void *data, const char *host, int port);
+
+typedef struct
+{
+  mms_io_select_func select;
+  void *select_data;
+  mms_io_read_func read;
+  void *read_data;
+  mms_io_write_func write;
+  void *write_data;
+  mms_io_tcp_connect_func connect;
+  void *connect_data;
+} mms_io_t;
+
+/* set default IO implementation, it will be used in absence of specific IO
+   parameter. Structure is referenced, not copied, must remain valid for entire
+   usage period. Passing NULL reverts to default, POSIX based implementation */
+void mms_set_default_io_impl(const mms_io_t *io);
+const mms_io_t* mms_get_default_io_impl();
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MMS_IO_H__ */