示例#1
0
        /// <summary>
        /// Change playlist container. The response comes as plain XML.
        /// </summary>
        public void SendChangePlaylistContainer(IChannelListener listener, PlaylistContainer playlistContainer, string xml)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Change-Playlist-Container-Channel", Channel.ChannelType.TYPE_PLAYLIST, listener);
            byte[]          bytes   = Encoding.UTF8.GetBytes(xml);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 16 + 1 + 4 + 4 + 4 + 1 + 1 + bytes.Length);

            /* Append channel id, playlist id and some bytes... */
            buffer.PutShort((short)channel.Id);
            buffer.Put(Hex.ToBytes("00000000000000000000000000000000")); /* 16 bytes */
            buffer.Put((byte)0x00);                                      /* Playlists identifier. */
            buffer.PutInt((int)playlistContainer.Revision);
            buffer.PutInt(playlistContainer.Playlists.Count);
            buffer.PutInt((int)playlistContainer.Checksum);
            buffer.Put((byte)0x00); /* Collaborative */
            buffer.Put((byte)0x03); /* Unknown */
            buffer.Put(bytes);
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_CHANGEPLAYLIST, buffer);
        }
示例#2
0
        /// <summary>
        /// Create playlist. The response comes as plain XML.
        /// </summary>
        public void SendCreatePlaylist(IChannelListener listener, Playlist playlist, string xml)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Change-Playlist-Channel", Channel.ChannelType.TYPE_PLAYLIST, listener);
            byte[]          bytes   = Encoding.UTF8.GetBytes(xml);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 16 + 1 + 4 + 4 + 4 + 1 + 1 + bytes.Length);

            /* Append channel id, playlist id and some bytes... */
            buffer.PutShort((short)channel.Id);
            buffer.Put(Hex.ToBytes(playlist.Id)); /* 16 bytes */
            buffer.Put((byte)0x02);               /* Playlist identifier. */
            buffer.PutInt(0);
            buffer.PutInt(0);
            buffer.PutInt(-1);      /* -1: Create playlist. */
            buffer.Put((byte)(playlist.IsCollaborative ? 0x01 : 0x00));
            buffer.Put((byte)0x03); /* Unknown */
            buffer.Put(bytes);
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_CHANGEPLAYLIST, buffer);
        }
示例#3
0
        /// <summary>
        /// Get a toplist. The response comes as GZIP compressed XML.
        /// </summary>
        public void SendToplistRequest(IChannelListener listener, Dictionary <string, string> paramargs)
        {
            /* Check if type parameter is present. */
            if (!paramargs.ContainsKey("type"))
            {
                throw new ArgumentException("Parameter 'type' not given!");
            }

            /* Create a map of parameters and calculate their length. */
            Dictionary <byte[], byte[]> parameters = new Dictionary <byte[], byte[]>();
            int parametersLength = 0;

            foreach (KeyValuePair <String, String> param in paramargs)
            {
                if (param.Key == null || param.Value == null)
                {
                    continue;
                }

                byte[] key   = Encoding.UTF8.GetBytes(param.Key);
                byte[] value = Encoding.UTF8.GetBytes(param.Value);

                parametersLength += 1 + 2 + key.Length + value.Length;

                parameters.Add(key, value);
            }

            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Toplist-Channel", Channel.ChannelType.TYPE_TOPLIST, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 2 + 2 + parametersLength);

            /* Append channel id, some values, query length and query. */
            buffer.PutShort((short)channel.Id);
            buffer.PutInt(0x00000000);

            foreach (KeyValuePair <byte[], byte[]> parameter in parameters)
            {
                byte[] key   = parameter.Key;
                byte[] value = parameter.Value;

                buffer.Put((byte)key.Length);
                buffer.PutShort((short)value.Length);
                buffer.Put(key);
                buffer.Put(value);
            }

            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_GETTOPLIST, buffer);
        }
示例#4
0
        public void Load(string category, string hash, IChannelListener listener)
        {
            /* Load data in a separate thread, because we're an asynchronous load method. */

            new Thread(delegate() {
                Channel channel = new Channel("Cached-Substream-Channel", ChannelType.TYPE_SUBSTREAM, null);
                listener.ChannelHeader(channel, null);
                listener.ChannelData(channel, Load(category, hash));
                listener.ChannelEnd(channel);
            }).Start();
        }
示例#5
0
        /// <summary>
        /// Get metadata for an artist (type = 1), album (type = 2) or a
        /// list of tracks (type = 3). The response comes as compressed XML.
        /// </summary>
        public void SendBrowseRequest(IChannelListener listener, int type, List <String> ids)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Browse-Channel", Channel.ChannelType.TYPE_BROWSE, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 2 + 1 + ids.Count * 16 + ((type == 1 || type == 2) ? 4 : 0));

            /* Check arguments. */
            if (type != 1 && type != 2 && type != 3)
            {
                throw new ArgumentException("Type needs to be 1, 2 or 3.");
            }
            else if ((type == 1 && type == 2) && ids.Count != 1)
            {
                throw new ArgumentException("Types 1 and 2 only accept a single id.");
            }

            /* Append channel id and type. */
            buffer.PutShort((short)channel.Id);
            buffer.PutShort((short)0x0000);         /* Unknown. */
            buffer.Put((byte)type);

            /* Append (16 byte binary, 32 byte hex string) ids. */
            foreach (string id in ids)
            {
                /* Check length of id. */
                if (id.Length != 32)
                {
                    throw new ArgumentException("Id needs to have a length of 32.");
                }

                buffer.Put(Hex.ToBytes(id));
            }

            /* Append zero. */
            if (type == 1 || type == 2)
            {
                buffer.PutInt(0);             /* Timestamp of cached version? */
            }

            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_BROWSE, buffer);
        }
示例#6
0
        /// <summary>
        /// Request ads. The response is GZIP compressed XML.
        /// </summary>
        public void SendAdRequest(IChannelListener listener, int type)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Ad-Channel", Channel.ChannelType.TYPE_AD, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 1);

            /* Append channel id and ad type. */
            buffer.PutShort((short)channel.Id);
            buffer.Put((byte)type); /* 0: audio, 1: banner, 2: fullscreen-banner, 3: unknown.  */
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_REQUESTAD, buffer);
        }
示例#7
0
        /// <summary>
        /// Request playlist details. The response comes as plain XML.
        /// </summary>
        public void SendPlaylistRequest(IChannelListener listener, string id)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Playlist-Channel", Channel.ChannelType.TYPE_PLAYLIST, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 16 + 1 + 4 + 4 + 4 + 1);

            /* Check length of id. */
            if (id != null && id.Length != 32)
            {
                throw new ArgumentException("Playlist id needs to have a length of 32.");
            }

            /* Append channel id, playlist id and some bytes... */
            buffer.PutShort((short)channel.Id);

            /* Playlist container. */
            if (id == null)
            {
                buffer.Put(Hex.ToBytes("00000000000000000000000000000000")); /* 16 bytes */
                buffer.Put((byte)0x00);                                      /* Playlist container identifier. */
            }
            /* Normal playlist. */
            else
            {
                buffer.Put(Hex.ToBytes(id)); /* 16 bytes */
                buffer.Put((byte)0x02);      /* Playlist identifier. */
            }

            /*
             * TODO: Other playlist identifiers (e.g. 0x03, starred tracks? inbox?).
             */

            /* TODO: Use those fields to request only the information needed. */
            buffer.PutInt(-1);      /* Revision. -1: no cached data. */
            buffer.PutInt(0);       /* Number of entries. */
            buffer.PutInt(1);       /* Checksum. */
            buffer.Put((byte)0x00); /* Collaborative. */
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_GETPLAYLIST, buffer);
        }
示例#8
0
        /// <summary>
        /// Request a part of the encrypted file from the server.
        ///
        /// The data should be decrypted using AES key in CTR mode
        /// with AES key provided and a static IV, incremented for
        /// each 16 byte data processed.
        /// </summary>
        public void SendSubstreamRequest(IChannelListener listener, Sharpotify.Media.File file, int offset, int length)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Substream-Channel", Channel.ChannelType.TYPE_SUBSTREAM, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 2 + 2 + 2 + 2 + 2 + 2 + 4 + 20 + 4 + 4);

            /* Append channel id. */
            buffer.PutShort((short)channel.Id);

            /* Unknown 10 bytes. */
            buffer.PutShort((short)0x0800);
            buffer.PutShort((short)0x0000);
            buffer.PutShort((short)0x0000);
            buffer.PutShort((short)0x0000);
            buffer.PutShort((short)0x0000);
            buffer.PutShort((short)0x4e20);

            /* Unknown (static value) */
            buffer.PutInt(200 * 1000);

            /* 20 bytes file id. */
            buffer.Put(Hex.ToBytes(file.Id));

            if (offset % 4096 != 0 || length % 4096 != 0 || length == 0)
            {
                throw new ArgumentException("Offset and length need to be a multiple of 4096.");
            }

            offset >>= 2;
            length >>= 2;

            /* Append offset and length. */
            buffer.PutInt(offset);
            buffer.PutInt(offset + length);
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_GETSUBSTREAM, buffer);
        }
示例#9
0
        /// <summary>
        /// Request AES key for a track.
        /// </summary>
        public void SendAesKeyRequest(IChannelListener listener, Track track, Sharpotify.Media.File file)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("AES-Key-Channel", Channel.ChannelType.TYPE_AESKEY, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(20 + 16 + 2 + 2 + 2);

            /* Request the AES key for this file by sending the file id and track id. */
            buffer.Put(Hex.ToBytes(file.Id));  /* 20 bytes */
            buffer.Put(Hex.ToBytes(track.Id)); /* 16 bytes */
            buffer.PutShort((short)0x0000);
            buffer.PutShort((short)channel.Id);
            buffer.PutShort((short)0x0000);
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_REQKEY, buffer);
        }
示例#10
0
        /// <summary>
        /// Search music. The response comes as GZIP compressed XML.
        /// </summary>
        public void SendSearchQuery(IChannelListener listener, string query, int offset, int limit)
        {
            /* Create channel and buffer. */
            byte[]          queryBytes = Encoding.UTF8.GetBytes(query);
            Channel.Channel channel    = new Channel.Channel("Search-Channel", Channel.ChannelType.TYPE_SEARCH, listener);
            ByteBuffer      buffer     = ByteBuffer.Allocate(2 + 2 + 6 * 4 + 2 + 1 + queryBytes.Length);

            /* Check offset and limit. */
            if (offset < 0)
            {
                throw new ArgumentException("Offset needs to be >= 0");
            }
            else if ((limit < 0 && limit != -1) || limit == 0)
            {
                throw new ArgumentException("Limit needs to be either -1 for no limit or > 0");
            }

            /* Append channel id, some unknown values, query length and query. */
            buffer.PutShort((short)channel.Id);
            buffer.PutShort((short)0x0000); /* Unknown. */
            buffer.PutInt(offset);          /* Track offset. */
            buffer.PutInt(limit);           /* Track limit. */
            buffer.PutInt(offset);          /* Album offset. */
            buffer.PutInt(limit);           /* Album limit. */
            buffer.PutInt(offset);          /* Artist offset. */
            buffer.PutInt(limit);           /* Artist limit. */
            buffer.PutShort((short)0x0000); /* Unknown. */
            buffer.Put((byte)queryBytes.Length);
            buffer.Put(queryBytes);
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_SEARCH, buffer);
        }
示例#11
0
        /// <summary>
        /// Request image using a 20 byte id. The response is a JPG.
        /// </summary>
        public void SendImageRequest(IChannelListener listener, string id)
        {
            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Image-Channel", Channel.ChannelType.TYPE_IMAGE, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 2 + 20);

            /* Check length of id. */
            if (id.Length != 40)
            {
                throw new ArgumentException("Image id needs to have a length of 40.");
            }

            /* Append channel id and image hash. */
            buffer.PutShort((short)channel.Id);
            buffer.PutShort((short)0x0000);
            buffer.Put(Hex.ToBytes(id));
            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_IMAGE, buffer);
        }
示例#12
0
 public void ChannelHeader(Channel channel, byte[] header)
 {
     /* Do nothing. */
 }
示例#13
0
 public void ChannelError(Channel channel)
 {
     /* Do nothing. */
 }
示例#14
0
 public void ChannelEnd(Channel channel)
 {
     this._offset += channel.DataLength;
     Channel.Unregister(channel.Id);
 }
示例#15
0
 public static void Register(Channel channel)
 {
     Channel._channels.Add(channel.Id, channel);
 }
示例#16
0
 public void ChannelHeader(Channel channel, byte[] header)
 {
     /* Ignore */
 }
示例#17
0
 public void ChannelError(Channel channel)
 {
     this._done.Release();
 }
示例#18
0
 public void ChannelData(Channel channel, byte[] data)
 {
     ByteBuffer buffer = new ByteBuffer(data);
     this._bytes += data.Length;
     this._buffers.Add(buffer);
 }
示例#19
0
        public void ChannelData(Channel channel, byte[] data)
        {
            /* Offsets needed for deinterleaving. */
            int off, w, x, y, z;

            /* Copy data to cache buffer. */
            for (int i = 0; i < data.Length; i++)
            {
                this._cacheData[this._channelTotal + i] = data[i];
            }

            /* Allocate space for ciphertext. */
            byte[] ciphertext = new byte[data.Length + 1024];
            byte[] keystream = new byte[16];

            /* Decrypt each 1024 byte block. */
            for (int block = 0; block < data.Length / 1024; block++)
            {
                /* Deinterleave the 4x256 byte blocks. */
                off = block * 1024;
                w = block * 1024 + 0 * 256;
                x = block * 1024 + 1 * 256;
                y = block * 1024 + 2 * 256;
                z = block * 1024 + 3 * 256;

                for (int i = 0; i < 1024 && (block * 1024 + i) < data.Length; i += 4)
                {
                    ciphertext[off++] = data[w++];
                    ciphertext[off++] = data[x++];
                    ciphertext[off++] = data[y++];
                    ciphertext[off++] = data[z++];
                }

                /* Decrypt 1024 bytes block. This will fail for the last block. */
                for (int i = 0; i < 1024 && (block * 1024 + i) < data.Length; i += 16)
                {
                    /* Produce 16 bytes of keystream from the IV. */
                    try
                    {
                        var crypt = _cipher.CreateEncryptor(_key, _iv);
                        keystream = crypt.TransformFinalBlock(this._iv, 0, this._iv.Length);
                    }
                    catch (Exception)
                    {
                    }

                    /*
                     * Produce plaintext by XORing ciphertext with keystream.
                     * And somehow I also need to XOR with the IV... Please
                     * somebody tell me what I'm doing wrong, or is it the
                     * Java implementation of AES? At least it works like this.
                     */
                    // FIXME: Does the IV needs to be XORed in C# ?
                    for (int j = 0; j < 16; j++)
                    {
                        //ciphertext[block * 1024 + i + j] ^= (byte)(keystream[j] ^ this._iv[j]);
                        ciphertext[block * 1024 + i + j] ^= keystream[j];
                    }

                    /* Update IV counter. */
                    for (int j = 15; j >= 0; j--)
                    {
                        this._iv[j] += 1;

                        if ((int)(this._iv[j] & 0xFF) != 0)
                        {
                            break;
                        }
                    }

                    /* Set new IV. */
                    this._cipher.IV = this._iv;
                }
            }

            /* Save data to output stream. */
            try
            {
                off = 0;

                /* Check if we decoded the header yet. */
                if (this._header == null)
                {
                    /* Get header from data. */
                    byte[] bytes = new byte[167];
                    Array.Copy(ciphertext, bytes, bytes.Length);

                    /* Decode header. */
                    this._header = new SpotifyOggHeader(bytes);

                    off = 167;

                    //Set stream length
                    this._output.SetLength(this._header.Size);
                }

                this._output.WriteInternal(ciphertext, off, data.Length - off);
                //this._output.Write(ciphertext, off, data.Length - off);
                //this._output.Flush();

                /*
                 * Don't subtract 'off' here! Otherwise we would
                 * accidentially close the stream in channelEnd!
                 */
                this._channelTotal += data.Length;
            }
            catch (Exception)
            {
                /* Don't care. */
            }
        }
示例#20
0
 public void ChannelHeader(Channel channel, byte[] header)
 {
     this._cacheData = new byte[this._channelLength];
     this._channelTotal = 0;
 }
示例#21
0
        public void ChannelEnd(Channel channel)
        {
            /* Create cache hash. */
            string hash = this._cache.Hash(this._file, this._channelOffset, this._channelLength);

            /* Save to cache. */
            if (this._cache != null && !this._cache.Contains("substream", hash))
            {
                this._cache.Store("substream", hash, this._cacheData, this._channelTotal);
            }

            /* Send next substream request. */
            try
            {
                if (this._channelTotal < this._channelLength)
                {
                    this._output.AllAvailable = true;

                    return;
                }

                this._channelOffset += this._channelLength;

                hash = this._cache.Hash(this._file, this._channelOffset, this._channelLength);

                if (this._cache != null && this._cache.Contains("substream", hash))
                {
                    this._cache.Load("substream", hash, this);
                }
                else
                {
                    this._protocol.SendSubstreamRequest(this, this._file, this._channelOffset, this._channelLength);
                }
            }
            catch (Exception)
            {
                /* Ignore. */
            }

            Channel.Unregister(channel.Id);
        }
示例#22
0
        /// <summary>
        /// Request replacements for a list of tracks. The response comes as compressed XML.
        /// </summary>
        public void SendReplacementRequest(IChannelListener listener, List <Track> tracks)
        {
            /* Calculate data length. */
            int dataLength = 0;

            foreach (Track track in tracks)
            {
                if (track.Artist != null && track.Artist.Name != null)
                {
                    dataLength += Encoding.UTF8.GetBytes(track.Artist.Name).Length;
                }

                if (track.Album != null && track.Album.Name != null)
                {
                    dataLength += Encoding.UTF8.GetBytes(track.Album.Name).Length;
                }

                if (track.Title != null)
                {
                    dataLength += Encoding.UTF8.GetBytes(track.Title).Length;
                }

                if (track.Length != -1)
                {
                    dataLength += Encoding.UTF8.GetBytes((track.Length / 1000).ToString()).Length;
                }

                dataLength += 4;             /* Separators */
            }

            /* Create channel and buffer. */
            Channel.Channel channel = new Channel.Channel("Browse-Channel", Channel.ChannelType.TYPE_BROWSE, listener);
            ByteBuffer      buffer  = ByteBuffer.Allocate(2 + 2 + 1 + dataLength);

            /* Append channel id and type. */
            buffer.PutShort((short)channel.Id);
            buffer.PutShort((short)0x0000);         /* Unknown. */
            buffer.Put((byte)0x06);

            /* Append track info. */
            foreach (Track track in tracks)
            {
                if (track.Artist != null && track.Artist.Name != null)
                {
                    buffer.Put(Encoding.UTF8.GetBytes(track.Artist.Name));
                }

                buffer.Put((byte)0x01);             /* Separator. */

                if (track.Album != null && track.Album.Name != null)
                {
                    buffer.Put(Encoding.UTF8.GetBytes(track.Album.Name));
                }

                buffer.Put((byte)0x01);             /* Separator. */

                if (track.Title != null)
                {
                    buffer.Put(Encoding.UTF8.GetBytes(track.Title));
                }

                buffer.Put((byte)0x01);             /* Separator. */

                if (track.Length != -1)
                {
                    buffer.Put(Encoding.UTF8.GetBytes((track.Length / 1000).ToString()));
                }

                buffer.Put((byte)0x00);             /* Separator. */
            }

            buffer.Flip();

            /* Register channel. */
            Channel.Channel.Register(channel);

            /* Send packet. */
            this.SendPacket(Command.COMMAND_BROWSE, buffer);
        }
示例#23
0
        public void ChannelData(Channel channel, byte[] data)
        {
            /* Offsets needed for deinterleaving. */
            int off, w, x, y, z;

            /* Allocate space for ciphertext. */
            byte[] ciphertext = new byte[data.Length + 1024];
            byte[] keystream = new byte[16];

            /* Decrypt each 1024 byte block. */
            for (int block = 0; block < data.Length / 1024; block++)
            {
                /* Deinterleave the 4x256 byte blocks. */
                off = block * 1024;
                w = block * 1024 + 0 * 256;
                x = block * 1024 + 1 * 256;
                y = block * 1024 + 2 * 256;
                z = block * 1024 + 3 * 256;

                for (int i = 0; i < 1024 && (block * 1024 + i) < data.Length; i += 4)
                {
                    ciphertext[off++] = data[w++];
                    ciphertext[off++] = data[x++];
                    ciphertext[off++] = data[y++];
                    ciphertext[off++] = data[z++];
                }

                /* Decrypt 1024 bytes block. This will fail for the last block. */
                for (int i = 0; i < 1024 && (block * 1024 + i) < data.Length; i += 16)
                {
                    /* Produce 16 bytes of keystream from the IV. */
                    try
                    {
                        var crypt = _cipher.CreateEncryptor(_key, _iv);
                        keystream = crypt.TransformFinalBlock(this._iv, 0, this._iv.Length);
                    }
                    catch (Exception)
                    {
                    }

                    /*
                     * Produce plaintext by XORing ciphertext with keystream.
                     * And somehow I also need to XOR with the IV... Please
                     * somebody tell me what I'm doing wrong, or is it the
                     * Java implementation of AES? At least it works like this.
                     */
                    // FIXME: Does the IV needs to be XORed in C# ?
                    for (int j = 0; j < 16; j++)
                    {
                        ciphertext[block * 1024 + i + j] ^= (byte)(keystream[j] ^ this._iv[j]);
                    }

                    /* Update IV counter. */
                    for (int j = 15; j >= 0; j--)
                    {
                        this._iv[j] += 1;

                        if ((int)(this._iv[j] & 0xFF) != 0)
                        {
                            break;
                        }
                    }

                    /* Set new IV. */
                    this._cipher.IV = this._iv;
                }
            }

            /* Write data to output stream. */
            try
            {
                this._outputStream.Write(ciphertext, 0, ciphertext.Length - 1024);
            }
            catch (Exception)
            {
                /* Just don't care... */
            }
        }
示例#24
0
 public void ChannelError(Channel channel)
 {
     /* Ignore */
 }
示例#25
0
 public void ChannelEnd(Channel channel)
 {
     Channel.Unregister(channel.Id);
     this._done.Release();
 }