Click here to Skip to main content
15,881,812 members
Articles / Programming Languages / C#

Console FTP in C#

Rate me:
Please Sign up or sign in to vote.
3.78/5 (17 votes)
7 Mar 20043 min read 224.3K   3K   46  
A basic FTP client in C#.
using System;
using System.Text;
using System.IO;
using System.Collections;
using System.Collections.Specialized;

namespace HB.Web.Mail.Mime
{
	/// <summary>
	/// A MIME part with ASCII content.
	/// </summary>
	public class MimePartContent : MimePart
	{
		/// <summary>
		/// Creates a new MIME part content object.
		/// </summary>
		/// <param name="content">The content of the MIME part.</param>
		/// <param name="contentType">The contnet-type of the MIME part.</param>
		/// <param name="boundary">The boundary of the MIME part.</param>
		/// <param name="messageBoundary">The boundary of the MIME message.</param>
		/// <remarks>Exceptions thrown from the base constructor are not caught.</remarks>
		public MimePartContent(string contentType, string boundary, string messageBoundary, string content)
			: base(contentType, boundary, messageBoundary)
		{
			this.content = new StringBuilder(content);
		}

		/// <summary>
		/// Copy constructor.
		/// </summary>
		/// <param name="mimePartContent">The MIME part content to copy.</param>
		/// <remarks>A deep copy is performed.
		/// Exceptions thrown from the base constructor are not caught.</remarks>
		public MimePartContent(MimePartContent mimePartContent) : base(mimePartContent)
		{
			content = new StringBuilder(mimePartContent.content.ToString());
		}

		/// <summary>
		/// Extracts inner <see cref="MimePartContent"/> sections from a <see cref="MimePartContent"/>.
		/// </summary>
		/// <param name="content">The <see cref="MimePartContent"/> to parse.</param>
		/// <returns>The inner <see cref="MimePartContent"/> sections of parameter content.</returns>
		/// <exception cref="ArgumentNullException">When parameter content is null.</exception>
		/// <remarks>No exception handling is performed.</remarks>
		public static MimePartContent[] Parse(MimePartContent content)
		{
			if(content == null)
				throw new ArgumentNullException("content");
			StringReader data = new StringReader(content.Content);
			ArrayList parts = new ArrayList();
			string line = data.ReadLine();
			while(line == "--" + content.Boundary)
			{
				parts.Add(GetMimePart(data, content.Boundary, out line));
				if(line == "--" + content.Boundary + "--")
					break;
			}
			return (MimePartContent[]) parts.ToArray(typeof(MimePartContent));
		}

		/// <summary>
		/// Gets the <see cref="MimePartContent"/> from a text stream.
		/// </summary>
		/// <param name="data">The text stream.</param>
		/// <param name="boundary">The <see cref="MimePart.Boundary"/> of the <see cref="MimePartContent"/>.</param>
		/// <param name="line">The last line read from the text stream.</param>
		/// <returns>The <see cref="MimePartContent"/> read from the text stream.</returns>
		/// <remarks>No exception handling is performed.</remarks>
		private static MimePartContent GetMimePart(StringReader data, string boundary, out string line)
		{
			if(data == null)
				throw new ArgumentNullException("data");
			if(boundary == null)
				throw new ArgumentNullException("boundary");
			if(boundary == string.Empty)
				throw new ArgumentException("boundary cannot be an empty string.");
			line = data.ReadLine();
			StringWriter content = new StringWriter();
			while(line != "")
			{
				content.WriteLine(line);
				line = data.ReadLine();
			}
			content.Flush();
			content.Close();
			NameValueCollection hdrs;
			GetHeaders(content.ToString(), out hdrs);
			string contenttype = hdrs["content-type"];
			MimePartContent altContent = new MimePartContent(contenttype, boundary, boundary, "");
			foreach(string key in hdrs.AllKeys)
				altContent.Headers[key] = hdrs[key];			
			content = new StringWriter();
			line = data.ReadLine();
			while((line != "--" + boundary) && (line != "--" + boundary + "--"))
			{
				content.WriteLine(line);
				line = data.ReadLine();
			}
			content.Flush();
			content.Close();
			altContent.Content = content.ToString();
			return altContent;
		}

		/// <summary>
		/// Extracts the MIME portion of an e-mail.
		/// </summary>
		/// <param name="data">The text data of the e-mail.</param>
		/// <returns>A <see cref="MimePartContent"/> containing the MIME portion of the e-mail.</returns>
		/// <exception cref="ArgumentNullException">When parameter data is null.</exception>
		/// <exception cref="ApplicationException">When an error occurred while parsing the text.</exception>
		public static MimePartContent Parse(string data)
		{			
			if(data == null)
				throw new ArgumentNullException("data");
			NameValueCollection headers;
			int linesRead = GetHeaders(data, out headers);
			object contentType = headers["content-type"];
			if(contentType == null)
				throw new ApplicationException("The content type could not be located.");
			string boundary = ExtractBoundary(contentType.ToString());
			StringReader lines = new StringReader(data);
			for(int i = 0; i < linesRead; i++)
				lines.ReadLine();
			string line = null;
			StringWriter content = new StringWriter();
			MimePartContent part = null;
			if(boundary == null)
			{
				//throw new ApplicationException("The content boundary could not be located.");
				part = new MimePartContent(contentType.ToString(), "", "", "");
				part.Headers["content-type"] = headers["content-type"];
				if(headers["content-transfer-encoding"] != null)
					part.Headers["content-transfer-encoding"] = headers["content-transfer-encoding"];
				while(lines.Peek() != -1)
					content.WriteLine(lines.ReadLine());
			}
			else
			{
				part = new MimePartContent(contentType.ToString(), boundary, boundary, "");

				if(lines.Peek() == -1)
					throw new ApplicationException("End of text reached prematurely.");
				line = lines.ReadLine();
				while(line != "--" + boundary)
				{
					if(lines.Peek() == -1)
						throw new ApplicationException("The start boundary could not be located.");
					line = lines.ReadLine();
				}

				content.WriteLine(line);
				line = lines.ReadLine();
				if(lines.Peek() == -1)
					throw new ApplicationException("The end boundary could not be located.");
				while(line != "--" + boundary + "--")
				{
					if(lines.Peek() == -1)
					{
						line = "--" + boundary + "--";
						break;
						//throw new ApplicationException("The end boundary could not be located.");
					}
					content.WriteLine(line);
					line = lines.ReadLine();				
				}
				content.Write(line);
			}			
			content.Flush();
			content.Close();
			part.Content = content.ToString();
			return part;
		}

		/// <summary>
		/// Gets or sets the content of the MIME part.
		/// </summary>
		public string Content
		{
			get
			{
				return content.ToString();
			}
			set
			{
				content = new StringBuilder(value);
			}
		}

		/// <summary>
		/// Writes the MIME part content to the provided <see cref="ArpaClientStream"/>.
		/// </summary>
		/// <param name="stream">The <see cref="ArpaClientStream"/> to write to.</param>
		/// <exception cref="ArgumentNullException">When parameter stream is null.</exception>
		/// <exception cref="ApplicationException">When an error occurred while writing to the
		/// arpa client stream.</exception>
		public override void ToData(ArpaClientStream stream)
		{
			base.WriteHeader(stream);
			if(stream == null)
				throw new ArgumentNullException("stream");
			try
			{
				stream.Write(ArpaTextMessage.MakeTransparent(Content));
			}
			catch(Exception e)
			{
				string msg = "An error occurred while writing data to the arpa client stream. " + e.Message;
				throw new ApplicationException(msg);
			}
		}

		/// <summary>
		/// Determines if this instance of <see cref="MimePartContent"/> is equal
		/// to another object.
		/// </summary>
		/// <param name="obj">The object to compare.</param>
		/// <returns>true if parameter obj is of type <see cref="MimePartContent"/>
		/// with an equal <see cref="MimePart.ContentType"/>.</returns>
		public override bool Equals(object obj)
		{
			return ((obj is MimePartContent) && (this == ((MimePartContent)obj)));
		}

		/// <summary>
		/// Determines if type objects of type <see cref="MimePartContent"/> are
		/// equal to each other.
		/// </summary>
		/// <param name="lhs">An object to compare.</param>
		/// <param name="rhs">An object to compare.</param>
		/// <returns>true if both objects are of type <see cref="MimePartContent"/>
		/// with an equal <see cref="MimePart.ContentType"/>.</returns>
		public static bool operator ==(MimePartContent lhs, MimePartContent rhs)
		{
			if(((object)lhs == null) && ((object)rhs == null))
				return true;
			if(((object)lhs == null) || ((object)rhs == null))
				return false;
			return (lhs.ContentType == rhs.ContentType);
		}

		/// <summary>
		/// Determines if type objects of type <see cref="MimePartContent"/> are
		/// not equal to each other.
		/// </summary>
		/// <param name="lhs">An object to compare.</param>
		/// <param name="rhs">An object to compare.</param>
		/// <returns>true if one or both objects are not of type <see cref="MimePartContent"/>
		/// or if both objects are of type <see cref="MimePartContent"/> 
		/// with a different<see cref="MimePart.ContentType"/>.</returns>
		public static bool operator !=(MimePartContent lhs, MimePartContent rhs)
		{
			return !MimePartContent.Equals(lhs, rhs);
		}

		/// <summary>
		/// Creates a copy of the invoked instance.
		/// </summary>
		/// <returns>A deep copy of the invoked instance.</returns>
		/// <remarks>A deep copy is made using the copy constructor.</remarks>
		public override object Clone()
		{
			return new MimePartContent(this);
		}

		/// <summary>
		/// Stores the content of the MIME part.
		/// </summary>
		protected StringBuilder content;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions