diff --git a/.gitignore b/.gitignore index 0bc8230..014c88c 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,7 @@ obj/ [Rr]elease*/ _ReSharper*/ [Tt]est[Rr]esult* +/.vs +#Don't ignore DebugControl UI Control +!Floe.UI/DebugControl/ +!Floe.UI/DebugControl/* \ No newline at end of file diff --git a/Floe.Audio/Exceptions.cs b/Floe.Audio/Exceptions.cs deleted file mode 100644 index bac3e1b..0000000 --- a/Floe.Audio/Exceptions.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace Floe.Audio -{ - [Serializable] - public class FileFormatException : Exception - { - public FileFormatException() - { - } - - public FileFormatException(string message) - : base(message) - { - } - } -} diff --git a/Floe.Audio/FifoStream.cs b/Floe.Audio/FifoStream.cs deleted file mode 100644 index 865895b..0000000 --- a/Floe.Audio/FifoStream.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; - -namespace Floe.Audio -{ - public class FifoStream : Stream - { - private const int BlockSize = 8192; - - private LinkedList _blocks; - private int _readIdx, _writeIdx; - private ManualResetEventSlim _pulse; - private bool _isDisposed; - - public FifoStream() - { - _blocks = new LinkedList(); - _pulse = new ManualResetEventSlim(false); - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return true; } } - public override void Flush() { throw new NotImplementedException(); } - public override long Length { get { throw new NotImplementedException(); } } - public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - public override void SetLength(long value) { throw new NotImplementedException(); } - - public override int Read(byte[] buffer, int offset, int count) - { - _pulse.Wait(); - if (_isDisposed) - { - return 0; - } - int total = 0; - lock (_blocks) - { - while (count > 0) - { - int written; - written = Math.Min(count, (_blocks.First == _blocks.Last ? _writeIdx : BlockSize) - _readIdx); - Array.Copy(_blocks.First.Value, _readIdx, buffer, offset, written); - count -= written; - offset += written; - _readIdx += written; - - if (_readIdx >= BlockSize) - { - _blocks.RemoveFirst(); - _readIdx = 0; - } - total += written; - - if (_blocks.First == null || - (_blocks.First == _blocks.Last && _readIdx >= _writeIdx)) - { - _pulse.Reset(); - break; - } - } - } - return total; - } - - public override void Write(byte[] buffer, int offset, int count) - { - if (count < 1) - { - return; - } - - lock (_blocks) - { - while (count > 0) - { - if (_blocks.Last == null || _writeIdx >= BlockSize) - { - _blocks.AddLast(new byte[BlockSize]); - _writeIdx = 0; - } - int written = Math.Min(count, BlockSize - _writeIdx); - Array.Copy(buffer, offset, _blocks.Last.Value, _writeIdx, written); - count -= written; - offset += written; - _writeIdx += written; - _pulse.Set(); - } - } - } - - public override void Close() - { - base.Close(); - _isDisposed = true; - _pulse.Set(); - } - } -} diff --git a/Floe.Audio/FilePlayer.cs b/Floe.Audio/FilePlayer.cs deleted file mode 100644 index 99709d7..0000000 --- a/Floe.Audio/FilePlayer.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using Floe.Interop; - -namespace Floe.Audio -{ - public class FilePlayer : IDisposable - { - private const int WavBufferSamples = 3000; - private static readonly byte[] WavFileSignature = { 0x52, 0x49, 0x46, 0x46 }; // RIFF - private static readonly byte[] Mp3FileSignature = { 0x49, 0x44, 0x33 }; // ID3 - - private WaveOut _waveOut; - - public event EventHandler Done; - - public FilePlayer(string fileName) - { - var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read); - var sig = new byte[4]; - try - { - fileStream.Read(sig, 0, 4); - fileStream.Seek(0, SeekOrigin.Begin); - if (WavFileSignature.SequenceEqual(sig.Take(WavFileSignature.Length))) - { - var wavStream = new WavFileStream(fileStream); - _waveOut = new WaveOut(wavStream, wavStream.Format, WavBufferSamples * wavStream.Format.FrameSize); - } - else if (Mp3FileSignature.SequenceEqual(sig.Take(Mp3FileSignature.Length))) - { - var mp3Stream = new Mp3FileStream(fileStream); - _waveOut = new WaveOut(mp3Stream, mp3Stream.Format, mp3Stream.Format.BlockSize + 1); - } - else - { - throw new FileFormatException("Unrecognized file format."); - } - } - catch (EndOfStreamException) - { - throw new FileFormatException("Premature end of file."); - } - _waveOut.EndOfStream += (sender, e) => - { - var handler = this.Done; - if(handler != null) - { - handler(this, EventArgs.Empty); - } - }; - } - - public void Start() - { - _waveOut.Start(); - } - - public void Close() - { - _waveOut.Close(); - } - - public void Dispose() - { - _waveOut.Dispose(); - } - - public static void PlayAsync(string fileName, Action callback = null, object state = null) - { - var player = new FilePlayer(fileName); - player.Done += (sender, e) => - { - if (callback != null) - { - callback(state); - } - player.Close(); - }; - player.Start(); - } - } -} diff --git a/Floe.Audio/Floe.Audio.csproj b/Floe.Audio/Floe.Audio.csproj deleted file mode 100644 index c5d1b0d..0000000 --- a/Floe.Audio/Floe.Audio.csproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {BDD20714-E82B-45C9-A310-BE57BA986F44} - Library - Properties - Floe.Audio - Floe.Audio - v4.0 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - - - ..\Floe.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {3CEFFCEB-C836-47CC-8B8A-EC5655E1B5B7} - Floe.Interop - - - {1D4AD463-4355-4DA6-B8E6-0E8BB75B50D9} - Floe.Net - - - - - \ No newline at end of file diff --git a/Floe.Audio/Mp3FileStream.cs b/Floe.Audio/Mp3FileStream.cs deleted file mode 100644 index 9138811..0000000 --- a/Floe.Audio/Mp3FileStream.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System; -using System.IO; - -using Floe.Interop; - -namespace Floe.Audio -{ - public class Mp3FileStream : Stream - { - private static readonly short[, ,] MpegBitRates = new short[2, 3, 16] - { - { - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }, - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }, - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 } - }, - { - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 }, - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }, - { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 } - } - }; - - private static readonly int[,] MpegSampleRates = new int[3, 4] - { - { - 44100, 48000, 32000, 0 - }, - { - 22050, 24000, 16000, 0 - }, - { - 11025, 12000, 8000, 0 - } - }; - - private Stream _stream; - private WaveFormatMp3 _format; - - public Mp3FileStream(string fileName) - : this(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - } - - public Mp3FileStream(Stream stream) - { - _stream = stream; - var bytes = new byte[10]; - _stream.Read(bytes, 0, 10); - if (bytes[3] != 0x03 || bytes[4] != 0x00) // v2.3.0 - { - throw new FileFormatException("Unsupported ID3 version."); - } - if (bytes[5] != 0x00) - { - throw new FileFormatException(string.Format("Unsupported ID3 flags ({0})", bytes[5])); - } - - _stream.Seek((bytes[6] << 21) | (bytes[7] << 14) | (bytes[8] << 7) | bytes[9], SeekOrigin.Current); - - int channels, bitRate, sampleRate; - int size = this.ReadFrameHeader(out channels, out sampleRate, out bitRate); - _format = new WaveFormatMp3((short)channels, sampleRate, bitRate * 1000); - } - - public WaveFormatMp3 Format { get { return _format; } } - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return false; } } - public override void Flush() { throw new NotImplementedException(); } - public override long Length { get { throw new NotImplementedException(); } } - public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - public override void SetLength(long value) { throw new NotImplementedException(); } - public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } - - public override int Read(byte[] buffer, int offset, int count) - { - int blockSize = this.ReadFrameHeader(); - int numRead = _stream.Read(buffer, offset, Math.Min(count, blockSize)); - if (blockSize > count) - { - _stream.Seek(blockSize - count, SeekOrigin.Current); - } - return numRead; - } - - public override void Close() - { - _stream.Close(); - } - - private int ReadFrameHeader() - { - int channels, sampleRate, bitRate; - return this.ReadFrameHeader(out channels, out sampleRate, out bitRate); - } - - private int ReadFrameHeader(out int channels, out int sampleRate, out int bitRate) - { - channels = 0; - sampleRate = 0; - bitRate = 0; - - int b; - while (true) - { - if ((b = _stream.ReadByte()) == -1) - { - return 0; - } - else if (b != 0xff) - { - continue; - } - - if ((b = _stream.ReadByte()) == -1) - { - return 0; - } - if ((b & 0xe0) != 0xe0) - { - continue; - } - - int version = (b & 0x18) >> 3; - if (version == 1) - { - continue; - } - switch (version) - { - case 0: - version = 2; - break; - case 2: - version = 1; - break; - case 3: - version = 0; - break; - } - int layer = (b & 0x6) >> 1; - if (layer == 0) - { - continue; - } - switch (layer) - { - case 1: - layer = 2; - break; - case 2: - layer = 1; - break; - case 3: - layer = 0; - break; - } - - if ((b = _stream.ReadByte()) == -1) - { - return 0; - } - bitRate = MpegBitRates[version > 0 ? 1 : 0, layer, (b >> 4)]; - if (bitRate == 0) - { - continue; - } - - sampleRate = MpegSampleRates[version, (b & 0xc) >> 2]; - if (sampleRate == 0) - { - continue; - } - int padding = (b & 0x2) > 0 ? 1 : 0; - - if ((b = _stream.ReadByte()) == -1) - { - return 0; - } - channels = ((b & 0xc0) >> 6) == 3 ? 1 : 2; - - _stream.Seek(-4, SeekOrigin.Current); - return 144 * bitRate * 1000 / sampleRate + padding; - } - } - } -} diff --git a/Floe.Audio/Properties/AssemblyInfo.cs b/Floe.Audio/Properties/AssemblyInfo.cs deleted file mode 100644 index ca08882..0000000 --- a/Floe.Audio/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Floe.Audio")] -[assembly: AssemblyDescription("Floe Voice Library")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Floe")] -[assembly: AssemblyCopyright("Copyright © 2011")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("d97923f3-80f7-4015-8266-b664b7daadff")] - -[assembly: AssemblyVersion("1.6.0.0")] -[assembly: AssemblyFileVersion("1.6.0.0")] -[assembly: CLSCompliant(true)] diff --git a/Floe.Audio/Voice/CodecInfo.cs b/Floe.Audio/Voice/CodecInfo.cs deleted file mode 100644 index e152c5b..0000000 --- a/Floe.Audio/Voice/CodecInfo.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Floe.Interop; - -namespace Floe.Audio -{ - /// - /// Specifies a codec to use for transmitting voice. Currently, only GSM 6.10 is supported. - /// - public enum VoiceCodec - { - /// - /// Use the GSM 6.10 codec. - /// - Gsm610 - } - - public class CodecInfo - { - private const int Gsm610PayloadType = 3; - private const int Gsm610SamplesPerBlock = 320; - private const int Gsm610BytesPerBlock = 65; - private const int MinBufferLength = 25; // milliseconds - - public int PayloadType { get; private set; } - public int EncodedBufferSize { get; private set; } - public int DecodedBufferSize { get; private set; } - public int SampleRate { get; private set; } - public int SamplesPerPacket { get; private set; } - public WaveFormat EncodedFormat { get; private set; } - public WaveFormat DecodedFormat { get; private set; } - - public CodecInfo(VoiceCodec codec, int sampleRate) - { - switch (codec) - { - case VoiceCodec.Gsm610: - this.PayloadType = Gsm610PayloadType; - this.SampleRate = sampleRate; - - int blocksPerPacket = 1; - while ((blocksPerPacket * Gsm610SamplesPerBlock * 1000) / sampleRate <= MinBufferLength) - { - blocksPerPacket++; - } - - this.SamplesPerPacket = Gsm610SamplesPerBlock * blocksPerPacket; - this.EncodedBufferSize = Gsm610BytesPerBlock * blocksPerPacket; - this.DecodedBufferSize = this.SamplesPerPacket * 2; - this.EncodedFormat = new WaveFormatGsm610(sampleRate); - this.DecodedFormat = new WaveFormatPcm(sampleRate, 16, 1); - break; - default: - throw new ArgumentException("Unsupported codec."); - } - } - - public AudioConverter GetEncoder() - { - return new AudioConverter(this.DecodedBufferSize, this.DecodedFormat, this.EncodedFormat); - } - - public AudioConverter GetDecoder() - { - return new AudioConverter(this.EncodedBufferSize, this.EncodedFormat, this.DecodedFormat); - } - } -} diff --git a/Floe.Audio/Voice/Delegates.cs b/Floe.Audio/Voice/Delegates.cs deleted file mode 100644 index 5caa017..0000000 --- a/Floe.Audio/Voice/Delegates.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Net; - -namespace Floe.Audio -{ - /// - /// Defines a method signature for a handler that determines whether audio should be encoded and transmitted. - /// - /// Returns true if transmission should occur, false otherwise. - public delegate bool TransmitPredicate(); - - /// - /// Defines a method signature for a handler that determines whether to process audio received from a given endpoint. - /// - /// The endpoint from which a packet was received. - /// Returns true if the packet should be processed, false otherwise. - public delegate bool ReceivePredicate(IPEndPoint endpoint); -} diff --git a/Floe.Audio/Voice/JitterBuffer.cs b/Floe.Audio/Voice/JitterBuffer.cs deleted file mode 100644 index 4bdab35..0000000 --- a/Floe.Audio/Voice/JitterBuffer.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.IO; -using System.Threading; - -using Floe.Interop; - -namespace Floe.Audio -{ - class JitterBuffer : Stream - { - private const int MaxBufferSize = 200; - private const int Delay = 2; // number of spans - - private AudioConverter _decoder; - private ConcurrentQueue _incoming; - private LinkedList _buffer; - private int _timestamp, _span, _lostCount, _delay; - private bool _reset; - - public JitterBuffer(CodecInfo codec) - { - _span = codec.SamplesPerPacket; - _decoder = codec.GetDecoder(); - _incoming = new ConcurrentQueue(); - _buffer = new LinkedList(); - - this.Reset(); - } - - public float Gain { get; set; } - - public void Enqueue(VoicePacket packet) - { - _incoming.Enqueue(packet); - } - - public VoicePacket Dequeue() - { - VoicePacket packet; - while (_incoming.TryDequeue(out packet)) - { - this.Insert(packet); - } - - return this.GetPacket(); - } - - private void Insert(VoicePacket packet) - { - if (!_reset) - { - var node = _buffer.First; - while (node != null) - { - if (packet.TimeStamp + _span <= _timestamp) - { - node.Value.Dispose(); - _buffer.RemoveFirst(); - } - node = node.Next; - } - } - - if (_lostCount > 20) - { - this.Reset(); - } - - if (_reset || packet.TimeStamp + _span >= _timestamp) - { - if (_buffer.Count == MaxBufferSize) - { - _buffer.First.Value.Dispose(); - _buffer.RemoveFirst(); - } - var node = _buffer.First; - while (node != null && node.Value.TimeStamp <= packet.TimeStamp) - { - node = node.Next; - } - if (node == null) - { - _buffer.AddLast(packet); - } - else - { - _buffer.AddBefore(node, packet); - } - } - } - - private VoicePacket GetPacket() - { - if (_reset) - { - var oldest = _buffer.First; - if (oldest == null) - { - return null; - } - else - { - _reset = false; - _timestamp = oldest.Value.TimeStamp; - } - } - - if (_buffer.Count > 0 && _delay > 0) - { - _delay--; - return null; - } - - var node = _buffer.First; - if (node != null && node.Value.TimeStamp > _timestamp + _span) - { - node = null; - } - - if (node != null) - { - _lostCount = 0; - var packet = node.Value; - _buffer.Remove(node); - _timestamp = node.Value.TimeStamp + _span; - return packet; - } - - _lostCount++; - _timestamp += _span; - return null; - } - - public void Reset() - { - while (_buffer.Count > 0) - { - var packet = _buffer.First.Value; - packet.Dispose(); - _buffer.RemoveFirst(); - } - _lostCount = 0; - _reset = true; - _delay = Delay; - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return false; } } - public override void Flush() { throw new NotImplementedException(); } - public override long Length { get { throw new NotImplementedException(); } } - public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - public override void SetLength(long value) { throw new NotImplementedException(); } - public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } - - public override int Read(byte[] buffer, int offset, int count) - { - Array.Clear(buffer, 0, count); - - var packet = this.Dequeue(); - if (packet != null) - { - count = _decoder.Convert(packet.Data, packet.Data.Length, buffer); - packet.Dispose(); - float gain = this.Gain != 0f ? (float)Math.Pow(10, this.Gain / 20f) : 1f; - WavProcess.ApplyGain(gain, buffer, count); - } - - return count; - } - } -} diff --git a/Floe.Audio/Voice/VoiceClient.cs b/Floe.Audio/Voice/VoiceClient.cs deleted file mode 100644 index e4c8817..0000000 --- a/Floe.Audio/Voice/VoiceClient.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; - -using Floe.Interop; -using Floe.Net; - -namespace Floe.Audio -{ - /// - /// Manages a voice session connecting to one or more peers. Recorded audio is encoded and sent to all peers, and received audio is played. - /// This class uses GSM 6.10 to compress the audio stream. - /// - public sealed class VoiceClient : RtpClient, IDisposable - { - private const long DummyIPAddress = 0x03030303; - private const int DummyPort = 3333; - - private VoiceIn _voiceIn; - private Dictionary _peers; - private float _outputVolume = 1f, _outputGain = 0f; - private VoicePacketPool _pool; - private ReceivePredicate _receivePredicate; - - /// - /// Construct a new voice session. - /// - /// The transmit codec. - /// The transmit quality (usually the sample rate). - /// An optional already-bound UDP client to use. If this is null, then a new client will be constructed. - /// An optional callback to determine whether to transmit each packet. An application may - /// use logic such as PTT (push-to-talk) or an automatic peak level-based approach. By default, all packets are transmitted. - public VoiceClient(CodecInfo codec, UdpClient client = null, - TransmitPredicate transmitPredicate = null, ReceivePredicate receivePredicate = null) - : base((byte)codec.PayloadType, codec.EncodedBufferSize, new IPEndPoint(new IPAddress(DummyIPAddress), DummyPort), client) - { - _peers = new Dictionary(); - _pool = new VoicePacketPool(); - _receivePredicate = receivePredicate; - _voiceIn = new VoiceIn(codec, this, transmitPredicate); - } - - /// - /// Gets or sets the volume at which voice chat renders. This is a value between 0 and 1. - /// - public float OutputVolume - { - get { return _outputVolume; } - set - { - if (_outputVolume != value) - { - _outputVolume = value; - foreach (var peer in _peers.Values) - { - peer.Volume = value; - } - } - } - } - - /// - /// Gets or sets the amount of gain (in decibels) to apply to the output. - /// - public float OutputGain - { - get { return _outputGain; } - set - { - if (_outputGain != value) - { - _outputGain = value; - foreach (var peer in _peers.Values) - { - peer.Gain = value; - } - } - } - } - - /// - /// Gets or sets the amount of gain (in decibels) to apply to the microphone input. - /// - public float InputGain { get { return _voiceIn.Gain; } set { _voiceIn.Gain = value; } } - - /// - /// Gets the current noise level from the microphone input. This could be used, for example, to activate transmission when the user talks. - /// - public float InputLevel { get { return _voiceIn.Level; } } - - public event EventHandler Error; - - /// - /// Open the voice session and begin sending/receiving data. - /// - public override void Open() - { - base.Open(); - _voiceIn.Start(); - } - - /// - /// Close the voice session. - /// - public override void Close() - { - base.Close(); - _voiceIn.Close(); - } - - /// - /// Add a peer to the session. - /// - /// The peer's audio codec. - /// The peer's audio quality (usually the sample rate). - /// The peer's public endpoint. - public void AddPeer(VoiceCodec codec, int quality, IPEndPoint endpoint) - { - base.AddPeer(endpoint); - var peer = new VoicePeer(codec, quality, _pool); - peer.Volume = _outputVolume; - peer.Gain = _outputGain; - _peers.Add(endpoint, peer); - } - - /// - /// Remove a peer from the session. - /// - /// The peer's public endpoint. - public new void RemovePeer(IPEndPoint endpoint) - { - if (base.RemovePeer(endpoint)) - { - var peer = _peers[endpoint]; - _peers.Remove(endpoint); - peer.Dispose(); - } - } - - protected override void OnReceived(IPEndPoint endpoint, short payloadType, int seqNumber, int timeStamp, byte[] payload, int count) - { - if (_receivePredicate == null || _receivePredicate(endpoint)) - { - _peers[endpoint].Enqueue(seqNumber, timeStamp, payload, count); - } - } - - protected override void OnError(Exception ex) - { - var handler = this.Error; - if (handler != null) - { - handler(this, new ErrorEventArgs(ex)); - } - } - - /// - /// Dispose the voice session. - /// - public override void Dispose() - { - base.Dispose(); - _voiceIn.Dispose(); - foreach (var peer in _peers.Values) - { - peer.Dispose(); - } - } - - ~VoiceClient() - { - this.Dispose(); - } - } -} diff --git a/Floe.Audio/Voice/VoiceIn.cs b/Floe.Audio/Voice/VoiceIn.cs deleted file mode 100644 index 5f4f6ab..0000000 --- a/Floe.Audio/Voice/VoiceIn.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.IO; - -using Floe.Interop; -using Floe.Net; - -namespace Floe.Audio -{ - class VoiceIn : Stream - { - private CodecInfo _codec; - private AudioConverter _encoder; - private RtpClient _client; - private TransmitPredicate _predicate; - private int _timeStamp; - private WaveIn _waveIn; - - public VoiceIn(CodecInfo codec, RtpClient client, TransmitPredicate predicate) - { - _codec = codec; - _client = client; - _predicate = predicate; - this.InitAudio(); - } - - public float Level { get; private set; } - - public float Gain { get; set; } - - public void Start() - { - _waveIn.Start(); - } - - public override void Close() - { - base.Close(); - _waveIn.Dispose(); - } - - private void InitAudio() - { - if (_waveIn != null) - { - _waveIn.Close(); - } - _waveIn = new WaveIn(this, _codec.DecodedFormat, _codec.DecodedBufferSize); - _encoder = new AudioConverter(_codec.DecodedBufferSize, _codec.DecodedFormat, _codec.EncodedFormat); - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return false; } } - public override void Flush() { throw new NotImplementedException(); } - public override long Length { get { throw new NotImplementedException(); } } - public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - public override void SetLength(long value) { throw new NotImplementedException(); } - public override int Read(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } - - public override void Write(byte[] buffer, int offset, int count) - { - float gain = this.Gain != 0f ? (float)Math.Pow(10, this.Gain / 20f) : 1f; - this.Level = WavProcess.ApplyGain(gain, buffer, count); - - if (_client != null) - { - count = _encoder.Convert(buffer, count, buffer); - if (count >= _client.PayloadSize && (_predicate == null || _predicate())) - { - _client.Send(_timeStamp, buffer); - } - } - _timeStamp += _codec.SamplesPerPacket; - } - } -} diff --git a/Floe.Audio/Voice/VoiceLoopback.cs b/Floe.Audio/Voice/VoiceLoopback.cs deleted file mode 100644 index 256301c..0000000 --- a/Floe.Audio/Voice/VoiceLoopback.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; - -using Floe.Interop; - -namespace Floe.Audio -{ - /// - /// Allows users to test their microphone by hearing themselves speak. This class encodes the audio - /// using the selected codec and quality and immediate decodes and plays it back. - /// - public class VoiceLoopback : FifoStream, IDisposable - { - private WaveIn _waveIn; - private WaveOut _waveOut; - private AudioConverter _encoder; - - /// - /// Construct a new voice loopback session. - /// - /// An audio codec to encode and decode with. - /// The encoding quality (usually the sample rate). - public VoiceLoopback(VoiceCodec codec, int quality) - { - var info = new CodecInfo(codec, quality); - _waveIn = new WaveIn(this, info.DecodedFormat, info.DecodedBufferSize); - _waveOut = new WaveOut(this, info.EncodedFormat, info.EncodedBufferSize); - _encoder = new AudioConverter(info.DecodedBufferSize, info.DecodedFormat, info.EncodedFormat); - } - - /// - /// Gets or sets the render volume. - /// - public float RenderVolume { get { return _waveOut.Volume; } set { _waveOut.Volume = value; } } - - /// - /// Gets or sets the microphone input gain. - /// - public float InputGain { get; set; } - - /// - /// Gets or sets the output gain. - /// - public float OutputGain { get; set; } - - /// - /// Starts the loopback session. - /// - public void Start() - { - _waveIn.Start(); - _waveOut.Start(); - } - - /// - /// Stops the loopback session. - /// - public override void Close() - { - base.Close(); - _waveIn.Dispose(); - _waveOut.Dispose(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - return base.Read(buffer, offset, count); - } - - public override void Write(byte[] buffer, int offset, int count) - { - float gain = this.InputGain != 0f ? (float)Math.Pow(10, this.InputGain / 20f) : 1f; - WavProcess.ApplyGain(gain, buffer, count); - - if (offset != 0) - { - throw new ArgumentException("Offsets are not supported."); - } - count = _encoder.Convert(buffer, count, buffer); - base.Write(buffer, offset, count); - } - } -} diff --git a/Floe.Audio/Voice/VoicePacket.cs b/Floe.Audio/Voice/VoicePacket.cs deleted file mode 100644 index b460ca2..0000000 --- a/Floe.Audio/Voice/VoicePacket.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; - -namespace Floe.Audio -{ - class VoicePacket : IDisposable - { - private VoicePacketPool _pool; - - public int SequenceNumber { get; private set; } - public int TimeStamp { get; set; } - public byte[] Data { get; private set; } - - internal VoicePacket(VoicePacketPool pool) - { - _pool = pool; - } - - internal void Init(int seqNumber, int timeStamp, byte[] payload, int count) - { - this.SequenceNumber = seqNumber; - this.TimeStamp = timeStamp; - if (this.Data == null || this.Data.Length != count) - { - this.Data = new byte[count]; - } - Array.Copy(payload, this.Data, count); - } - - public void Dispose() - { - _pool.Recycle(this); - } - } -} diff --git a/Floe.Audio/Voice/VoicePacketPool.cs b/Floe.Audio/Voice/VoicePacketPool.cs deleted file mode 100644 index a136d30..0000000 --- a/Floe.Audio/Voice/VoicePacketPool.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Collections.Concurrent; - -namespace Floe.Audio -{ - class VoicePacketPool - { - private ConcurrentStack _pool = new ConcurrentStack(); - - public VoicePacketPool() - { - _pool = new ConcurrentStack(); - } - - public VoicePacket Create(int seqNumber, int timeStamp, byte[] payload, int count) - { - VoicePacket packet; - if (!_pool.TryPop(out packet)) - { - packet = new VoicePacket(this); - } - packet.Init(seqNumber, timeStamp, payload, count); - return packet; - } - - public void Recycle(VoicePacket packet) - { - _pool.Push(packet); - } - } -} diff --git a/Floe.Audio/Voice/VoicePeer.cs b/Floe.Audio/Voice/VoicePeer.cs deleted file mode 100644 index aa1f4e6..0000000 --- a/Floe.Audio/Voice/VoicePeer.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; - -using Floe.Interop; - -namespace Floe.Audio -{ - class VoicePeer : IDisposable - { - private WaveOut _waveOut; - private JitterBuffer _buffer; - private CodecInfo _codec; - private VoicePacketPool _pool; - - public VoicePeer(VoiceCodec codec, int quality, VoicePacketPool pool) - { - _codec = new CodecInfo(codec, quality); - _buffer = new JitterBuffer(_codec); - _pool = pool; - this.InitAudio(); - } - - public float Volume { get { return _waveOut.Volume; } set { _waveOut.Volume = value; } } - public float Gain { get { return _buffer.Gain; } set { _buffer.Gain = value; } } - - public void Enqueue(int seqNumber, int timeStamp, byte[] payload, int count) - { - _buffer.Enqueue(_pool.Create(seqNumber, timeStamp, payload, count)); - } - - private void InitAudio() - { - _waveOut = new WaveOut(_buffer, _codec.DecodedFormat, _codec.DecodedBufferSize); - _waveOut.Start(); - } - - public void Dispose() - { - _waveOut.Dispose(); - } - } -} diff --git a/Floe.Audio/WavFileStream.cs b/Floe.Audio/WavFileStream.cs deleted file mode 100644 index aad9f8e..0000000 --- a/Floe.Audio/WavFileStream.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.IO; - -using Floe.Interop; - -namespace Floe.Audio -{ - public class WavFileStream : Stream - { - private Stream _stream; - private WaveFormat _format; - - public WavFileStream(string fileName) - : this(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - } - - public WavFileStream(Stream stream) - { - _stream = stream; - var bytes = new byte[20]; - if (_stream.Read(bytes, 0, bytes.Length) < bytes.Length || - BitConverter.ToInt32(bytes, 4) == 0 || - BitConverter.ToInt32(bytes, 8) != 0x45564157 || // "WAVE" - BitConverter.ToInt32(bytes, 12) != 0x20746d66) // "fmt " - { - throw new FileFormatException("Badly formed RIFF file."); - } - var fmtBytes = new byte[BitConverter.ToInt32(bytes, 16)]; - _stream.Read(fmtBytes, 0, fmtBytes.Length); - _format = new WaveFormat(fmtBytes); - - while (_stream.Read(bytes, 0, 8) == 8) - { - var dataType = BitConverter.ToInt32(bytes, 0); - var dataSize = BitConverter.ToInt32(bytes, 4); - if (dataType == 0x61746164) - { - return; - } - _stream.Seek(dataSize, SeekOrigin.Current); - } - throw new FileFormatException("Could not find wave data."); - } - - public WaveFormat Format { get { return _format; } } - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return false; } } - public override void Flush() { throw new NotImplementedException(); } - public override long Length { get { throw new NotImplementedException(); } } - public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - public override void SetLength(long value) { throw new NotImplementedException(); } - public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } - - public override int Read(byte[] buffer, int offset, int count) - { - return _stream.Read(buffer, offset, count); - } - - public override void Close() - { - _stream.Close(); - } - } -} diff --git a/Floe.Audio/WavProcess.cs b/Floe.Audio/WavProcess.cs deleted file mode 100644 index 1e6d00a..0000000 --- a/Floe.Audio/WavProcess.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Floe.Audio -{ - public static class WavProcess - { - public static float ApplyGain(float gain, byte[] buffer, int count) - { - float sum = 0f; - double min = (double)short.MinValue; - double max = (double)short.MaxValue; - for (int i = 0; i < count; i += 2) - { - short sample = BitConverter.ToInt16(buffer, i); - if (gain != 1f) - { - double adj = Math.Max(min, Math.Min(max, (double)sample * gain)); - sample = (short)adj; - buffer[i] = (byte)sample; - buffer[i + 1] = (byte)(sample >> 8); - } - sum += (float)Math.Pow(2, (double)sample / (double)short.MaxValue); - } - return (float)Math.Sqrt(sum); - } - } -} diff --git a/Floe.Audio/WaveInMeter.cs b/Floe.Audio/WaveInMeter.cs deleted file mode 100644 index 0028697..0000000 --- a/Floe.Audio/WaveInMeter.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; - -using Floe.Interop; - -namespace Floe.Audio -{ - public class WaveLevelEventArgs : EventArgs - { - public float Level { get; internal set; } - } - - public class WaveInMeter : IDisposable - { - private class MeterStream : Stream - { - private WaveInMeter _meter; - - public MeterStream(WaveInMeter meter) - { - _meter = meter; - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override bool CanWrite { get { return true; } } - public override void Flush() { throw new NotImplementedException(); } - public override long Length { get { throw new NotImplementedException(); } } - public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } } - public override long Seek(long offset, SeekOrigin origin) { throw new NotImplementedException(); } - public override void SetLength(long value) { throw new NotImplementedException(); } - public override int Read(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } - - public override void Write(byte[] buffer, int offset, int count) - { - float sum = 0f; - for (int i = 0; i < count; i += 2) - { - float sample = (float)((short)(buffer[i + 1] << 8) | (short)(buffer[i])) / (float)short.MaxValue; - sum += sample * sample; - } - sum = (float)Math.Sqrt(sum); - _meter.OnLevelUpdated(sum); - return; - } - } - - private WaveIn _waveIn; - private WaveLevelEventArgs _args; - - public WaveInMeter(int samples) - { - _args = new WaveLevelEventArgs(); - var format = new WaveFormatPcm(44100, 16, 1); - _waveIn = new WaveIn(new MeterStream(this), format, format.FrameSize * samples); - _waveIn.Start(); - } - - public event EventHandler LevelUpdated; - - public void Dispose() - { - _waveIn.Dispose(); - } - - internal void OnLevelUpdated(float level) - { - var handler = this.LevelUpdated; - if (handler != null) - { - _args.Level = level; - handler(this, _args); - } - } - } -} diff --git a/Floe.Configuration/ColorsElement.cs b/Floe.Configuration/ColorsElement.cs index 4cabc10..2397c5c 100644 --- a/Floe.Configuration/ColorsElement.cs +++ b/Floe.Configuration/ColorsElement.cs @@ -8,42 +8,42 @@ namespace Floe.Configuration { public class ColorsElement : ConfigurationElement, INotifyPropertyChanged { - [ConfigurationProperty("background", DefaultValue = "Black")] + [ConfigurationProperty("background", DefaultValue = "#FFC0C0C0")] public string Background { get { return (string)this["background"]; } set { this["background"] = value; OnPropertyChanged("Background"); } } - [ConfigurationProperty("editBackground", DefaultValue = "Black")] + [ConfigurationProperty("editBackground", DefaultValue = "#FFC0C0C0")] public string EditBackground { get { return (string)this["editBackground"]; } set { this["editBackground"] = value; OnPropertyChanged("EditBackground"); } } - [ConfigurationProperty("edit", DefaultValue = "White")] + [ConfigurationProperty("edit", DefaultValue = "Black")] public string Edit { get { return (string)this["edit"]; } set { this["edit"] = value; OnPropertyChanged("Edit"); } } - [ConfigurationProperty("default", DefaultValue = "White")] + [ConfigurationProperty("default", DefaultValue = "#FF000000")] public string Default { get { return (string)this["default"]; } set { this["default"] = value; OnPropertyChanged("Default"); } } - [ConfigurationProperty("action", DefaultValue = "White")] + [ConfigurationProperty("action", DefaultValue = "#FFFF00FF")] public string Action { get { return (string)this["action"]; } set { this["action"] = value; OnPropertyChanged("Action"); } } - [ConfigurationProperty("ctcp", DefaultValue = "Yellow")] + [ConfigurationProperty("ctcp", DefaultValue = "#FF00FF00")] public string Ctcp { get { return (string)this["ctcp"]; } @@ -57,70 +57,70 @@ public string Info set { this["info"] = value; OnPropertyChanged("Info"); } } - [ConfigurationProperty("invite", DefaultValue = "Yellow")] + [ConfigurationProperty("invite", DefaultValue = "#FF00FF00")] public string Invite { get { return (string)this["invite"]; } set { this["invite"] = value; OnPropertyChanged("Invite"); } } - [ConfigurationProperty("join", DefaultValue = "Lavender")] + [ConfigurationProperty("join", DefaultValue = "#FF008000")] public string Join { get { return (string)this["join"]; } set { this["join"] = value; OnPropertyChanged("Join"); } } - [ConfigurationProperty("kick", DefaultValue = "Lavender")] + [ConfigurationProperty("kick", DefaultValue = "#FF008000")] public string Kick { get { return (string)this["kick"]; } set { this["kick"] = value; OnPropertyChanged("Kick"); } } - [ConfigurationProperty("mode", DefaultValue = "Yellow")] + [ConfigurationProperty("mode", DefaultValue = "#FF008000")] public string Mode { get { return (string)this["mode"]; } set { this["mode"] = value; OnPropertyChanged("Mode"); } } - [ConfigurationProperty("nick", DefaultValue = "Yellow")] + [ConfigurationProperty("nick", DefaultValue = "#FF008000")] public string Nick { get { return (string)this["nick"]; } set { this["nick"] = value; OnPropertyChanged("Nick"); } } - [ConfigurationProperty("notice", DefaultValue = "Yellow")] + [ConfigurationProperty("notice", DefaultValue = "#FF800000")] public string Notice { get { return (string)this["notice"]; } set { this["notice"] = value; OnPropertyChanged("Notice"); } } - [ConfigurationProperty("own", DefaultValue = "Gray")] + [ConfigurationProperty("own", DefaultValue = "#FF000000")] public string Own { get { return (string)this["own"]; } set { this["own"] = value; OnPropertyChanged("Own"); } } - [ConfigurationProperty("part", DefaultValue = "Lavender")] + [ConfigurationProperty("part", DefaultValue = "#FF008000")] public string Part { get { return (string)this["part"]; } set { this["part"] = value; OnPropertyChanged("Part"); } } - [ConfigurationProperty("quit", DefaultValue = "Lavender")] + [ConfigurationProperty("quit", DefaultValue = "#FF0000A0")] public string Quit { get { return (string)this["quit"]; } set { this["quit"] = value; OnPropertyChanged("Quit"); } } - [ConfigurationProperty("topic", DefaultValue = "Yellow")] + [ConfigurationProperty("topic", DefaultValue = "#FF008000")] public string Topic { get { return (string)this["topic"]; } @@ -148,7 +148,7 @@ public string OldMarker set { this["oldMarker"] = value; OnPropertyChanged("OldMarker"); } } - [ConfigurationProperty("attention", DefaultValue = "#404000")] + [ConfigurationProperty("attention", DefaultValue = "#FF00FF00")] public string Attention { get { return (string)this["attention"]; } @@ -176,21 +176,21 @@ public string Alert set { this["alertActivity"] = value; OnPropertyChanged("Alert"); } } - [ConfigurationProperty("windowBackground", DefaultValue = "#293955")] + [ConfigurationProperty("windowBackground", DefaultValue = "#FF293955")] public string WindowBackground { get { return (string)this["windowBackground"]; } set { this["windowBackground"] = value; OnPropertyChanged("WindowBackground"); } } - [ConfigurationProperty("windowForeground", DefaultValue = "White")] + [ConfigurationProperty("windowForeground", DefaultValue = "#FFFFFFFF")] public string WindowForeground { get { return (string)this["windowForeground"]; } set { this["windowForeground"] = value; OnPropertyChanged("WindowForeground"); } } - [ConfigurationProperty("highlight", DefaultValue = "#3399FF")] + [ConfigurationProperty("highlight", DefaultValue = "#FF00FFFF")] public string Highlight { get { return (string)this["highlight"]; } diff --git a/Floe.Configuration/Enums.cs b/Floe.Configuration/Enums.cs index 238ff61..62cb18e 100644 --- a/Floe.Configuration/Enums.cs +++ b/Floe.Configuration/Enums.cs @@ -5,6 +5,8 @@ namespace Floe.Configuration public enum TabStripPosition { Top, - Bottom + Bottom, + Left, + Right } } diff --git a/Floe.Configuration/Floe.Configuration.csproj b/Floe.Configuration/Floe.Configuration.csproj index a94e9fa..7124048 100644 --- a/Floe.Configuration/Floe.Configuration.csproj +++ b/Floe.Configuration/Floe.Configuration.csproj @@ -1,110 +1,8 @@ - - + + - Debug - AnyCPU - 8.0.30703 - 2.0 - {75037294-D6D4-42B0-AF4B-FE2F438D0670} - Library - Properties - Floe.Configuration - Floe.Configuration - v4.0 - 512 - Client + netcoreapp3.1 + true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - - - ..\Floe.snk - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + diff --git a/Floe.Configuration/FormattingElement.cs b/Floe.Configuration/FormattingElement.cs index 5d68a98..7f2b48e 100644 --- a/Floe.Configuration/FormattingElement.cs +++ b/Floe.Configuration/FormattingElement.cs @@ -65,14 +65,14 @@ public string TimestampFormat } } - [ConfigurationProperty("useTabularView", DefaultValue=true)] + [ConfigurationProperty("useTabularView", DefaultValue=false)] public bool UseTabularView { get { return (bool)this["useTabularView"]; } set { this["useTabularView"] = value; this.OnPropertyChanged("UseTabularView"); } } - [ConfigurationProperty("colorizeNicknames", DefaultValue = true)] + [ConfigurationProperty("colorizeNicknames", DefaultValue = false)] public bool ColorizeNicknames { get { return (bool)this["colorizeNicknames"]; } @@ -86,26 +86,26 @@ public int NicknameColorSeed set { this["nicknameColorSeed"] = value; this.OnPropertyChanged("NicknameColorSeed"); } } - [ConfigurationProperty("attentionOnOwnNickname", DefaultValue = false)] + [ConfigurationProperty("attentionOnOwnNickname", DefaultValue = true)] public bool AttentionOnOwnNickname { get { return (bool)this["attentionOnOwnNickname"]; } set { this["attentionOnOwnNickname"] = value; this.OnPropertyChanged("AttentionOnOwnNickname"); } } - [ConfigurationProperty("overlayIconOnChatActivity", DefaultValue = false)] - public bool OverlayIconOnChatActivity - { - get { return (bool)this["overlayIconOnChatActivity"]; } - set { this["overlayIconOnChatActivity"] = value; this.OnPropertyChanged("OverlayIconOnChatActivity"); } - } - - [ConfigurationProperty("overlayIconChangeColor", DefaultValue = false)] - public bool OverlayIconChangeColor - { - get { return (bool)this["overlayIconChangeColor"]; } - set { this["overlayIconChangeColor"] = value; this.OnPropertyChanged("OverlayIconChangeColor"); } - } + [ConfigurationProperty("overlayIconOnChatActivity", DefaultValue = false)] + public bool OverlayIconOnChatActivity + { + get { return (bool)this["overlayIconOnChatActivity"]; } + set { this["overlayIconOnChatActivity"] = value; this.OnPropertyChanged("OverlayIconOnChatActivity"); } + } + + [ConfigurationProperty("overlayIconChangeColor", DefaultValue = false)] + public bool OverlayIconChangeColor + { + get { return (bool)this["overlayIconChangeColor"]; } + set { this["overlayIconChangeColor"] = value; this.OnPropertyChanged("OverlayIconChangeColor"); } + } [ConfigurationProperty("attentionPatterns", DefaultValue = "")] public string AttentionPatterns diff --git a/Floe.Configuration/PersistentSettings.cs b/Floe.Configuration/PersistentSettings.cs index c8b7284..c2528b5 100644 --- a/Floe.Configuration/PersistentSettings.cs +++ b/Floe.Configuration/PersistentSettings.cs @@ -43,9 +43,9 @@ public void Save() public void Load() { var map = new ExeConfigurationFileMap(); - map.ExeConfigFilename = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; + map.ExeConfigFilename = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), _appName); -#if DEBUG1 +#if DEBUG path = Path.Combine(path, string.Format("{0}.DEBUG.config", _appName)); #else path = Path.Combine(path, string.Format("{0}.config", _appName)); diff --git a/Floe.Configuration/Properties/AssemblyInfo.cs b/Floe.Configuration/Properties/AssemblyInfo.cs deleted file mode 100644 index 3965cc9..0000000 --- a/Floe.Configuration/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Floe.Configuration.dll")] -[assembly: AssemblyDescription("Floe Configuration Assembly")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Floe")] -[assembly: AssemblyCopyright("Copyright © 2010")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("bde98a47-96e2-47bf-9561-a398e7b7474a")] - -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Floe.Configuration/ServerElement.cs b/Floe.Configuration/ServerElement.cs index 0cfb425..f1cf678 100644 --- a/Floe.Configuration/ServerElement.cs +++ b/Floe.Configuration/ServerElement.cs @@ -136,6 +136,62 @@ public bool AutoReconnect set { this["autoReconnect"] = value; } } + [ConfigurationProperty("useGlobalProxySettings", DefaultValue = true)] + public bool UseGlobalProxySettings + { + get { return (bool)this["useGlobalProxySettings"]; } + set { this["useGlobalProxySettings"] = value; } + } + + [ConfigurationProperty("useProxySettings", DefaultValue = false)] + public bool UseProxySettings + { + get { return (bool)this["useProxySettings"]; } + set { this["useProxySettings"] = value; } + } + + [ConfigurationProperty("proxyHostname", DefaultValue = "127.0.0.1")] + public string ProxyHostname + { + get + { + if (((string)this["proxyHostname"]).Trim().Length < 1) + { + this["proxyHostname"] = "127.0.0.1"; + } + return (string)this["proxyHostname"]; + } + set { this["proxyHostname"] = value; } + } + + [ConfigurationProperty("proxyPort", DefaultValue = 1080)] + public int ProxyPort + { + get { return (int)this["proxyPort"]; } + set + { + if (value <= 0 || value > ushort.MaxValue) + { + throw new ArgumentException("The port must be within the range of 1 - 65535."); + } + this["proxyPort"] = value; + } + } + + [ConfigurationProperty("proxyUsername", DefaultValue = "")] + public string ProxyUsername + { + get { return (string)this["proxyUsername"]; } + set { this["proxyUsername"] = value; } + } + + [ConfigurationProperty("proxyPassword", DefaultValue = "")] + public string ProxyPassword + { + get { return (string)this["proxyPassword"]; } + set { this["proxyPassword"] = value; } + } + [ConfigurationProperty("onConnect", DefaultValue="")] public string OnConnect { diff --git a/Floe.Configuration/WindowsElement.cs b/Floe.Configuration/WindowsElement.cs index eed9d67..eeb211a 100644 --- a/Floe.Configuration/WindowsElement.cs +++ b/Floe.Configuration/WindowsElement.cs @@ -6,6 +6,8 @@ namespace Floe.Configuration { public class WindowsElement : ConfigurationElement, INotifyPropertyChanged { + public static EventHandler OrientationChanged; + [ConfigurationProperty("placement")] public string Placement { @@ -41,7 +43,7 @@ public double ChromeOpacity set { this["chromeOpacity"] = value; this.OnPropertyChanged("ChromeOpacity"); } } - [ConfigurationProperty("backgroundOpacity", DefaultValue = 0.92)] + [ConfigurationProperty("backgroundOpacity", DefaultValue = 1.0)] public double BackgroundOpacity { get { return (double)this["backgroundOpacity"]; } @@ -55,11 +57,14 @@ public bool MinimizeToSysTray set { this["minimizeToSysTray"] = value; this.OnPropertyChanged("MinimizeToSysTray"); } } - [ConfigurationProperty("tabStripPosition", DefaultValue=TabStripPosition.Bottom)] + [ConfigurationProperty("tabStripPosition", DefaultValue=TabStripPosition.Right)] public TabStripPosition TabStripPosition { get { return (TabStripPosition)this["tabStripPosition"]; } - set { this["tabStripPosition"] = value; this.OnPropertyChanged("TabStripPosition"); } + set { this["tabStripPosition"] = value; this.OnPropertyChanged("TabStripPosition"); + if (OrientationChanged != null) + OrientationChanged(this, new EventArgs()); + } } [ConfigurationProperty("minTabWidth", DefaultValue = 75.0)] diff --git a/Floe.Interop/AssemblyInfo.cpp b/Floe.Interop/AssemblyInfo.cpp deleted file mode 100644 index d5fc8b1..0000000 --- a/Floe.Interop/AssemblyInfo.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "stdafx.h" - -using namespace System; -using namespace System::Reflection; -using namespace System::Runtime::CompilerServices; -using namespace System::Runtime::InteropServices; -using namespace System::Security::Permissions; - -[assembly:AssemblyTitleAttribute("Floe.Interop")]; -[assembly:AssemblyDescriptionAttribute("Floe Interop Library")]; -[assembly:AssemblyConfigurationAttribute("")]; -[assembly:AssemblyCompanyAttribute("")]; -[assembly:AssemblyProductAttribute("Floe")]; -[assembly:AssemblyCopyrightAttribute("Copyright (c) 2011")]; -[assembly:AssemblyTrademarkAttribute("")]; -[assembly:AssemblyCultureAttribute("")]; - -[assembly:AssemblyVersionAttribute("1.6.0.0")]; - -[assembly:ComVisible(false)]; - -[assembly:CLSCompliantAttribute(true)]; - -[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)]; \ No newline at end of file diff --git a/Floe.Interop/AudioConverter.cpp b/Floe.Interop/AudioConverter.cpp deleted file mode 100644 index b95dd34..0000000 --- a/Floe.Interop/AudioConverter.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include "Stdafx.h" -#include "AudioConverter.h" - -namespace Floe -{ - namespace Interop - { - AudioConverter::AudioConverter(int maxSrcSize, WaveFormat ^srcFormat, ...array ^dstFormats) - { - m_count = dstFormats->Length; - if(m_count < 1) - { - throw gcnew System::ArgumentException("At least one destination format must be specified."); - } - - m_streams = new HACMSTREAM[m_count]; - m_headers = new LPACMSTREAMHEADER[m_count]; - - int srcSize, dstSize; - for(int i = 0; i < m_count; i++) - { - ThrowOnFailure(acmStreamOpen(&m_streams[i], 0, i == 0 ? srcFormat->Data : dstFormats[i-1]->Data, dstFormats[i]->Data, 0, 0, 0, 0)); - m_headers[i] = new ACMSTREAMHEADER(); - m_headers[i]->cbStruct = sizeof(ACMSTREAMHEADER); - m_headers[i]->cbSrcLength = m_headers[i]->dwSrcUser = srcSize = i == 0 ? maxSrcSize * 2 : m_headers[i-1]->cbDstLength; - m_headers[i]->pbSrc = (LPBYTE)malloc(srcSize); - ThrowOnFailure(acmStreamSize(m_streams[i], srcSize, (LPDWORD)&dstSize, ACM_STREAMSIZEF_SOURCE)); - m_headers[i]->cbDstLength = m_headers[i]->dwDstUser = dstSize; - m_headers[i]->pbDst = (LPBYTE)malloc(dstSize); - m_headers[i]->fdwStatus = 0; - m_headers[i]->cbSrcLengthUsed = m_headers[i]->cbDstLengthUsed = 0; - ThrowOnFailure(acmStreamPrepareHeader(m_streams[i], m_headers[i], 0)); - m_headers[i]->cbSrcLengthUsed = m_headers[i]->cbSrcLength; - } - } - - int AudioConverter::Convert(IntPtr srcBuffer, int size, [Out] IntPtr &dstBuffer) - { - for(int i = 0; i < m_count; i++) - { - int remainder = m_headers[i]->cbSrcLength - m_headers[i]->cbSrcLengthUsed; - if(remainder > 0) - { - memmove(m_headers[i]->pbSrc, m_headers[i]->pbSrc + m_headers[i]->cbSrcLengthUsed, remainder); - } - m_headers[i]->cbSrcLength = i == 0 ? size : m_headers[i-1]->cbDstLengthUsed; - memcpy(m_headers[i]->pbSrc + remainder, i == 0 ? (void*)srcBuffer : m_headers[i-1]->pbDst, m_headers[i]->cbSrcLength); - m_headers[i]->cbSrcLength += remainder; - ThrowOnFailure(acmStreamConvert(m_streams[i], m_headers[i], ACM_STREAMCONVERTF_BLOCKALIGN)); - } - dstBuffer = (IntPtr)m_headers[m_count-1]->pbDst; - return m_headers[m_count-1]->cbDstLengthUsed; - } - - int AudioConverter::Convert(array^ srcBuffer, int size, array^ dstBuffer) - { - pin_ptr pSrc = &srcBuffer[0]; - IntPtr pDst; - size = this->Convert((IntPtr)pSrc, size, pDst); - if(dstBuffer->Length < size) - { - throw gcnew InteropException("Destination buffer too small."); - } - Marshal::Copy(pDst, dstBuffer, 0, size); - return size; - } - - AudioConverter::~AudioConverter() - { - if(m_headers != 0 && m_streams != 0) - { - for(int i = 0; i < m_count; i++) - { - m_headers[i]->cbSrcLength = m_headers[i]->dwSrcUser; - m_headers[i]->cbDstLength = m_headers[i]->dwDstUser; - acmStreamUnprepareHeader(m_streams[i], m_headers[i], 0); - acmStreamClose(m_streams[i], 0); - delete m_headers[i]->pbSrc; - delete m_headers[i]->pbDst; - delete m_headers[i]; - } - delete m_headers; - delete m_streams; - m_headers = 0; - m_streams = 0; - } - } - - AudioConverter::!AudioConverter() - { - this->~AudioConverter(); - } - } -} diff --git a/Floe.Interop/AudioConverter.h b/Floe.Interop/AudioConverter.h deleted file mode 100644 index 53becf2..0000000 --- a/Floe.Interop/AudioConverter.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "Stdafx.h" -#include "Common.h" - -namespace Floe -{ - namespace Interop - { - using System::IntPtr; - using System::Byte; - using namespace System::Collections::Generic; - using namespace System::Runtime::InteropServices; - - public ref class AudioConverter - { - private: - HACMSTREAM *m_streams; - LPACMSTREAMHEADER *m_headers; - int m_count; - - public: - AudioConverter(int maxSrcSize, WaveFormat ^srcFormat, ...array ^dstFormats); - int Convert(IntPtr srcBuffer, int size, [Out] IntPtr &dstBuffer); - int Convert(array^ srcBuffer, int size, array^ dstBuffer); - - property int SourceBufferSize - { - int get() - { - return m_headers[0]->dwSrcUser; - } - } - - property int DestBufferSize - { - int get() - { - return m_headers[m_count - 1]->dwDstUser; - } - } - - private: - ~AudioConverter(); - !AudioConverter(); - }; - } -} \ No newline at end of file diff --git a/Floe.Interop/Common.h b/Floe.Interop/Common.h deleted file mode 100644 index 15d38ea..0000000 --- a/Floe.Interop/Common.h +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once -#include "Stdafx.h" -#include "WaveFormat.h" - -using System::String; -using System::Exception; - -namespace Floe -{ - namespace Interop - { - public ref class InteropException : Exception - { - public: - InteropException(String^ message) - : Exception(message) - { - } - }; - - public ref class InteropErrorEventArgs : System::EventArgs - { - private: - Exception ^m_exception; - - internal: - InteropErrorEventArgs(Exception ^exception) : m_exception(exception) - { - } - - public: - property Exception ^Exception - { - System::Exception ^get() - { - return m_exception; - } - } - }; - - inline void ThrowOnFailure(HRESULT hr) - { - switch(hr) - { - case MMSYSERR_ALLOCATED: - throw gcnew InteropException("The multimedia device is already in use."); - } - - if(hr != 0) - { - throw gcnew InteropException(System::String::Format("System error: {0}", hr.ToString("X"))); - } - } - - inline void ThrowOnZero(HANDLE handle) - { - if(handle == 0) - { - throw gcnew InteropException("A null handle was returned."); - } - } - } -} \ No newline at end of file diff --git a/Floe.Interop/Floe.Interop.vcxproj b/Floe.Interop/Floe.Interop.vcxproj deleted file mode 100644 index fa9d01d..0000000 --- a/Floe.Interop/Floe.Interop.vcxproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {3CEFFCEB-C836-47CC-8B8A-EC5655E1B5B7} - v4.0 - ManagedCProj - FloeAudio - - - - DynamicLibrary - true - true - Unicode - - - DynamicLibrary - false - true - Unicode - - - - - - - - - - - - - true - - - false - - - true - - - ..\Floe.snk - - - - - false - false - false - ..\Floe.snk - ..\Floe.snk - - - - Level3 - Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) - Use - - - true - Ole32.lib;Msacm32.lib;winmm.lib;%(AdditionalDependencies) - ..\Floe.snk - - - - - - - - - - - - - Level3 - WIN32;NDEBUG;%(PreprocessorDefinitions) - Use - MultiThreadedDLL - - - true - Ole32.lib;Msacm32.lib;winmm.lib;%(AdditionalDependencies) - ..\Floe.snk - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - - - - - - - - - - \ No newline at end of file diff --git a/Floe.Interop/InputButton.h b/Floe.Interop/InputButton.h deleted file mode 100644 index 094e237..0000000 --- a/Floe.Interop/InputButton.h +++ /dev/null @@ -1,210 +0,0 @@ -#pragma once - -namespace Floe -{ - namespace Interop - { - public enum class InputButton - { - A = 0x41, - Add = 0x6b, - Alt = 0x40000, - Apps = 0x5d, - Attn = 0xf6, - B = 0x42, - Back = 8, - BrowserBack = 0xa6, - BrowserFavorites = 0xab, - BrowserForward = 0xa7, - BrowserHome = 0xac, - BrowserRefresh = 0xa8, - BrowserSearch = 170, - BrowserStop = 0xa9, - C = 0x43, - Cancel = 3, - Capital = 20, - CapsLock = 20, - Clear = 12, - Control = 0x20000, - ControlKey = 0x11, - Crsel = 0xf7, - D = 0x44, - D0 = 0x30, - D1 = 0x31, - D2 = 50, - D3 = 0x33, - D4 = 0x34, - D5 = 0x35, - D6 = 0x36, - D7 = 0x37, - D8 = 0x38, - D9 = 0x39, - Decimal = 110, - Delete = 0x2e, - Divide = 0x6f, - Down = 40, - E = 0x45, - End = 0x23, - Enter = 13, - EraseEof = 0xf9, - Escape = 0x1b, - Execute = 0x2b, - Exsel = 0xf8, - F = 70, - F1 = 0x70, - F10 = 0x79, - F11 = 0x7a, - F12 = 0x7b, - F13 = 0x7c, - F14 = 0x7d, - F15 = 0x7e, - F16 = 0x7f, - F17 = 0x80, - F18 = 0x81, - F19 = 130, - F2 = 0x71, - F20 = 0x83, - F21 = 0x84, - F22 = 0x85, - F23 = 0x86, - F24 = 0x87, - F3 = 0x72, - F4 = 0x73, - F5 = 0x74, - F6 = 0x75, - F7 = 0x76, - F8 = 0x77, - F9 = 120, - FinalMode = 0x18, - G = 0x47, - H = 0x48, - HanguelMode = 0x15, - HangulMode = 0x15, - HanjaMode = 0x19, - Help = 0x2f, - Home = 0x24, - I = 0x49, - IMEAccept = 30, - IMEAceept = 30, - IMEConvert = 0x1c, - IMEModeChange = 0x1f, - IMENonconvert = 0x1d, - Insert = 0x2d, - J = 0x4a, - JunjaMode = 0x17, - K = 0x4b, - KanaMode = 0x15, - KanjiMode = 0x19, - KeyCode = 0xffff, - L = 0x4c, - LaunchApplication1 = 0xb6, - LaunchApplication2 = 0xb7, - LaunchMail = 180, - LButton = 1, - LControlKey = 0xa2, - Left = 0x25, - LineFeed = 10, - LMenu = 0xa4, - LShiftKey = 160, - LWin = 0x5b, - M = 0x4d, - MButton = 4, - MediaNextTrack = 0xb0, - MediaPlayPause = 0xb3, - MediaPreviousTrack = 0xb1, - MediaStop = 0xb2, - Menu = 0x12, - Modifiers = -65536, - Multiply = 0x6a, - N = 0x4e, - Next = 0x22, - NoName = 0xfc, - None = 0, - NumLock = 0x90, - NumPad0 = 0x60, - NumPad1 = 0x61, - NumPad2 = 0x62, - NumPad3 = 0x63, - NumPad4 = 100, - NumPad5 = 0x65, - NumPad6 = 0x66, - NumPad7 = 0x67, - NumPad8 = 0x68, - NumPad9 = 0x69, - O = 0x4f, - Oem1 = 0xba, - Oem102 = 0xe2, - Oem2 = 0xbf, - Oem3 = 0xc0, - Oem4 = 0xdb, - Oem5 = 220, - Oem6 = 0xdd, - Oem7 = 0xde, - Oem8 = 0xdf, - OemBackslash = 0xe2, - OemClear = 0xfe, - OemCloseBrackets = 0xdd, - Oemcomma = 0xbc, - OemMinus = 0xbd, - OemOpenBrackets = 0xdb, - OemPeriod = 190, - OemPipe = 220, - Oemplus = 0xbb, - OemQuestion = 0xbf, - OemQuotes = 0xde, - OemSemicolon = 0xba, - Oemtilde = 0xc0, - P = 80, - Pa1 = 0xfd, - Packet = 0xe7, - PageDown = 0x22, - PageUp = 0x21, - Pause = 0x13, - Play = 250, - Print = 0x2a, - PrintScreen = 0x2c, - Prior = 0x21, - ProcessKey = 0xe5, - Q = 0x51, - R = 0x52, - RButton = 2, - RControlKey = 0xa3, - Return = 13, - Right = 0x27, - RMenu = 0xa5, - RShiftKey = 0xa1, - RWin = 0x5c, - S = 0x53, - Scroll = 0x91, - Select = 0x29, - SelectMedia = 0xb5, - Separator = 0x6c, - Shift = 0x10000, - ShiftKey = 0x10, - Sleep = 0x5f, - Snapshot = 0x2c, - Space = 0x20, - Subtract = 0x6d, - T = 0x54, - Tab = 9, - U = 0x55, - Up = 0x26, - V = 0x56, - VolumeDown = 0xae, - VolumeMute = 0xad, - VolumeUp = 0xaf, - W = 0x57, - X = 0x58, - XButton1 = 5, - XButton2 = 6, - Y = 0x59, - Z = 90, - Zoom = 0xfb, - LMouseButton = 0x80000, - RMouseButton = 0x80001, - MMouseButton = 0x80002, - MouseButton4 = 0x80003, - MouseButton5 = 0x80004 - }; - } -} diff --git a/Floe.Interop/RawInput.cpp b/Floe.Interop/RawInput.cpp deleted file mode 100644 index 90fae76..0000000 --- a/Floe.Interop/RawInput.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "Stdafx.h" -#include "RawInput.h" - -namespace Floe -{ - namespace Interop - { - void RawInput::Initialize(Window ^window) - { - RAWINPUTDEVICE devices[2]; - devices[0].usUsagePage = 1; - devices[0].dwFlags = RIDEV_INPUTSINK; - devices[0].hwndTarget = (HWND)(void*)(gcnew WindowInteropHelper(window))->Handle; - devices[1] = devices[0]; - devices[0].usUsage = 6; - devices[1].usUsage = 2; - RegisterRawInputDevices(&devices[0], 2, sizeof(RAWINPUTDEVICE)); - } - - void RawInput::HandleInput(IntPtr lParam) - { - RAWINPUT input; - int size; - GetRawInputData((HRAWINPUT)(void*)lParam, RID_INPUT, 0, (PUINT)&size, sizeof(RAWINPUTHEADER)); - if(size > sizeof(RAWINPUT)) - { - return; - } - GetRawInputData((HRAWINPUT)(void*)lParam, RID_INPUT, &input, (PUINT)&size, sizeof(RAWINPUTHEADER)); - InputButton key = (InputButton)0; - bool isKeyDown = false; - switch(input.header.dwType) - { - case RIM_TYPEKEYBOARD: - key = (InputButton)input.data.keyboard.VKey; - switch(key) - { - case InputButton::ShiftKey: - key = (InputButton)MapVirtualKey(input.data.keyboard.MakeCode, MAPVK_VSC_TO_VK_EX); - break; - case InputButton::Menu: - key = (input.data.keyboard.Flags & RI_KEY_E0) > 0 ? InputButton::RMenu : InputButton::LMenu; - break; - case InputButton::ControlKey: - key = (input.data.keyboard.Flags & RI_KEY_E0) > 0 ? InputButton::RControlKey : InputButton::LControlKey; - break; - case InputButton::Enter: - key = (input.data.keyboard.Flags & RI_KEY_E0) > 0 ? InputButton::Separator : InputButton::Enter; - break; - } - isKeyDown = (input.data.keyboard.Flags & RI_KEY_BREAK) == 0; - break; - case RIM_TYPEMOUSE: - if((input.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) > 0) - { - key = InputButton::LMouseButton; - isKeyDown = true; - } - else if ((input.data.mouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) > 0) - { - key = InputButton::LMouseButton; - } - else if((input.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) > 0) - { - key = InputButton::RMouseButton; - isKeyDown = true; - } - else if ((input.data.mouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) > 0) - { - key = InputButton::RMouseButton; - } - else if((input.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_DOWN) > 0) - { - key = InputButton::MMouseButton; - isKeyDown = true; - } - else if ((input.data.mouse.usButtonFlags & RI_MOUSE_MIDDLE_BUTTON_UP) > 0) - { - key = InputButton::MMouseButton; - } - else if((input.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) > 0) - { - key = InputButton::MouseButton4; - isKeyDown = true; - } - else if ((input.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) > 0) - { - key = InputButton::MouseButton4; - } - else if((input.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) > 0) - { - key = InputButton::MouseButton5; - isKeyDown = true; - } - else if ((input.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) > 0) - { - key = InputButton::MouseButton5; - } - break; - } - - if(m_eventArgs == nullptr) - { - m_eventArgs = gcnew RawInputEventArgs(); - } - m_eventArgs->Handled = false; - - if((int)key > 0) - { - m_eventArgs->Button = key; - if(isKeyDown) - { - ButtonDown(nullptr, m_eventArgs); - } - else - { - ButtonUp(nullptr, m_eventArgs); - } - } - - if(!m_eventArgs->Handled) - { - PRAWINPUT pInput = &input; - DefRawInputProc(&pInput, 1, sizeof(RAWINPUT)); - } - } - } -} diff --git a/Floe.Interop/RawInput.h b/Floe.Interop/RawInput.h deleted file mode 100644 index 4ba8172..0000000 --- a/Floe.Interop/RawInput.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include "Stdafx.h" -#include "InputButton.h" - -namespace Floe -{ - namespace Interop - { - using System::Windows::Window; - using System::Windows::Interop::WindowInteropHelper; - using System::IntPtr; - - public ref class RawInputEventArgs : System::EventArgs - { - private: - InputButton m_button; - bool m_handled; - - public: - property InputButton Button - { - InputButton get() - { - return m_button; - } - internal: - void set(InputButton button) - { - m_button = button; - } - } - - property bool Handled - { - bool get() - { - return m_handled; - } - void set(bool handled) - { - m_handled = handled; - } - } - - internal: - RawInputEventArgs() {} - }; - - public ref class RawInput - { - private: - static RawInputEventArgs ^m_eventArgs; - - public: - static void Initialize(Window ^window); - static void HandleInput(IntPtr lParam); - - static event System::EventHandler ^ButtonDown; - static event System::EventHandler ^ButtonUp; - }; - } -} diff --git a/Floe.Interop/Stdafx.cpp b/Floe.Interop/Stdafx.cpp deleted file mode 100644 index f6d2fe6..0000000 --- a/Floe.Interop/Stdafx.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// Floe.Audio.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" diff --git a/Floe.Interop/Stdafx.h b/Floe.Interop/Stdafx.h deleted file mode 100644 index 7242a04..0000000 --- a/Floe.Interop/Stdafx.h +++ /dev/null @@ -1,11 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, -// but are changed infrequently - -#pragma once - - -#include -#include -#include -#include diff --git a/Floe.Interop/WaveFormat.h b/Floe.Interop/WaveFormat.h deleted file mode 100644 index 24c097e..0000000 --- a/Floe.Interop/WaveFormat.h +++ /dev/null @@ -1,211 +0,0 @@ -#pragma once - -namespace Floe -{ - namespace Interop - { - using System::IntPtr; - using System::Byte; - - public ref class WaveFormat - { - private: - WAVEFORMATEX *m_format; - - public: - WaveFormat(WAVEFORMATEX *format) - { - this->Init(format); - } - - WaveFormat(IntPtr format) - { - this->Init((WAVEFORMATEX*)(void*)format); - } - - WaveFormat(array^ format) - { - pin_ptr ptr = &format[0]; - this->Init((WAVEFORMATEX*)ptr); - } - - property WAVEFORMATEX *Data - { - WAVEFORMATEX *get() - { - return m_format; - } - } - - property IntPtr Handle - { - IntPtr get() - { - return (IntPtr)m_format; - } - } - - property short FormatTag - { - short get() - { - return m_format->wFormatTag; - } - } - - property int SampleRate - { - int get() - { - return m_format->nSamplesPerSec; - } - } - - property short BitsPerSample - { - short get() - { - return m_format->wBitsPerSample; - } - } - - property short Channels - { - short get() - { - return m_format->nChannels; - } - } - - property short FrameSize - { - short get() - { - return m_format->nBlockAlign; - } - } - - property int ByteRate - { - int get() - { - return m_format->nAvgBytesPerSec; - } - } - - protected: - WaveFormat() {} - - void Init(WAVEFORMATEX *format) - { - int size = sizeof(WAVEFORMATEX) + format->cbSize; - m_format = (WAVEFORMATEX*)malloc(size); - memcpy(m_format, format, size); - } - - private: - ~WaveFormat() - { - if(m_format != 0) - { - delete m_format; - m_format = 0; - } - } - - !WaveFormat() - { - this->~WaveFormat(); - } - }; - - public ref class WaveFormatPcm : WaveFormat - { - public: - WaveFormatPcm(int sampleRate, int bitsPerSample, short channels) - { - WAVEFORMATEX format; - format.wFormatTag = WAVE_FORMAT_PCM; - format.nSamplesPerSec = sampleRate; - format.wBitsPerSample = bitsPerSample; - format.nChannels = channels; - format.cbSize = 0; - format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; - format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; - - this->Init(&format); - } - }; - - public ref class WaveFormatGsm610 : WaveFormat - { - public: - WaveFormatGsm610(int sampleRate) - { - if(sampleRate % 320 != 0) - { - throw gcnew System::ArgumentException("Invalid sample rate for GSM 6.10."); - } - - GSM610WAVEFORMAT format; - format.wfx.wFormatTag = WAVE_FORMAT_GSM610; - format.wfx.nChannels = 1; - format.wfx.nSamplesPerSec = sampleRate; - format.wfx.nAvgBytesPerSec = (sampleRate / 320) * 65; - format.wfx.nBlockAlign = 65; - format.wfx.wBitsPerSample = 0; - format.wfx.cbSize = 2; - format.wSamplesPerBlock = 320; - - this->Init((WAVEFORMATEX*)&format); - } - - property short SamplesPerBlock - { - short get() - { - return ((GSM610WAVEFORMAT*)this->Data)->wSamplesPerBlock; - } - } - }; - - public ref class WaveFormatMp3 : WaveFormat - { - public: - WaveFormatMp3(short channels, int sampleRate, int bitRate) - { - MPEGLAYER3WAVEFORMAT format; - format.wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3; - format.wfx.nChannels = channels; - format.wfx.nSamplesPerSec = sampleRate; - format.wfx.nAvgBytesPerSec = bitRate * 8 * sampleRate * channels; - format.wfx.nBlockAlign = 1; - format.wfx.wBitsPerSample = 0; - format.wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES; - format.wID = MPEGLAYER3_ID_MPEG; - format.fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF; - format.nBlockSize = (144 * bitRate) / sampleRate; - format.nFramesPerBlock = 1; - format.nCodecDelay = 0; - - this->Init((WAVEFORMATEX*)&format); - } - - property int FramesPerBlock - { - int get() - { - return ((MPEGLAYER3WAVEFORMAT*)this->Data)->nFramesPerBlock; - } - } - - property int BlockSize - { - int get() - { - return ((MPEGLAYER3WAVEFORMAT*)this->Data)->nBlockSize; - } - } - }; - } -} diff --git a/Floe.Interop/WaveIn.cpp b/Floe.Interop/WaveIn.cpp deleted file mode 100644 index c8cac15..0000000 --- a/Floe.Interop/WaveIn.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include "Stdafx.h" -#include "WaveIn.h" - -namespace Floe -{ - namespace Interop - { - WaveIn::WaveIn(Stream ^stream, WaveFormat ^format, int bufferSize) - { - m_stream = stream; - m_format = format; - m_bufferSize = bufferSize; - m_stop = gcnew AutoResetEvent(false); - } - - void WaveIn::Start() - { - m_thread = gcnew Thread(gcnew ThreadStart(this, &WaveIn::Loop)); - m_thread->IsBackground = true; - m_thread->Priority = ThreadPriority::Highest; - m_thread->Start(); - } - - void WaveIn::Pause() - { - waveInStop(m_wavHandle); - } - - void WaveIn::Resume() - { - waveInStart(m_wavHandle); - } - - void WaveIn::Close() - { - m_stop->Set(); - } - - void WaveIn::Loop() - { - using namespace System::Runtime::InteropServices; - - array ^bytes = gcnew array(m_bufferSize); - AutoResetEvent ^bufEvent = gcnew AutoResetEvent(false); - array ^handles = { m_stop, bufEvent }; - int bufIdx = 0; - HWAVEIN wavHandle; - WAVEHDR hdr[2]; - bool isInitialized = false; - - try - { - ThrowOnFailure(waveInOpen(&wavHandle, WAVE_MAPPER, m_format->Data, (int)bufEvent->Handle, 0, CALLBACK_EVENT)); - m_wavHandle = wavHandle; - for(int i = 0; i < 2; i++) - { - hdr[i].lpData = (LPSTR)new BYTE[m_bufferSize]; - hdr[i].dwBufferLength = m_bufferSize; - hdr[i].dwFlags = hdr[i].dwBytesRecorded = 0; - ThrowOnFailure(waveInPrepareHeader(wavHandle, &hdr[i], sizeof(WAVEHDR))); - } - isInitialized = true; - waveInStart(wavHandle); - - while(true) - { - switch(WaitHandle::WaitAny(handles)) - { - case 0: - return; - case 1: - for(int i = 0; i < 2; i++) - { - if((hdr[i].dwFlags & WHDR_INQUEUE) == 0) - { - int count = hdr[i].dwBytesRecorded; - if(count > 0) - { - Marshal::Copy((IntPtr)hdr[i].lpData, bytes, 0, count); - m_stream->Write(bytes, 0, count); - } - ThrowOnFailure(waveInAddBuffer(wavHandle, &hdr[i], sizeof(WAVEHDR))); - } - } - } - } - } - catch(InteropException ^ex) - { - this->Error(this, gcnew InteropErrorEventArgs(ex)); - } - finally - { - if(isInitialized) - { - waveInReset(wavHandle); - for(int i = 0; i < 2; i++) - { - waveInUnprepareHeader(wavHandle, &hdr[i], sizeof(WAVEHDR)); - delete[] (BYTE*)hdr[i].lpData; - } - waveInClose(wavHandle); - } - } - } - - WaveIn::~WaveIn() - { - this->Close(); - if(m_thread != nullptr) - { - m_thread->Join(); - m_thread = nullptr; - } - } - - WaveIn::!WaveIn() - { - this->~WaveIn(); - } - } -} diff --git a/Floe.Interop/WaveIn.h b/Floe.Interop/WaveIn.h deleted file mode 100644 index 499bcec..0000000 --- a/Floe.Interop/WaveIn.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "Stdafx.h" -#include "Common.h" - -namespace Floe -{ - namespace Interop - { - using namespace System::IO; - using namespace System::Threading; - - public ref class WaveIn - { - private: - Stream ^m_stream; - WaveFormat ^m_format; - Thread ^m_thread; - AutoResetEvent ^m_stop; - int m_bufferSize; - HWAVEIN m_wavHandle; - - public: - WaveIn(Stream ^stream, WaveFormat ^format, int bufferSize); - void Start(); - void Pause(); - void Resume(); - void Close(); - event System::EventHandler ^Error; - - private: - void Loop(); - ~WaveIn(); - !WaveIn(); - }; - } -} diff --git a/Floe.Interop/WaveOut.cpp b/Floe.Interop/WaveOut.cpp deleted file mode 100644 index a4166a0..0000000 --- a/Floe.Interop/WaveOut.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "Stdafx.h" -#include "WaveOut.h" - -namespace Floe -{ - namespace Interop - { - WaveOut::WaveOut(Stream ^stream, WaveFormat ^format, int bufferSize) - { - m_stream = stream; - m_format = format; - m_bufferSize = bufferSize; - m_stop = gcnew AutoResetEvent(false); - m_volume = 1.0f; - } - - void WaveOut::Start() - { - m_thread = gcnew Thread(gcnew ThreadStart(this, &WaveOut::Loop)); - m_thread->IsBackground = true; - m_thread->Priority = ThreadPriority::Highest; - m_thread->Start(); - } - - void WaveOut::Pause() - { - waveOutPause(m_wavHandle); - } - - void WaveOut::Resume() - { - waveOutRestart(m_wavHandle); - } - - void WaveOut::Close() - { - m_stop->Set(); - } - - void WaveOut::Loop() - { - using namespace System::Runtime::InteropServices; - - array ^bytes = gcnew array(m_bufferSize); - AutoResetEvent ^bufEvent = gcnew AutoResetEvent(false); - array ^handles = { m_stop, bufEvent }; - int bufIdx = 0; - HWAVEOUT wavHandle; - WAVEHDR hdr[2]; - bool isInitialized = false; - - try - { - ThrowOnFailure(waveOutOpen(&wavHandle, WAVE_MAPPER, m_format->Data, (int)bufEvent->Handle, 0, CALLBACK_EVENT)); - m_wavHandle = wavHandle; - for(int i = 0; i < 2; i++) - { - hdr[i].lpData = (LPSTR)new BYTE[m_bufferSize]; - hdr[i].dwBufferLength = m_bufferSize; - hdr[i].dwFlags = 0; - ThrowOnFailure(waveOutPrepareHeader(wavHandle, &hdr[i], sizeof(WAVEHDR))); - } - isInitialized = true; - this->Volume = m_volume; - - while(true) - { - switch(WaitHandle::WaitAny(handles)) - { - case 0: - return; - case 1: - bool eos = true; - for(int i = 0; i < 2; i++) - { - if((hdr[i].dwFlags & WHDR_INQUEUE) == 0) - { - hdr[i].dwBufferLength = (int)m_stream->Read(bytes, 0, m_bufferSize); - Marshal::Copy(bytes, 0, (IntPtr)hdr[i].lpData, hdr[i].dwBufferLength); - ThrowOnFailure(waveOutWrite(wavHandle, &hdr[i], sizeof(WAVEHDR))); - if(hdr[i].dwBufferLength > 0) - { - eos = false; - } - } - } - if(eos) - { - this->EndOfStream(this, System::EventArgs::Empty); - } - } - } - } - catch(InteropException ^ex) - { - this->Error(this, gcnew InteropErrorEventArgs(ex)); - } - finally - { - if(isInitialized) - { - waveOutReset(wavHandle); - for(int i = 0; i < 2; i++) - { - waveOutUnprepareHeader(wavHandle, &hdr[i], sizeof(WAVEHDR)); - delete[] (BYTE*)hdr[i].lpData; - } - waveOutClose(wavHandle); - } - } - } - - WaveOut::~WaveOut() - { - this->Close(); - if(m_thread != nullptr) - { - m_thread->Join(); - m_thread = nullptr; - } - } - - WaveOut::!WaveOut() - { - this->~WaveOut(); - } - } -} diff --git a/Floe.Interop/WaveOut.h b/Floe.Interop/WaveOut.h deleted file mode 100644 index f83ba0b..0000000 --- a/Floe.Interop/WaveOut.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once -#include "Stdafx.h" -#include "Common.h" - -namespace Floe -{ - namespace Interop - { - using namespace System::IO; - using namespace System::Threading; - using System::Math; - - public ref class WaveOut - { - private: - Stream ^m_stream; - WaveFormat ^m_format; - Thread ^m_thread; - AutoResetEvent ^m_stop; - int m_bufferSize; - float m_volume; - HWAVEOUT m_wavHandle; - - public: - WaveOut(Stream ^stream, WaveFormat ^format, int bufferSize); - void Start(); - void Pause(); - void Resume(); - void Close(); - event System::EventHandler ^Error; - - property float Volume - { - float get() - { - DWORD vol; - waveOutGetVolume(m_wavHandle, &vol); - return (float)(vol & 0xffff) / 255.0f; - } - void set(float value) - { - m_volume = Math::Max(0.0f, Math::Min(1.0f, value)); - DWORD vol = (DWORD)(value * 0xffff); - vol |= (vol << 16); - waveOutSetVolume(m_wavHandle, vol); - } - } - - event System::EventHandler ^EndOfStream; - - private: - void Loop(); - ~WaveOut(); - !WaveOut(); - }; - } -} diff --git a/Floe.Net/Floe.Net.csproj b/Floe.Net/Floe.Net.csproj index 0b7b8ef..7124048 100644 --- a/Floe.Net/Floe.Net.csproj +++ b/Floe.Net/Floe.Net.csproj @@ -1,118 +1,8 @@ - - + + - Debug - AnyCPU - 8.0.30703 - 2.0 - {1D4AD463-4355-4DA6-B8E6-0E8BB75B50D9} - Library - Properties - Floe.Net - Floe.Net - v4.0 - 512 - Client + netcoreapp3.1 + true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true - - - ..\Floe.snk - - - true - bin\x64\Debug\ - DEBUG;TRACE - full - x64 - prompt - MinimumRecommendedRules.ruleset - - - bin\x64\Release\ - TRACE - true - pdbonly - x64 - prompt - MinimumRecommendedRules.ruleset - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - prompt - MinimumRecommendedRules.ruleset - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - prompt - MinimumRecommendedRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + diff --git a/Floe.Net/Irc/IrcCode.cs b/Floe.Net/Irc/IrcCode.cs index 4fdf5c9..c518800 100644 --- a/Floe.Net/Irc/IrcCode.cs +++ b/Floe.Net/Irc/IrcCode.cs @@ -32,9 +32,11 @@ public enum IrcCode RPL_CHANNELMODEIS = 324, RPL_UNIQOPIS = 325, RPL_CHANNELCREATEDON = 329, + RPL_WHOISACCOUNT = 330, RPL_NOTOPIC = 331, RPL_TOPIC = 332, RPL_TOPICSETBY = 333, + RPL_WHOISUSERHOST = 338, RPL_INVITING = 341, RPL_SUMMONING = 342, RPL_INVITELIST = 346, @@ -94,6 +96,7 @@ public enum IrcCode RPL_ADMINLOC2 = 258, RPL_ADMINEMAIL = 259, RPL_TRYAGAIN = 263, + ERR_ERROR = 400, ERR_NOSUCHNICK = 401, ERR_NOSUCHSERVER = 402, ERR_NOSUCHCHANNEL = 403, diff --git a/Floe.Net/Irc/IrcEventArgs.cs b/Floe.Net/Irc/IrcEventArgs.cs index 9b8c778..f0c0cf3 100644 --- a/Floe.Net/Irc/IrcEventArgs.cs +++ b/Floe.Net/Irc/IrcEventArgs.cs @@ -73,7 +73,7 @@ public sealed class IrcMessageEventArgs : IrcEventArgs /// /// Gets the user who sent the message. /// - public IrcPeer From { get; private set; } + public IrcTarget From { get; private set; } /// /// Gets the target of the message. It could be sent to a channel or directly to the user who owns the IRC session. @@ -88,7 +88,7 @@ public sealed class IrcMessageEventArgs : IrcEventArgs internal IrcMessageEventArgs(IrcMessage message) : base(message) { - this.From = message.From as IrcPeer; + this.From = new IrcTarget(message.From); this.To = message.Parameters.Count > 0 ? new IrcTarget(message.Parameters[0]) : null; this.Text = message.Parameters.Count > 1 ? message.Parameters[1] : null; } @@ -177,7 +177,7 @@ public sealed class IrcTopicEventArgs : IrcEventArgs /// /// Gets the user who changed the topic. /// - public IrcPeer Who { get; private set; } + public IrcTarget Who { get; private set; } /// /// Gets the channel in which the topic was changed. @@ -192,7 +192,7 @@ public sealed class IrcTopicEventArgs : IrcEventArgs internal IrcTopicEventArgs(IrcMessage message) : base(message) { - this.Who = message.From as IrcPeer; + this.Who = new IrcTarget(message.From); this.Channel = message.Parameters.Count > 0 ? new IrcTarget(message.Parameters[0]) : null; this.Text = message.Parameters.Count > 1 ? message.Parameters[1] : null; } @@ -206,7 +206,7 @@ public sealed class IrcInviteEventArgs : IrcEventArgs /// /// Gets the user who sent the invite. /// - public IrcPeer From { get; private set; } + public IrcTarget From { get; private set; } /// /// Gets the channel to which the target was invited. @@ -216,7 +216,7 @@ public sealed class IrcInviteEventArgs : IrcEventArgs internal IrcInviteEventArgs(IrcMessage message) : base(message) { - this.From = message.From as IrcPeer; + this.From = new IrcTarget(message.From); this.Channel = message.Parameters.Count > 1 ? message.Parameters[1] : null; } } @@ -229,7 +229,7 @@ public sealed class IrcKickEventArgs : IrcEventArgs /// /// Gets the user who performed the kick. /// - public IrcPeer Kicker { get; private set; } + public IrcTarget Kicker { get; private set; } /// /// Gets the channel from which someone has been kicked. @@ -249,7 +249,7 @@ public sealed class IrcKickEventArgs : IrcEventArgs internal IrcKickEventArgs(IrcMessage message) : base(message) { - this.Kicker = message.From as IrcPeer; + this.Kicker = new IrcTarget(message.From); this.Channel = message.Parameters.Count > 0 ? new IrcTarget(message.Parameters[0]) : null; this.KickeeNickname = message.Parameters.Count > 1 ? message.Parameters[1] : null; this.Text = message.Parameters.Count > 2 ? message.Parameters[2] : null; @@ -264,7 +264,7 @@ public sealed class IrcChannelModeEventArgs : IrcEventArgs /// /// Gets the user who performed the mode change. /// - public IrcPeer Who { get; private set; } + public IrcTarget Who { get; private set; } /// /// Gets the channel on which the modes were changed. @@ -279,7 +279,7 @@ public sealed class IrcChannelModeEventArgs : IrcEventArgs internal IrcChannelModeEventArgs(IrcMessage message) : base(message) { - this.Who = message.From as IrcPeer; + this.Who = new IrcTarget(message.From); this.Channel = message.Parameters.Count > 0 ? new IrcTarget(message.Parameters[0]) : null; this.Modes = message.Parameters.Count > 1 ? IrcChannelMode.ParseModes(message.Parameters.Skip(1)) : null; } @@ -335,6 +335,9 @@ internal IrcInfoEventArgs(IrcMessage message) this.Text = message.Parameters.Count > 1 ? string.Join(" ", message.Parameters.Skip(1).ToArray()) : null; this.IsError = (int)this.Code >= 400; + + if (this.IsError && String.IsNullOrEmpty(this.Text)) + this.Text = "ERROR: " + message.Parameters[0]; } } @@ -346,7 +349,7 @@ public sealed class CtcpEventArgs : IrcEventArgs /// /// Gets the user who sent the command. /// - public IrcPeer From { get; private set; } + public IrcTarget From { get; private set; } /// /// Gets the target to which the command was sent. It could be sent to a channel or directly to the user who owns the IRC session. @@ -366,7 +369,7 @@ public sealed class CtcpEventArgs : IrcEventArgs internal CtcpEventArgs(IrcMessage message) : base(message) { - this.From = message.From as IrcPeer; + this.From = new IrcTarget(message.From); this.To = message.Parameters.Count > 0 ? new IrcTarget(message.Parameters[0]) : null; this.Command = message.Parameters.Count > 1 ? CtcpCommand.Parse(message.Parameters[1]) : null; this.IsResponse = message.Command == "NOTICE"; diff --git a/Floe.Net/Irc/IrcMessage.cs b/Floe.Net/Irc/IrcMessage.cs index dc5b032..c4aefa8 100644 --- a/Floe.Net/Irc/IrcMessage.cs +++ b/Floe.Net/Irc/IrcMessage.cs @@ -78,7 +78,7 @@ public override string ToString() } sb.Append(' '); - if (i == this.Parameters.Count - 1) + if ((i == this.Parameters.Count - 1) && (this.Command != "PASS") && (this.Parameters[i] != ":")) sb.Append(':'); sb.Append(this.Parameters[i]); } diff --git a/Floe.Net/Irc/IrcPrefix.cs b/Floe.Net/Irc/IrcPrefix.cs index 6371fc5..88f63d1 100644 --- a/Floe.Net/Irc/IrcPrefix.cs +++ b/Floe.Net/Irc/IrcPrefix.cs @@ -26,7 +26,17 @@ public override string ToString() return this.Prefix; } - public static IrcPrefix Parse(string prefix) + public override bool Equals(object obj) + { + return this.Prefix.Equals(obj.ToString(), StringComparison.OrdinalIgnoreCase); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public static IrcPrefix Parse(string prefix) { if (string.IsNullOrEmpty(prefix)) { diff --git a/Floe.Net/Irc/IrcSession.cs b/Floe.Net/Irc/IrcSession.cs index 388b702..6a26ff4 100644 --- a/Floe.Net/Irc/IrcSession.cs +++ b/Floe.Net/Irc/IrcSession.cs @@ -198,7 +198,7 @@ private set /// /// Fires when the topic of a channel has been changed. /// - public event EventHandler TopicChanged; + public event EventHandler TopicChanged; /// /// Fires when the session has been invited to a channel. @@ -238,9 +238,10 @@ private set /// /// Default constructor. /// - public IrcSession() + public IrcSession(string nickName = null) { this.State = IrcSessionState.Disconnected; + this.Nickname = nickName; this.UserModes = new char[0]; _syncContext = SynchronizationContext.Current; @@ -391,6 +392,25 @@ public void Quote(string rawText) this.Send(new IrcMessage(rawText)); } + /// + /// Request an oper + /// + /// The optional command parameters. + public void Oper(params string[] parameters) + { + this.Send("OPER", parameters); + } + + /// + /// Kill a user. The session must be an IRC Operator. + /// + /// The user who will be killed. + /// The kill message. + public void Kill(IrcTarget target, string message) + { + this.Send("KILL", target, message); + } + /// /// Change the nickname. /// @@ -469,6 +489,16 @@ public void Part(string channel) this.Send("PART", channel); } + /// + /// Part (leave) a channel with message. + /// + /// The channel to leave. + /// The optional part message. + public void Part(string channel, string text) + { + this.Send("PART", channel, text); + } + /// /// Change the topic on a channel. The session must have the appropriate permissions on the channel. /// @@ -488,6 +518,14 @@ public void Topic(string channel) this.Send("TOPIC", channel); } + /// + /// Query the actual list of channels invited to. + /// + public void Invite() + { + this.Send("INVITE"); + } + /// /// Invite another user to a channel. The session must have the appropriate permissions on the channel. /// @@ -743,6 +781,14 @@ public bool RemoveHandler(IrcCodeHandler capture) } } + public bool ContainsHandler(IrcCodeHandler capture) + { + lock (_captures) + { + return _captures.Contains(capture); + } + } + private void RaiseEvent(EventHandler evt, T e) where T : EventArgs { if (evt != null) @@ -887,9 +933,10 @@ private void OnMessageReceived(IrcEventArgs e) case "MODE": this.OnMode(e.Message); break; - case "CAP": - this.OnCap(e.Message); - break; + case "CAP": + this.OnCap(e.Message); + break; + case "ERROR": default: this.OnOther(e.Message); break; @@ -953,7 +1000,11 @@ private void OnJoin(IrcMessage message) { var handler = this.Joined; var e = new IrcJoinEventArgs(message); - if (this.IsSelf(e.Who.Nickname)) + if (e.Who == null) + { + handler = this.SelfJoined; + } + else if (this.IsSelf(e.Who.Nickname)) { handler = this.SelfJoined; } @@ -1012,30 +1063,32 @@ private void OnMode(IrcMessage message) } } - // IRCv3 Client Capability Negotiation - private void OnCap(IrcMessage message) - { - if (message.Parameters.Count >= 2) - { - switch (message.Parameters[1].ToUpper()) - { - // RIGHT NOW WE DON'T CARE, we're just supporting one thing and ZNC 1.4 doesn't really - // follow the spec like I thought it would... - // We don't really even need to do anything about "ACK" but we might want to handle "NAK" - // in case ZNC 1.5 or whatever drops znc.in/server-time-iso in favor of server-time... - case "LS": // Server listed capabilities. END or REQ. - break; - case "ACK": // Server acknowledged. Turn it on. - break; - case "NAK": // Server rejected. Turn it off. - break; - case "LIST": // Server listed. Make sure we match? - break; - default: // Who cares? - break; - } - } - } + // IRCv3 Client Capability Negotiation + private void OnCap(IrcMessage message) + { + if (message.Parameters.Count >= 2) + { + switch (message.Parameters[1].ToUpper()) + { + // RIGHT NOW WE DON'T CARE, we're just supporting one thing and ZNC 1.4 doesn't really + // follow the spec like I thought it would... + // We don't really even need to do anything about "ACK" but we might want to handle "NAK" + // in case ZNC 1.5 or whatever drops znc.in/server-time-iso in favor of server-time... + case "LS": // Server listed capabilities. END or REQ. + _conn.QueueMessage(new IrcMessage("CAP REQ", message.Parameters.Skip(2).ToArray())); + break; + case "ACK": // Server acknowledged. Turn it on. + _conn.QueueMessage(new IrcMessage("CAP", "END")); + break; + case "NAK": // Server rejected. Turn it off. + break; + case "LIST": // Server listed. Make sure we match? + break; + default: // Who cares? + break; + } + } + } private void OnOther(IrcMessage message) { @@ -1074,6 +1127,11 @@ private void OnOther(IrcMessage message) this.RaiseEvent(this.InfoReceived, e); } + else if (message.Command == "ERROR") + { + var e = new IrcInfoEventArgs(new IrcMessage(((int)IrcCode.ERR_ERROR).ToString(), message.Parameters.ToArray())); + this.RaiseEvent(this.InfoReceived, e); + } } private void OnCtcpCommand(IrcMessage message) @@ -1102,10 +1160,10 @@ private void _conn_Connected(object sender, EventArgs e) Dns.GetHostEntry(string.Empty).AddressList .Where((ip) => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault(); - // IRCv3 Client Capability Negotiation - //_conn.QueueMessage(new IrcMessage("CAP", "LS")); - // NEGOTIATION? I MEANT A ONE-SIDED DEMAND. - _conn.QueueMessage(new IrcMessage("CAP", "REQ", "znc.in/server-time-iso")); + // IRCv3 Client Capability Negotiation + _conn.QueueMessage(new IrcMessage("CAP", "LS")); + // NEGOTIATION? I MEANT A ONE-SIDED DEMAND. + _conn.QueueMessage(new IrcMessage("CAP", "REQ", "znc.in/server-time-iso")); if (!string.IsNullOrEmpty(_password)) { @@ -1131,6 +1189,6 @@ private void _conn_Heartbeat(object sender, EventArgs e) _isWaitingForActivity = true; this.Send("PING", this.Server); } - } + } } } diff --git a/Floe.Net/Irc/IrcTarget.cs b/Floe.Net/Irc/IrcTarget.cs index 486cf3d..52291ee 100644 --- a/Floe.Net/Irc/IrcTarget.cs +++ b/Floe.Net/Irc/IrcTarget.cs @@ -7,6 +7,11 @@ namespace Floe.Net /// public sealed class IrcTarget { + /// + /// Gets the IrcPrefix of this IrcTarget was constructed from. + /// + public IrcPrefix Prefix { get; private set; } + /// /// Gets a value indicating whether the target is a channel. If this is false, the target is a user. /// @@ -45,10 +50,40 @@ public IrcTarget(bool isChannel, string name) /// public IrcTarget(IrcPeer peer) { + this.Prefix = peer; this.IsChannel = false; this.Name = peer.Nickname; } + /// + /// Construct an IrcTarget from an IrcServer. This is useful when replying to a received message. + /// + /// + public IrcTarget(IrcServer peer) + { + this.Prefix = peer; + this.IsChannel = false; + this.Name = peer.ServerName; + } + + /// + /// Construct an IrcTarget from an IrcPrefix. This is useful when replying to a received message. + /// + /// + public IrcTarget(IrcPrefix peer) + { + this.Prefix = peer; + this.IsChannel = false; + if (peer is IrcPeer) + { + this.Name = new IrcPeer(peer.Prefix.ToString()).Nickname; + } + if (peer is IrcServer) + { + this.Name = new IrcServer(peer.Prefix.ToString()).ServerName; + } + } + /// /// Gets the name of the target. /// @@ -65,7 +100,13 @@ public override string ToString() /// Returns true if the name refers to a channel, false if it refers to a user. public static bool IsChannelName(string name) { - return name.Length > 1 && name[0] == '#' || name[0] == '+' || name[0] == '&' || name[0] == '!'; + if (name.Length < 1) + return false; + if (name.StartsWith("@")) + name = name.Substring(1); + if (name.Length < 1) + return false; + return name[0] == '#' || name[0] == '+' || name[0] == '&' || name[0] == '!'; } /// @@ -76,8 +117,19 @@ public static bool IsChannelName(string name) public override bool Equals(object obj) { var other = obj as IrcTarget; + string otherName = String.Empty; + if (other != null) + { + otherName = other.Name; + if (otherName.StartsWith("@")) + otherName = otherName.Substring(1); + } + string thisName = this.Name; + if (thisName.StartsWith("@")) + thisName = thisName.Substring(1); + return other != null && other.IsChannel == this.IsChannel && - string.Compare(other.Name, this.Name, StringComparison.OrdinalIgnoreCase) == 0; + string.Compare(otherName, thisName, StringComparison.OrdinalIgnoreCase) == 0; } /// diff --git a/Floe.Net/Properties/AssemblyInfo.cs b/Floe.Net/Properties/AssemblyInfo.cs deleted file mode 100644 index 13ea761..0000000 --- a/Floe.Net/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Floe.Net")] -[assembly: AssemblyDescription("Floe Network Library")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Floe")] -[assembly: AssemblyCopyright("Copyright © 2011")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -[assembly: ComVisible(false)] - -[assembly: Guid("0d14d2ad-80d2-49f5-8868-22a731e328a1")] - -[assembly: AssemblyVersion("1.6.1.0")] -[assembly: AssemblyFileVersion("1.6.1.0")] -[assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/Floe.Net/Utils/UnixTimeStamp.cs b/Floe.Net/Utils/UnixTimeStamp.cs new file mode 100644 index 0000000..35b1c91 --- /dev/null +++ b/Floe.Net/Utils/UnixTimeStamp.cs @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2010-2012 Dani J + * Copyright (C) 2016 Gergo F. + * + * 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 3 of the License, or + * (at your option) any later version. + * + * This program 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, see . + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Floe.Net +{ + /// + /// Converts a DateTime to and from a Unix timestamp + /// (number of seconds since 1-1-1970) + /// + public class UnixTimestamp + { + /// + /// Default constructor + /// + public UnixTimestamp() + { + Timestamp = 0; + } + /// + /// Constructs a UnixTimestamp from an integer value + /// + /// + public UnixTimestamp(int timestamp) + { + Timestamp = timestamp; + } + /// + /// Constructs a UnixTimestamp from a DateTime value + /// + /// + public UnixTimestamp(DateTime dateTime) + { + DateTime = dateTime; + } + /// + /// Gets or sets the timestamp + /// + public int Timestamp { get; set; } + /// + /// Gets or sets the timestamp + /// + public DateTime DateTime + { + get + { + return DateTimeFromTimestamp(Timestamp); + } + set + { + Timestamp = TimestampFromDateTime(value); + } + } + /// + /// Converts a UnixTimestamp to a string + /// + /// + public override string ToString() + { + return Timestamp.ToString(); + } + /// + /// Calculates the current timestamp + /// + /// + public static UnixTimestamp CurrentTimestamp() + { + return new UnixTimestamp( + (int)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds + ); + } + /// + /// Converts a DateTime to a timestamp + /// + /// + /// + public static int TimestampFromDateTime(DateTime value) + { + return (int)(value - new DateTime(1970, 1, 1, 0, 0, 0)).TotalSeconds; + } + /// + /// Converts a timestamp to a DateTime + /// + /// + /// + public static DateTime DateTimeFromTimestamp(int value) + { + DateTime result = new DateTime(1970, 1, 1, 0, 0, 0); + result = result.AddSeconds(value); + result = result.Add(DateTime.Now - DateTime.UtcNow); + return result; + } + } +} diff --git a/Floe.UI/App.ico b/Floe.UI/App.ico new file mode 100644 index 0000000..c196f6c Binary files /dev/null and b/Floe.UI/App.ico differ diff --git a/Floe.UI/Application/App.xaml b/Floe.UI/Application/App.xaml index 84317b0..a70457a 100644 --- a/Floe.UI/Application/App.xaml +++ b/Floe.UI/Application/App.xaml @@ -4,192 +4,192 @@ xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" xmlns:local="clr-namespace:Floe.UI"> - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + - + - - M0,0 L8,8 M0,8 L8,0 - M 9,3 A 6,6 0 0 1 9,11 M 13,0 A 7,10 0 0 1 13,14 M 6,6 L 6,8 - M 4,12 L 17,0 - - + + + + + + + M0,0 L8,8 M0,8 L8,0 + M 9,3 A 6,6 0 0 1 9,11 M 13,0 A 7,10 0 0 1 13,14 M 6,6 L 6,8 + M 4,12 L 17,0 + + + + + + + + + + + + + + + + + + +                     + + + + + + - + - + @@ -239,11 +276,11 @@ - + + HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="{Binding Path=TabsOrientationTemplate.VerticalScrollBarVisibility}"> @@ -262,8 +299,7 @@ - + @@ -288,7 +324,7 @@ - + @@ -306,10 +342,12 @@ + + @@ -335,8 +373,8 @@ - - + + @@ -348,11 +386,11 @@ -