context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.IO;
  using System.Net;
  using System.Security.Cryptography;
  using System.Threading;
  using System.Net.Sockets;
  
  #if !SILVERLIGHT
  using System.Net.Security;
  #endif
  
  namespace IrcDotNet
  {
      /// <inheritdoc/>
      public class StandardIrcClient : IrcClient
      {
          // Minimum duration of time to wait between sending successive raw messages.
          private const long minimumSendWaitTime = 50;
  
          // Size of buffer for data received by socket, in bytes.
          private const int socketReceiveBufferSize = 0xFFFF;
  
          // Queue of pending messages and their tokens to be sent when ready.
          private Queue<Tuple<string, object>> messageSendQueue;
  
          // Network (TCP) I/O.
          private Socket socket;
          private CircularBufferStream receiveStream;
          private Stream dataStream;
          private StreamReader dataStreamReader;
          private SafeLineReader dataStreamLineReader;
          private Timer sendTimer;
          private AutoResetEvent disconnectedEvent;
  
          public StandardIrcClient()
              : base()
          {
  
              
              this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
              this.sendTimer = new Timer(new TimerCallback(WritePendingMessages), null,
                                         Timeout.Infinite, Timeout.Infinite);
              this.disconnectedEvent = new AutoResetEvent(false);
              this.messageSendQueue = new Queue<Tuple<string, object>>();
          }
  
          public override bool IsConnected {
              get
              {
                  CheckDisposed();
                  return this.socket != null && this.socket.Connected;
              }
          }
  
          protected override void Dispose(bool disposing)
          {
              base.Dispose(disposing);
              if (disposing)
              {
                  if (this.socket != null)
                  {
                      this.socket.Dispose();
                      this.socket = null;
  
                      HandleClientDisconnected();
                  }
                  if (this.receiveStream != null)
                  {
                      this.receiveStream.Dispose();
                      this.receiveStream = null;
                  }
                  if (this.dataStream != null)
                  {
                      this.dataStream.Dispose();
                      this.dataStream = null;
                  }
                  if (this.dataStreamReader != null)
                  {
                      this.dataStreamReader.Dispose();
                      this.dataStreamReader = null;
                  }
                  if (this.sendTimer != null)
                  {
                      this.sendTimer.Dispose();
                      this.sendTimer = null;
                  }
                  if (this.disconnectedEvent != null)
                  {
                      this.disconnectedEvent.Dispose();
                      this.disconnectedEvent = null;
                  }
              }
          }
  
          protected override void WriteMessage(string line, object token)
          {
              // Add message line to send queue.
              messageSendQueue.Enqueue(Tuple.Create(line + Environment.NewLine, token));
          }
  
          /// <inheritdoc cref="Connect(string, int, bool, IrcRegistrationInfo)"/>
          /// <summary>
          /// Connects to a server using the specified URL and user information.
          /// </summary>
          public void Connect(Uri url, IrcRegistrationInfo registrationInfo)
          {
              CheckDisposed();
  
              if (registrationInfo == null)
                  throw new ArgumentNullException("registrationInfo");
  
              // Check URL scheme and decide whether to use SSL.
              bool useSsl;
              if (url.Scheme == "irc")
                  useSsl = false;
              else if (url.Scheme == "ircs")
                  useSsl = true;
              else
                  throw new ArgumentException(string.Format("MessageInvalidUrlScheme",
                                                            url.Scheme), "url");
  
              Connect(url.Host, url.Port == -1 ? DefaultPort : url.Port, useSsl, registrationInfo);
          }
  
          /// <inheritdoc cref="Connect(string, int, bool, IrcRegistrationInfo)"/>
          public void Connect(string hostName, bool useSsl, IrcRegistrationInfo registrationInfo)
          {
              CheckDisposed();
  
              if (registrationInfo == null)
                  throw new ArgumentNullException("registrationInfo");
  
              Connect(hostName, DefaultPort, useSsl, registrationInfo);
          }
  
          /// <inheritdoc cref="Connect(EndPoint, bool, IrcRegistrationInfo)"/>
          /// <param name="hostName">The name of the remote host.</param>
          /// <param name="port">The port number of the remote host.</param>
          public void Connect(string hostName, int port, bool useSsl, IrcRegistrationInfo registrationInfo)
          {
              CheckDisposed();
  
              if (registrationInfo == null)
                  throw new ArgumentNullException("registrationInfo");
  
              Connect(new DnsEndPoint(hostName, port), useSsl, registrationInfo);
          }
  
          /// <inheritdoc cref="Connect(IPAddress, int, bool, IrcRegistrationInfo)"/>
          public void Connect(IPAddress address, bool useSsl, IrcRegistrationInfo registrationInfo)
          {
              CheckDisposed();
  
              if (registrationInfo == null)
                  throw new ArgumentNullException("registrationInfo");
  
              Connect(address, DefaultPort, useSsl, registrationInfo);
          }
  
          /// <inheritdoc cref="Connect(EndPoint, bool, IrcRegistrationInfo)"/>
          /// <param name="address">An IP addresses that designates the remote host.</param>
          /// <param name="port">The port number of the remote host.</param>
          public void Connect(IPAddress address, int port, bool useSsl, IrcRegistrationInfo registrationInfo)
          {
              CheckDisposed();
  
              if (registrationInfo == null)
                  throw new ArgumentNullException("registrationInfo");
  
              Connect(new IPEndPoint(address, port), useSsl, registrationInfo);
          }
  
          /// <summary>
          /// Connects asynchronously to the specified server.
          /// </summary>
          /// <param name="remoteEndPoint">The network endpoint (IP address and port) of the server to which to connect.
          /// </param>
          /// <param name="useSsl"><see langword="true"/> to connect to the server via SSL; <see langword="false"/>,
          /// otherwise</param>
          /// <param name="registrationInfo">The information used for registering the client.
          /// The type of the object may be either <see cref="IrcUserRegistrationInfo"/> or
          /// <see cref="IrcServiceRegistrationInfo"/>.</param>
          /// <exception cref="ArgumentNullException"><paramref name="registrationInfo"/> is <see langword="null"/>.
          /// </exception>
          /// <exception cref="ArgumentException"><paramref name="registrationInfo"/> does not specify valid registration
          /// information.</exception>
          /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
          public void Connect(EndPoint remoteEndPoint, bool useSsl, IrcRegistrationInfo registrationInfo)
          {
              Connect(registrationInfo);
              // Connect socket to remote host.
              ConnectAsync(remoteEndPoint, Tuple.Create(useSsl, string.Empty, registrationInfo));
  
              HandleClientConnecting();
          }
  
          public override void Quit(int timeout, string comment)
          {
              base.Quit(timeout, comment);
              if (!this.disconnectedEvent.WaitOne(timeout))
                  Disconnect();
          }
  
          protected override void ResetState()
          {
              base.ResetState();
  
              // Reset network I/O objects.
              if (this.receiveStream != null)
                  this.receiveStream.Dispose();
              if (this.dataStream != null)
                  this.dataStream.Dispose();
              if (this.dataStreamReader != null)
                  this.dataStreamReader = null;
          }
  
          private void WritePendingMessages(object state)
          {
              try
              {
                  // Send pending messages in queue until flood preventer indicates to stop.
                  int sendDelay = 0;
  
                  while (this.messageSendQueue.Count > 0)
                  {
                      Debug.Assert(this.messageSendQueue.Count < 100);
                      // Check that flood preventer currently permits sending of messages.
                      if (FloodPreventer != null)
                      {
                          sendDelay = FloodPreventer.GetSendDelay();
                          if (sendDelay > 0)
                              break;
                      }
  
                      // Send next message in queue.
                      var message = this.messageSendQueue.Dequeue();
                      var line = message.Item1;
                      var token = message.Item2;
                      var lineBuffer = TextEncoding.GetBytes(line);
                      SendAsync(lineBuffer, token);
  
                      // Tell flood preventer mechanism that message has just been sent.
  
gt:                     if (FloodPreventer != null)