All pastes #319371 Raw Edit

Macca

public text v1 · immutable
#319371 ·published 2007-01-17 08:08 UTC
rendered paste body
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Diagnostics;
using System.Timers;
using System.Threading;

namespace NzbLibrary.NNTP
{
	public enum NNTPConnectionStatus { Idle, Downloading };
	public delegate void DownloadCompleteEvent(object sender);

	public class NNTPConnection : TcpClient
	{
		private static List<NNTPConnection> m_Connections = new List<NNTPConnection>();

		public static NNTPConnection[] Connections { get { return m_Connections.ToArray(); } }

		private const long PacketSize = 8192;
		private const long SpeedHistoryDuration = 120;
		private const string CacheDirectory = @"D:\Projects\NzbDownloader\Articles\";

		#region Speed Monitoring

		private Dictionary<long, long> m_SpeedHistory = new Dictionary<long, long>();
		private System.Timers.Timer m_SpeedTimer = null;
		private long m_BytesLastSecond = 0;
		private long m_Second = 0;
		private long m_StartTime;
		public Dictionary<long, long> SpeedHistory { get { return m_SpeedHistory; } }
		public long Second { get { return m_Second; } }

		private void SpeedTimer_Elapsed(object sender, EventArgs e)
		{
			if (m_BytesLastSecond > 0)
			{
				m_SpeedHistory.Add(m_Second, m_BytesLastSecond);
				m_BytesLastSecond = 0;
			}

			m_Second++;

			if (m_SpeedHistory.Count > 0)
			{
				foreach (KeyValuePair<long, long> kvp in m_SpeedHistory)
				{
					if (kvp.Key < m_Second - SpeedHistoryDuration)
					{
						m_SpeedHistory.Remove(kvp.Key);
					}
				}
			}
		}

		#endregion

		private string m_CurrentGroup = "";
		private string m_CurrentArticle = "";
		private Stream Stream { get { return GetStream(); } }
		private NNTPConnectionStatus m_Status = NNTPConnectionStatus.Idle;
		private StreamReader Reader { get { return new StreamReader(Stream); } }
		private StreamWriter Writer { get { return new StreamWriter(Stream); } }
		private string Response { get { return ReadLine(); } }
		private int ResponseCode
		{
			get
			{
				string[] Parts = Response.Split(' ');
				int Code = 0;
				if (int.TryParse(Parts[0], out Code))
				{
					Code = int.Parse(Parts[0]);
				}
				else
				{
					Code = -1;
				}

				return Code;
			}
		}

		public string CurrentGroup { get { return m_CurrentGroup; } }
		public NNTPConnectionStatus Status { get { return m_Status; } }

		public event DownloadCompleteEvent DownloadComplete;

		public NNTPConnection()
			: base()
		{
			#region Speed Monitoring
			m_SpeedTimer = new System.Timers.Timer();
			m_StartTime = DateTime.Now.Ticks;
			m_SpeedTimer.Interval = 1000;
			m_SpeedTimer.Elapsed += new ElapsedEventHandler(SpeedTimer_Elapsed);
			m_SpeedTimer.Start();
			#endregion

			m_Connections.Add(this);
		}

		~NNTPConnection()
		{
			#region Speed Monitoring
			m_SpeedTimer.Stop();
			#endregion

			m_Connections.Remove(this);
		}

		private string ReadLine()
		{
			try
			{
				string Data = Reader.ReadLine();
				Debug.WriteLine("< " + Data);
				return Data;
			}
			catch (IOException io)
			{
				if (io.InnerException is SocketException)
				{
					SocketException se = (SocketException)io.InnerException;

					if (se.ErrorCode == 10060)
						Disconnect();

					throw se;
				}
				else
				{
					throw io;
				}
			}
		}

		private void WriteLine(string Data)
		{
			Debug.WriteLine("> " + Data);

			Stream.Write(ASCIIEncoding.ASCII.GetBytes(Data), 0, Data.Length);
			Stream.Write(ASCIIEncoding.ASCII.GetBytes(Environment.NewLine), 0, Environment.NewLine.Length);
		}

		private void ClearBuffer()
		{
			Reader.ReadToEnd();
		}

		public new bool Connect(string HostName, int Port)
		{
			Debug.WriteLine("? Connecting...");
			base.Connect(HostName, Port);

			switch (ResponseCode)
			{
				case 200:
				case 201:
					Debug.WriteLine("? Connected.");
					return true;
			}

			m_CurrentGroup = "";

			Debug.WriteLine("? Connection Failed.");
			Disconnect();
			return false;
		}

		public void Disconnect()
		{
			Debug.WriteLine("? Disconnecting...");
			if (base.Connected)
			{
				WriteLine("QUIT");
			}

			base.Close();

			Debug.WriteLine("? Disconnected.");
		}

		public bool Authenticate(string UserName, string Password)
		{
			Debug.WriteLine("? Authenticating...");

			WriteLine("AUTHINFO USER " + UserName);
			if (ResponseCode == 381)
			{
				WriteLine("AUTHINFO PASS " + Password);
				if (ResponseCode == 281) 
				{
					Debug.WriteLine("? Authenticated.");

					return true; 
				}
			}
			Debug.WriteLine("? Authentication Failed.");

			return false;
		}

		public bool SelectGroup(string Group)
		{
			if (Group == CurrentGroup) { return true; }

			Debug.WriteLine("? Selecting Group: '" + Group + "'");
			WriteLine("GROUP " + Group);

			if (ResponseCode == 211)
			{
				Debug.WriteLine("? Group '" + Group + "' Selected.");
				
				m_CurrentGroup = Group;

				return true;
			}

			return false;
		}

		public bool DownloadArticle(string MessageId)
		{
			string FileName = CacheDirectory + MessageId;
			
			Debug.WriteLine("? Downloading Article: '" + MessageId);
			WriteLine("BODY <" + MessageId + ">");

			switch (ResponseCode)
			{
				case 220:
				case 221:
				case 222:
					m_Status = NNTPConnectionStatus.Downloading;
					Thread TransferThread = new Thread(Transfer);
					TransferThread.Start();
					return true;
			}

			return false;
		}

		private void Transfer()
		{
			StringBuilder Data = new StringBuilder();
			while (true)
			{
				byte[] Section = new byte[PacketSize];

				int Read = Stream.Read(Section, 0, Section.Length);

				m_BytesLastSecond += Read;

				for (int i = 0; i < Read; i++)
				{
					Data.Append((char)Section[i]);
				}

				if (Data[Data.Length - 3] == '.' && Data[Data.Length - 2] == '\r' && Data[Data.Length - 1] == '\n') { break; }

				if (Read == 0) { break; }
			}

			Data = Data.Replace("\r\n..", "\r\n.");

			FileStream Output = new FileStream(CacheDirectory + m_CurrentArticle, FileMode.Create, FileAccess.Write, FileShare.None);
			StreamWriter Writer = new StreamWriter(Output, Encoding.GetEncoding("iso-8859-1"));
			Writer.Write(Data.ToString());
			Writer.Close();
			Output.Close();

			m_CurrentArticle = "";
			if (DownloadComplete != null) { DownloadComplete(this); }
			m_Status = NNTPConnectionStatus.Idle;
		}
	}
}