<?php
  /**************************************************************************\
  * phpGroupWare Module (Napster)                                            *
  * http://www.phpgroupware.org                                              *
  * Written by Mark Peters <mpeters@satx.rr.com>                             *
  * Based on WebNap Client copyright 2000                                    *
  * Written by Aakash Kambuj <aakash@idearing.com>                           *
  *            Kalpak Kothari <kalpak@idearing.com>                          *
  * --------------------------------------------                             *
  *  This program 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.                                              *
  * --------------------------------------------                             *
  * Napster is a registered trademark of Napster Inc  http://www.napster.com *
  \**************************************************************************/

  /* $Id: functions.inc.php,v 1.6 2000/10/29 00:44:15 skeeter Exp $ */

class napster {
  var $message_type_error = 0;
  var $message_type_login = 2;
  var $message_type_login_response = 3;
  var $message_type_version_check = 4;
  var $message_type_auto_upgrade = 5;
  var $message_type_new_user_login = 6;
  var $message_type_nick_check = 7;
  var $message_type_nick_not_registered = 8;
  var $message_type_nick_already_registered = 9;
  var $message_type_nick_invalid = 10;
  var $message_type_login_options = 14;
  var $message_type_notify_shared_file = 100;
  var $message_type_remove_file = 102;
  var $message_type_search = 200;
  var $message_type_search_result = 201;
  var $message_type_search_complete = 202;
  var $message_type_fileinfo_req = 203;
  var $message_type_fileinfo = 204;
  var $message_type_private_message = 205;
  var $message_type_get_error = 206;
  var $message_type_add_hotlist = 207;
  var $message_type_hotlist = 208;
  var $message_type_user_signon = 209;
  var $message_type_user_signoff = 210;
  var $message_type_browse = 211;
  var $message_type_browse_result = 212;
  var $message_type_browse_complete = 213;
  var $message_type_stats = 214;
  var $message_type_request_resume = 215;
  var $message_type_resume_response = 216;
  var $message_type_resume_comlete = 217;
  var $message_type_download_file = 218;
  var $message_type_download_complete = 219;
  var $message_type_upload_file = 220;
  var $message_type_upload_complete = 221;
  var $message_type_optional_ports = 300;
  var $message_type_hotlist_ack = 301;
  var $message_type_hotlist_error = 302;
  var $message_type_hotlist_remove_user = 303;
  var $message_type_client_disconnect = 316;
  var $message_type_user_ignore_list = 320;
  var $message_type_user_igonore_list_entry = 321;
  var $message_type_user_ignore_list_add = 322;
  var $message_type_user_ignore_list_remove = 323;
  var $message_type_user_not_ignored = 324;
  var $message_type_user_already_ignored = 325;
  var $message_type_clear_user_ignore_list = 326;
  var $message_type_blocked_ip_list = 330;
  var $message_type_block_ip = 332;
  var $message_type_unblock_ip = 333;
  var $message_type_join_channel = 400;
  var $message_type_part_channel = 401;
  var $message_type_send_public_message = 402;
  var $message_type_public_message = 403;
  var $message_type_error_message = 404;
  var $message_type_alt_download_req = 500;
  var $message_type_sysmsg = 621;
  var $message_type_change_port = 703;
  var $HEADER_SET = 0;
  var $in_motd;

  var $servers;
  var $speeds;
  var $comparators;

  var $firewall_nicks;
  var $ok_nicks;

  var $napserver;
  var $linespeed;
  var $conn_speed;
  var $linktype;
  var $nofirewall;
  var $title;
  var $nick;
  var $filename;
  var $pport;


  function napster() {
    global $phpgw;

    $phpgw->network->set_addcrlf(False);

    $phpgw->db->query("SELECT * FROM napster_servers");
    if($phpgw->db->num_rows()>0) {
      while($phpgw->db->next_record())
	$this->servers[$phpgw->db->f("name")] = $phpgw->db->f("ip").":".$phpgw->db->f("port");
    } else {
      $this->update_servers();
    }

    $phpgw->db->query("SELECT * FROM napster_speeds");
    while($phpgw->db->next_record())
      $this->speeds[count($this->speeds)] = $phpgw->db->f("speed");

    $phpgw->db->query("SELECT * FROM napster_compares");
    while($phpgw->db->next_record())
      $this->comparators[$phpgw->db->f("operator")] = $phpgw->db->f("operator");
  }

  function update_servers() {
    global $phpgw;

    $lines = $phpgw->network->gethttpsocketfile("http://www.napigator.com/servers.php?version=107&client=webnap");
    if($lines) {
      $phpgw->db->query("DELETE FROM napster_servers");

      $lastupdated = time();
      for($i=11;$i<count($lines) - 1;$i++) {
//	echo $lines[$i]."<br>\n";
	$lines[$i] = str_replace("\n","",$lines[$i]);
	$lines[$i] = str_replace("\r","",$lines[$i]);
	list($ip, $port, $network, $users, $files, $gb, $name) = explode(" ", $lines[$i]);
//	echo $ip."<br>\n";
//	echo $name."<br>\n";
	$phpgw->db->query("INSERT INTO napster_servers(name,ip,port,network,users,files,gb,lastupdated) "
			 ."VALUES('$name','$ip',$port,'$network',$users,$files,$gb,'$lastupdated')");
	$this->servers["$name"] = $ip.":".$port;
      }
    } else {
      echo "Can't read napigator file\n";
    }
  }

  function select_options($k, $a, $x) {
  // $x decides whether to compare $k with key or val
    $str = "";
    if ($x==0) { 
      while (list ($key, $val) = each ($a)) {
	if(!strcmp($k,$val))
	  $str .= "<option selected value=\"$val\">$key</option>\n";
	else
	  $str .= "<option value=\"$val\">$key</option>\n";
      }
    } else {
      while (list ($key, $val) = each ($a)) {
	if(!strcmp($k,$key))
	  $str .= "<option selected value=\"$key\">$val</option>\n";
	else
	  $str .= "<option value=\"$key\">$val</option>\n";
      }
    }
    return $str;
  }

  function get_post_string() {
    global $HTTP_POST_VARS;
    global $QUERY_STRING;

    $s = "?";
    if($QUERY_STRING != "")
      return "?$QUERY_STRING";
    else {
      while(list($key,$val) = each($HTTP_POST_VARS)) {
	$s .= "$key=$val&";
      }
    }
    return $s;
  }

  function get_key($v, $a) {
    while (list ($key, $val) = each ($a)) {
      if(!strcmp($v,$val))
	return $key;
    }
  }

  function write_packet($m_type, $m_mesg) {
    global $phpgw;

    $pkt_len = strlen($m_mesg);
    if($pkt_len <= 0) {
      echo "Error : Nothing to be sent to server<br>\n";
      exit;
    }
    $packet = pack( "vv",$pkt_len, $m_type);
    $packet .= $m_mesg;
    if(!$phpgw->network->bs_write_port($packet)) {
      echo $phpgw->network->error["msg"].":".$phpgw->network->error["desc"]."<br>\n";
      exit;
    }
  }

  function read_packet() {
    global $phpgw;

    $data_array= "";
    $buf = $phpgw->network->bs_read_port(4);

    if(strlen($buf) != 4) {
      echo "Error : Server is probably busy. <$buf><br>\n";
      exit;
    }
    $buf1 = unpack("v2vals",$buf);
    $len1 = (int)$buf1["vals1"];
    $msg_type1 = $buf1["vals2"];
    if((int)$len1 <=0 ) {
      $data_array[0] = (int)$len1;
      $data_array[1] = $msg_type1;
      $data_array[2] =  " \n";
    } else {
      $data = $phpgw->network->bs_read_port((int)$len1);
      $data_array[0] = (int)$len1;
      $data_array[1] = $msg_type1;
      $data_array[2] = $data;
    }
    return $data_array;
  }

  function printstats($stats) {
    list($users, $files, $size) = explode( " ", $stats);
    return "<br><br>Server Stats: $users users logged in, $files files available, $size Gb total library size <br>";
  }

  function motd()
  {
    $str = "";
    $last="";
    $this->in_motd = 1;
    do {
      $buffer = $this->read_packet();
      $last = ereg_replace("\n","<br>",$last);
      $str .= " $last ";
      $last = $buffer[2];
    } while ((int)$buffer[1]==$this->message_type_sysmsg);

    // the last line of the system message usually has the server stats
    $str .= $this->printstats($buffer[2]);
    return $str;
  }

  function init_conn() {
    global $phpgw;
    global $phpgw_info;
    global $PHP_SELF;

    $this->in_motd = 0;

    $hostarray = explode(":", $this->napserver);
//    $host = $hostarray[0];
//    $port = $hostarray[1];
    
    //now we know the hostname and port to connect to
    $phpgw->network->open_port($hostarray[0], $hostarray[1]);
    if (isset($phpgw->network->errorset) && $phpgw->network->errorset) {
      echo $phpgw->network->error["msg"].":".$phpgw->network->error["desc"]."<br>\n";
      return False;
    } else {
      //now we can send a login packet
//      $login_string =  $phpgw_info["user"]["userid"]." ". $phpgw->common->decrypt($phpgw->session->passwd)." 6699 \"v2.0 BETA 6\" 1";
      $login_string =  $phpgw_info["user"]["userid"]." ".$phpgw->common->decrypt($phpgw_info["user"]["passwd"])." 6699 \"v2.0 BETA 6\" 1";
      $this->write_packet($this->message_type_login, $login_string);
      flush();
      $buffer = $this->read_packet();

      if((int)$buffer[1] != $this->message_type_login_response) {
	echo "Error : Unable to login to server<br>\n";
	if((int)$buffer[1] == $this->message_type_error)
	  echo " ".$buffer[2]."<br>\n";
	else {
	  echo "The server may be busy or it might have reached the MAX user limit. Retrying automatically in 3 seconds...";
	  echo "<meta http-equiv=\"refresh\" content=\"3;URL=$PHP_SELF". $this->get_post_string() . "\">";
	}
	return False;
      }
    }
    return True;
  }

  function browse_userlist($nick) {

    $this->write_packet($this->message_type_browse, $nick);
  
    $songs[0]= "";
    $browse_done = FALSE;
    $i=0;
  
    do {
      $browse_result = $this->read_packet();

      switch ($browse_result[1]) {
	case $this->message_type_browse_complete:
	  $browse_done = TRUE;
	  break;
	case $this->message_type_browse_result:
	  $songs[$i]=trim($browse_result[2]);
	  $i++;
	  break;
	default:
	  break;
      }  //end of switch

    } while (!$browse_done);
  
    if ($i == 0)
      return "";
    else return $songs;
  }

  function find_song($keywords){
    global $phpgw_info;

    $find_str = "FILENAME CONTAINS \"$keywords\" MAX_RESULTS ".$phpgw_info["user"]["preferences"]["common"]["maxmatchs"]." LINESPEED \"" . $this->linespeed . "\" ".$this->linktype;

    $this->write_packet($this->message_type_search, $find_str);

    $songs[0]= "";
    $search_done = FALSE;
    $i=0;

    do {
      $search_result = $this->read_packet();

      switch ($search_result[1]) {
	case $this->message_type_search_complete:
	  $search_done = TRUE;
	  break;
	case $this->message_type_search_result:
	  $songs[$i]=trim($search_result[2]);
	  $i++;
	  break;
	default:
	  break;
      }  //end of switch

    } while (!$search_done);

    if ($i == 0)
      return "";
    else return $songs;
  }

  function status($title, $nick){
    if(in_array($nick, $firewall_nicks)) {
      return 0;
    } elseif(in_array($nick, $ok_nicks)) {
      return 4;
    }

    //send message to server
    $message =  "$nick  ";
    $message .=  "$title";
    $this->write_packet($this->message_type_fileinfo_req, $message);
    $answer = "";
    flush();
    $answer = $this->read_packet();

    if((int)$answer[1]==$this->message_type_get_error) {
      return 1;
      flush();
    } elseif((int)$answer[1]==$this->message_type_stats) {
      return $this->status($nick, $title);
    } elseif((int)$answer[1]==$this->message_type_sysmsg) {
      while((int)$answer[1]==$this->message_type_sysmsg)
	$answer = $this->read_packet();
    } elseif((int)$answer[1]!=$this->message_type_fileinfo) {
      // return if we did not receive download ack
      return 3;
    } else {
      // server returns the download ack
      $ruser = strtok($answer[2],  " ");
      $rhost = strtok( " ");
      $rport = strtok( " ");
      if ($rport != 0) {
	$this->ok_nicks[count($this->ok_nicks)] = $nick;
	return 4;
      } else {
	$this->firewall_nicks[count($this->firewall_nicks)] = $nick;
	return 0;
      }
    }
  }


  function cmp_title($a, $b) {
    return strcasecmp($a->filename, $b->filename);
  }

  function cmp_nick($a, $b) {
    return strcasecmp($a->nick, $b->nick);
  }

  function cmp_speed($a, $b) {
    if ($a->conn_speed == $b->conn_speed) return 0;
    return ($a->conn_speed > $b->conn_speed) ? -1 : 1;
  }

  function cmp_size($a, $b) {
    if ($a->size == $b->size) return 0;
    return ($a->size > $b->size) ? -1 : 1;
  }

  function cmp_time($a, $b) {
    if ($a->time == $b->time) return 0;
    return ($a->time > $b->time) ? -1 : 1;
  }

  function cmp_bitrate($a, $b) {
    if ($a->bitrate == $b->bitrate) return 0;
    return ($a->bitrate > $b->bitrate) ? -1 : 1;
  }

  function cmp_freq($a, $b) {
    if ($a->frequency == $b->frequency) return 0;
    return ($a->frequency > $b->frequency) ? -1 : 1;
  }

  function searchmp3($keyword, $type) {
    global $phpgw;
    global $phpgw_info;
    global $PHP_SELF;
    global $nick;
    global $sort, $FORMPOST;
    global $bd;
  
    include($phpgw_info["server"]["app_inc"]."/songs.inc.php");

    if($type)
      $songs = $this->browse_userlist($keyword);
    else
      $songs = $this->find_song($keyword);
    if (is_string($songs)) {
      echo "Your search returned 0 songs.\n";
      exit;
    } else
      $numsongs = count($songs);

    for($i=0;$i<$numsongs;$i++) {
      $songlist[$i] = new Song;
      $songlist[$i]->init_song($songs[$i], $type);
      if($type)
        $songlist[$i]->conn_speed = $this->conn_speed;
    }
  
    if ($this->nofirewall) {  
      // filter out firewall results
      $j=0;
      for ($i=0;$i<$numsongs;$i++) {
	switch ($this->status($songlist[$i]->title, $songlist[$i]->nick)) {
	  case 0:
	    $songlist[$i]->firewall = 1;
	    break;
	  case 1:
	    break;
	  case 2:
	    break;
	  case 3:
	    break;
	  case 4:
	    //	$newsonglist[$j] = $songlist[$i];
	    //	$j++;
	    break;
	  default:
	    break;
	}
      }
      // $songlist = $newsonglist;
      // $numsongs = count($songlist);
    }

    if ($numsongs == 0) {
      echo "Your search returned 0 songs.\n";
      exit;
    } else {
?>
      <table width="775" border="0">
	<tr>
	  <td align="left">
	    Your search returned <?php echo $numsongs; ?> songs.
	  </td>
	  <td align="right">
	    <font size="-1" face="<?php echo $phpgw_info["theme"]["font"]; ?>">
	      Note: Layout optimized for <a href="http://www.microsoft.com/windows/ie/ie5/default.asp\">IE5+</a> and <a href="http://www.mozilla.org">Mozilla</a>.
	    </font>
	  </td>
	</tr>
      </table>
<?php    
      //now $songs contains the list of songs we have
      //start printing results
      if($bd) {
?>
	<TABLE border="1" bordercolor="<?php echo $phpgw_info["theme"]["th_bg"]; ?>" width="775" cellspacing="0" cellpadding="0" rules="rows" frame="border">
<?php
      } else {
?>
        <TABLE border="0" width="775" cellspacing="0" cellpadding="0">
<?php
      }
?>
      <tr bgcolor="<?php echo $phpgw_info["theme"]["th_bg"]; ?>">
	<td width="30">&nbsp;</td>
<?php
      if($FORMPOST)
?>
	<td width="30" valign="center">&nbsp;</td>
      <td valign="center" width="400">
<?php
      $url = $phpgw->link("$PHP_SELF","napserver=".$this->napserver
				     ."&keywords=$keyword"
				     ."&nofirewall=".$this->nofirewall
				     ."&max=".$phpgw_info["user"]["preferences"]["maxmatchs"]
				     ."&linktype=".$this->linktype
				     ."&linespeed=".$this->linespeed);
      if(isset($nick))
	$url .= "&nick=$nick&conn_speed=".$this->conn_speed;
?>
	<a href="<?php echo $url."&sort=5"; ?>">Title</a>
      </td>
      <td align="center" width="75">
<?php
    // sort on different columns
      switch($sort) {
	case 0: 
	  usort($songlist, $this->cmp_speed);
	  $col0 = "Speed"; $type0 = $sort;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
	case 1: 
	  usort($songlist, $this->cmp_size);
	  $col0 = "Size"; $type0 = $sort;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Speed"; $type2 = 0;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
	case 2: 
	  usort($songlist, $this->cmp_time);    
	  $col0 = "Time"; $type0 = $sort;
	  $col1 = "Speed"; $type1 = 0;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
	case 3: 
	  usort($songlist, $this->cmp_bitrate); 
	  $col0 = "Bitrate"; $type0 = $sort;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Speed"; $type3 = 0;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
	case 4: 
	  usort($songlist, $this->cmp_freq);    
	  $col0 = "Frequency"; $type0 = $sort;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Speed"; $type4 = 0;
	  break;
	case 5:
	  usort($songlist, $this->cmp_title);
	  $col0 = "Speed"; $type0 = 0;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
	case 6:
	  usort($songlist, $this->cmp_nick);
	  $col0 = "Speed"; $type0 = 0;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
	default:
	  usort($songlist, $this->cmp_speed);
	  $col0 = "Speed"; $type0 = $sort;
	  $col1 = "Time"; $type1 = 2;
	  $col2 = "Size"; $type2 = 1;
	  $col3 = "Bitrate"; $type3 = 3;
	  $col4 = "Frequency"; $type4 = 4;
	  break;
      }

?>
	<a href="<?php echo $url."&sort=$type0"; ?>"><?php echo $col0; ?></a>
      </td>
      <td align="center" width="120">
	<table width="120" border="0" cellpadding="1" cellspacing="2">
	  <tr>
	    <td width="60" align="center">
	      <a href="<?php echo $url."&sort=$type1"; ?>"><?php echo $col1; ?></a>
	    </td>
	    <td width="60" align="center">
	      <a href="<?php echo $url."&sort=$type2"; ?>"><?php echo $col2; ?></a>
	    </td>
	  </tr>
	  <tr>
	    <td width="60" align="center">
	      <a href="<?php echo $url."&sort=$type3"; ?>"><?php echo $col3; ?></a>
	    </td>
	    <td width="60" align="center">
	      <a href="<?php echo $url."&sort=$type4"; ?>"><?php echo $col4; ?></a>
	    </td>
	  </tr>
	</table>
      </td>
      <td align="center" width="150">
	<a href="<?php echo $url."&sort=6"; ?>">Nick</a>
      </td>
    </tr>
<?php
      if($bd)
?>
  </table>
<?php
      $odd = $numsongs % 2;
      // print songs with alternate row colors
      if($odd)
	$j=0;
      else $j=1;
      $bgcolor=""; $frame=""; $rules="";

      for($i=0;$i<$numsongs;$i++) {
        $tr_color = $phpgw->nextmatchs->alternate_row_color($tr_color);

	if($j==0) {
	  if($border) {
	    $frame="border";
	    $rules="rows";
	  } else {
	    $frame="vsides";
	    $rules="none";
	  }
	} else {
	  $frame="vsides";
	  $rules="none";
	}
	if($bd)
?>
  <table width="775" bordercolor="<?php echo $phpgw_info["theme"]["th_bg"]; ?>" border="1" frame="<?php echo $frame; ?>" bgcolor="<?php echo $tr_color; ?>" cellspacing="0" cellpadding="0">
<?php      
        $j = !$j;
?>
    <tr bgcolor="<?php echo $tr_color; ?>" valign="center">
      <td valign="top" width="30" align="right"><?php echo ($i+1); ?></td>
<?php
        $songlist[$i]->print_song($sort);
?>
    </tr>
<?php
        if($bd)
?>
  </table>
<?php
      }
      if(!$border && $bd) {
        if($formdownload)
	  $cols=6;
        else
	  $cols=5;
?>
  <table width="775" bordercolor="<?php echo $phpgw_info["theme"]["th_bg"]; ?>" border="1" frame="above" rules="none" bgcolor="<?php echo $phpgw_info["theme"]["th_bg"]; ?>" cellspacing="0" cellpadding="0">
    <tr>
      <td colspan="<?php echo $cols; ?>">&nbsp;</td>
    </tr>
  </table>
<?php
      }
      if(!$bd)
?>
  </table>
<?php
    }
  }

  function get_freeport() {
    // retrieve a free port from file
    global $phpgw;

    $port = 0;
    $phpgw->db->query("SELECT port FROM napster_ports WHERE state=0");

    if($phpgw->db->num_rows()) {
      $phpgw->db->next_record();
      $port = $phpgw->db->f("port");
      $phpgw->db->query("UPDATE napster_ports SET state=1 WHERE port=$port");
    }
    return $port;
  }

  function add_freeport($port) {
    // reuse port, append to freeport queue
    global $phpgw;

    if(!(int)$port)
      return;

    $phpgw->db->query("UPDATE napster_ports SET state=0 WHERE port=$port");
  }

  function uinttoip($hostname) {
    $flag=0;
    $storage = $hostname;
    $temp = (double) $hostname;
    $temp = $temp - 2147483648.0;
    $hostname = (int)$temp;
    if ($hostname < 0 )
      $hostname = (int) $storage;
    else $flag=1;

    $dig4 = ($hostname & 2130706432) >> 24;

    if ($flag == 1)
      $dig4 += 128;
    $dig3 = ($hostname & 16711680) >> 16;
    $dig2 = ($hostname & 65280) >> 8;
    $dig1 = $hostname & 255;
  
    //  echo "<br> dig1 is $dig1  dig2 is $dig2  dig3 is $dig3  dig4 is $dig4<br>";

    $hname = (string) $dig1;
    $hname = $hname .  ".";
    $hname = $hname . (string)$dig2;
    $hname = $hname .  ".";
    $hname = $hname . (string)$dig3;
    $hname = $hname .  ".";
    $hname = $hname . (string)$dig4;

    return (string)$hname;
  }


  function getmp3() {
    global $QUERY_STRING;

    //we have already logged in. The find song code can then be called
    //repeatedly

//    if ($QUERY_STRING != "") {
//      $this->title = stripslashes($this->title);
//      $this->nick = stripslashes($this->nick);
//    }

//    $this->title = unserialize($this->title);  
//    $this->nick = unserialize($this->nick);  

    $temp = strrchr($this->title, '\\');
    if (!$temp)
      $this->filename = $this->title;
    else 
      $this->filename = substr($temp, 1, strlen($temp)-2);

    return $this->download_song();
  }

  function download_song() {

    $nick = $this->nick;
    $title = $this->title;
    //send message to server
    $message =  "$nick $title";

    $this->write_packet($this->message_type_fileinfo_req, $message);
    $answer = "";
    $gotreply = 0;
    flush();

    $answer = $this->read_packet();

    while(!$gotreply) {
      if((int)$answer[1]==$this->message_type_get_error) {
	echo "<br> Download Error. The remote file you requested to download is unavailable.<br>\n";
        exit;
      } elseif((int)$answer[1]==$this->message_type_stats) {
	$this->write_packet($this->message_type_fileinfo_req, $message);
	$answer = "";
	flush();
	$answer = $this->read_packet();
      } elseif((int)$answer[1]==$this->message_type_sysmsg) {
	while((int)$answer[1]==$this->message_type_sysmsg) {
	  $answer = $this->read_packet();
	}	  
	$this->write_packet($this->message_type_fileinfo_req, $message);
	$answer = "";
	flush();
	$answer = $this->read_packet();
      } elseif((int)$answer[1]!=$this->message_type_fileinfo) {
	// return if we did not receive download ack
	echo "<br> Download Error. Did not receive download ACK: ".$answer[1]." ".$answer[2]."<br>\n";
	exit;
      } else
	$gotreply = 1;
    }

    // server returns the download ack with remote host and port
    list($ruser,$rhost,$rport) = explode(" ",$answer[2]);

    //Convert the $rhost to quad dotted ip address format
    $rhost = $this->uinttoip($rhost);
    flush();

    if ($rport != 0)
      return $this->download($rhost,$rport);
    else
      return $this->fdownload();
  }

  function download($rhost,$rport) {
    global $phpgw;
    global $phpgw_info;

    $MTU = 15000;

    $remote_user = new network(False);
    $remote_user->open_port($rhost,$rport,30);
    if (isset($remote_user->errorset) && $remote_user->errorset) {
      echo $remote_user->error["msg"].":".$remote_user->error["desc"]."<br>\n";
      return;
    }

    //read magic character '1'
    $dt = (string)$remote_user->bs_read_port(1);
    if ($dt != "1") {
      echo "<br>ERROR Expected magic character '1' from remote user: $dt\n";
      return false;
    }

    $remote_user->bs_write_port("GET");         // write string "GET"
    flush();
    //send file name to get
    $mess = $phpgw_info["user"]["userid"]." ".$this->title . " 0";
    $remote_user->bs_write_port($mess);
    flush();

    //read the size of the mp3 file
    $file_length = "";
    $temp=0;
    for ($i=0;$i<$MTU;$i++){
      $temp = $remote_user->bs_read_port(1);
      if ($temp < '0' || $temp > '9') {
        break;
      }
      $file_length .= $temp;
    }

    $mpsize = (int)$file_length;
    settype($mpsize,"integer");
    flush();

    if ($mpsize <= 0) {
      echo "<br>ERROR. Remote user sent an invalid filesize: $mpsize\n";
      return false;
    }
    $num = pack( "C",$temp);

    // start sending file. indicate browser to download.
//    header(  "Content-Type: application/download" );
//    header(  "Content-Disposition: attachment; filename=\"".$this->filename."\"" );
//    header(  "Content-Length: $mpsize" );

//    echo $num;    //first byte of mp3 file

    $content = $num;

    $count=1;
    do {
      $received = $remote_user->bs_read_port($MTU);
      $count += $MTU;
      $content .= $received;
    } while ($count<$mpsize);
    unset($remote_user);
    $phpgw->vfs->write($this->filename,$content);
    return true;
  }

  function fdownload() {
    // implements firewall download by calling a perl script
    // to listen on a local socket

    global $phpgw;
    global $phpgw_info;
    global $phpgw_flags;
    $MTU = 15000;

    $lport = $this->get_freeport();
    if(!$lport) {
      echo "MAX firewall download limit reached. Try again in a few minutes.<br>\n";
      exit;
    }
    $this->write_packet($this->message_type_change_port, $lport);
    $this->write_packet($this->message_type_alt_download_req, $this->nick." ".$this->title);
  
    $fp = popen($phpgw_info["server"]["server_root"]."/".$phpgw_info["flags"]["currentapp"]."/firewall.pl ".$lport, "r");
    if (!$fp) {
      $this->add_freeport($lport);
      echo "Couldn't run perl script.<br>\n";
      exit;
    }

    $buf = fgets($fp, 8);
    if (!strcmp(substr($buf, 0, 5), "error")) {
      $error_string = $buf;
      $buf = fgets($fp, 100);
      if(strstr($buf, "bind"))
        $error_string .= $buf . "<br>Another user is currently using firewall download on the same port.<br>";
      elseif(strstr($buf, "alarm"))
        $error_string .= $buf . "<br>The remote user did not send any data. Perhaps the user has logged off or disabled file sharing.";
      elseif(strstr($buf, "response"))
        $error_string .= $buf . "<br>The remote user sent invalid data. Perhaps the file you requested does not exist.";
      $this->add_freeport($lport);
      echo $error_string;
      return False;
    }

    $this->write_packet($this->message_type_download_file, " ");
//    header(  "Content-Type: application/octet-stream" );
//    header(  "Content-Disposition: attachment; filename=".$this->filename );
    flush();

    $content = $buf;
    while(!feof($fp)) {
      $answer = fread($fp, $MTU);
      $content .= $answer;
      flush();
    }
    $phpgw->vfs->write($this->filename,$content);
    if(isset($fp))
      pclose($fp);
    if($lport) {
      $this->add_freeport($lport);
      $lport=0;
    }
    $this->write_packet($this->message_type_download_complete, " ");
    return;
  }
}
?>
