Click here to Skip to main content
15,884,099 members
Articles / Programming Languages / C#

STUN Client

Rate me:
Please Sign up or sign in to vote.
4.83/5 (36 votes)
20 Apr 2007CPOL 322.8K   14.9K   85  
STUN client C# implementation with sample application
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;

namespace LumiSoft.Net.Mime
{
	/// <summary>
	/// Class for creating,parsing,modifing rfc 2822 mime messages.
	/// </summary>
	/// <remarks>
	/// <code>
	/// 
	/// Message examples:
	/// 
	/// <B>Simple message:</B>
	/// 
	/// //--- Beginning of message
	/// From: sender@domain.com
	/// To: recipient@domain.com
	/// Subject: Message subject.
	/// Content-Type: text/plain
	/// 
	/// Message body text. Bla blaa
	/// blaa,blaa.
	/// //--- End of message
	/// 
	/// 
	/// In simple message MainEntity is whole message.
	/// 
	/// <B>Message with attachments:</B>
	/// 
	/// //--- Beginning of message
	/// From: sender@domain.com
	/// To: recipient@domain.com
	/// Subject: Message subject.
	/// Content-Type: multipart/mixed; boundary="multipart_mixed"
	/// 
	/// --multipart_mixed	/* text entity */
	///	Content-Type: text/plain
	///	
	///	Message body text. Bla blaa
	///	blaa,blaa.	
	///	--multipart_mixed	/* attachment entity */
	///	Content-Type: application/octet-stream
	///	
	///	attachment_data
	///	--multipart_mixed--
	///	//--- End of message
	///	
	///	MainEntity is multipart_mixed entity and text and attachment entities are child entities of MainEntity.
	/// </code>
	/// </remarks>
	/// <example>
	/// <code>
	/// // Parsing example:
	/// Mime m = Mime.Parse("message.eml");
	/// // Do your stuff with mime
	/// </code>
	/// <code>
	/// // Create simple message with simple way:
	/// AddressList from = new AddressList();
	/// from.Add(new MailboxAddress("dispaly name","user@domain.com"));
	///	AddressList to = new AddressList();
	///	to.Add(new MailboxAddress("dispaly name","user@domain.com"));
	///	
	///	Mime m = Mime.CreateSimple(from,to,"test subject","test body text","");
	/// </code>
	/// <code>
	/// // Creating a new simple message
	/// Mime m = new Mime();
	/// MimeEntity mainEntity = m.MainEntity;
	/// // Force to create From: header field
	/// mainEntity.From = new AddressList();
	/// mainEntity.From.Add(new MailboxAddress("dispaly name","user@domain.com"));
	/// // Force to create To: header field
	/// mainEntity.To = new AddressList();
	/// mainEntity.To.Add(new MailboxAddress("dispaly name","user@domain.com"));
	/// mainEntity.Subject = "subject";
	/// mainEntity.ContentType = MediaType_enum.Text_plain;
	/// mainEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
	/// mainEntity.DataText = "Message body text.";
	/// 
	/// m.ToFile("message.eml");
	/// </code>
	/// <code>
	/// // Creating message with text and attachments
	/// Mime m = new Mime();
	/// MimeEntity mainEntity = m.MainEntity;
	/// // Force to create From: header field
	/// mainEntity.From = new AddressList();
	/// mainEntity.From.Add(new MailboxAddress("dispaly name","user@domain.com"));
	/// // Force to create To: header field
	/// mainEntity.To = new AddressList();
	/// mainEntity.To.Add(new MailboxAddress("dispaly name","user@domain.com"));
	/// mainEntity.Subject = "subject";
	/// mainEntity.ContentType = MediaType_enum.Multipart_mixed;
	/// 
	/// MimeEntity textEntity = mainEntity.ChildEntities.Add();
	/// textEntity.ContentType = MediaType_enum.Text_plain;
	/// textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
	/// textEntity.DataText = "Message body text.";
	/// 
	/// MimeEntity attachmentEntity = mainEntity.ChildEntities.Add();
	/// attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;
	/// attachmentEntity.ContentDisposition = ContentDisposition_enum.Attachment;
	/// attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;
	/// attachmentEntity.ContentDisposition_FileName = "yourfile.xxx";
	/// attachmentEntity.DataFromFile("yourfile.xxx");
	/// // or
	/// attachmentEntity.Data = your_attachment_data;
	/// </code>
	/// </example>
	public class Mime
	{
		private MimeEntity m_pMainEntity = null;

		/// <summary>
		/// Default constructor.
		/// </summary>
		public Mime()
		{
			m_pMainEntity = new MimeEntity();

			// Add default header fields
			m_pMainEntity.MessageID = MimeUtils.CreateMessageID();
			m_pMainEntity.Date = DateTime.Now;
			m_pMainEntity.MimeVersion = "1.0";
		}


		#region static method Parse

		/// <summary>
		/// Parses mime message from byte[] data.
		/// </summary>
		/// <param name="data">Mime message data.</param>
		/// <returns></returns>
		public static Mime Parse(byte[] data)
		{
			using(MemoryStream ms = new MemoryStream(data)){
				return Parse(ms);
			}
		}

		/// <summary>
		/// Parses mime message from file.
		/// </summary>
		/// <param name="fileName">Mime message file.</param>
		/// <returns></returns>
		public static Mime Parse(string fileName)
		{
			using(FileStream fs = File.OpenRead(fileName)){
				return Parse(fs);
			}
		}

		/// <summary>
		/// Parses mime message from stream.
		/// </summary>
		/// <param name="stream">Mime message stream.</param>
		/// <returns></returns>
		public static Mime Parse(Stream stream)
		{
			Mime mime = new Mime();
			mime.MainEntity.Parse(stream,null);

			return mime;
		}

		#endregion


		#region static method CreateSimple

		/// <summary>
		/// Creates simple mime message.
		/// </summary>
		/// <param name="from">Header field From: value.</param>
		/// <param name="to">Header field To: value.</param>
		/// <param name="subject">Header field Subject: value.</param>
		/// <param name="bodyText">Body text of message. NOTE: Pass null is body text isn't wanted.</param>
		/// <param name="bodyHtml">Body HTML text of message. NOTE: Pass null is body HTML text isn't wanted.</param>
		/// <returns></returns>
		public static Mime CreateSimple(AddressList from,AddressList to,string subject,string bodyText,string bodyHtml)
		{
			return CreateSimple(from,to,subject,bodyText,bodyHtml,null);
		}

		/// <summary>
		/// Creates simple mime message with attachments.
		/// </summary>
		/// <param name="from">Header field From: value.</param>
		/// <param name="to">Header field To: value.</param>
		/// <param name="subject">Header field Subject: value.</param>
		/// <param name="bodyText">Body text of message. NOTE: Pass null is body text isn't wanted.</param>
		/// <param name="bodyHtml">Body HTML text of message. NOTE: Pass null is body HTML text isn't wanted.</param>
		/// <param name="attachmentFileNames">Attachment file names. Pass null if no attachments. NOTE: File name must contain full path to file, for example: c:\test.pdf.</param>
		/// <returns></returns>
		public static Mime CreateSimple(AddressList from,AddressList to,string subject,string bodyText,string bodyHtml,string[] attachmentFileNames)
		{
			Mime m = new Mime();

			MimeEntity mainEntity = m.MainEntity;
			mainEntity.From = from;
			mainEntity.To = to;
			mainEntity.Subject = subject;

			// There are no atachments
			if(attachmentFileNames == null || attachmentFileNames.Length == 0){
				// If bodyText and bodyHtml both specified
				if(bodyText != null && bodyHtml != null){
					mainEntity.ContentType = MediaType_enum.Multipart_alternative;

					MimeEntity textEntity = mainEntity.ChildEntities.Add();
					textEntity.ContentType = MediaType_enum.Text_plain;
					textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textEntity.DataText = bodyText;

					MimeEntity textHtmlEntity = mainEntity.ChildEntities.Add();
					textHtmlEntity.ContentType = MediaType_enum.Text_html;
					textHtmlEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textHtmlEntity.DataText = bodyHtml;
				}
				// There is only body text
				else if(bodyText != null){
					MimeEntity textEntity = mainEntity;
					textEntity.ContentType = MediaType_enum.Text_plain;
					textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textEntity.DataText = bodyText;
				}
				// There is only body html text
				else if(bodyHtml != null){
					MimeEntity textHtmlEntity = mainEntity;
					textHtmlEntity.ContentType = MediaType_enum.Text_html;
					textHtmlEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textHtmlEntity.DataText = bodyHtml;
				}
			}
			// There are attachments
			else{				
				mainEntity.ContentType = MediaType_enum.Multipart_mixed;

				// If bodyText and bodyHtml both specified
				if(bodyText != null && bodyHtml != null){
					MimeEntity multiPartAlternativeEntity = mainEntity.ChildEntities.Add();
					multiPartAlternativeEntity.ContentType = MediaType_enum.Multipart_alternative;

					MimeEntity textEntity = multiPartAlternativeEntity.ChildEntities.Add();
					textEntity.ContentType = MediaType_enum.Text_plain;
					textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textEntity.DataText = bodyText;

					MimeEntity textHtmlEntity = multiPartAlternativeEntity.ChildEntities.Add();
					textHtmlEntity.ContentType = MediaType_enum.Text_html;
					textHtmlEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textHtmlEntity.DataText = bodyHtml;
				}
				// There is only body text
				else if(bodyText != null){
					MimeEntity textEntity = mainEntity.ChildEntities.Add();
					textEntity.ContentType = MediaType_enum.Text_plain;
					textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textEntity.DataText = bodyText;
				}
				// There is only body html text
				else if(bodyHtml != null){
					MimeEntity textHtmlEntity = mainEntity.ChildEntities.Add();
					textHtmlEntity.ContentType = MediaType_enum.Text_html;
					textHtmlEntity.ContentTransferEncoding = ContentTransferEncoding_enum.QuotedPrintable;
					textHtmlEntity.DataText = bodyHtml;
				}

				foreach(string fileName in attachmentFileNames){
					MimeEntity attachmentEntity = mainEntity.ChildEntities.Add();
					attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;
					attachmentEntity.ContentDisposition = ContentDisposition_enum.Attachment;
					attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;
					attachmentEntity.ContentDisposition_FileName = Core.GetFileNameFromPath(fileName);
					attachmentEntity.DataFromFile(fileName);
				}
			}

			return m;
		}

		#endregion


		#region method ToStringData

		/// <summary>
		/// Stores mime message to string.
		/// </summary>
		/// <returns></returns>
		public string ToStringData()
		{
			return System.Text.Encoding.Default.GetString(this.ToByteData());
		}

		#endregion

		#region method ToByteData

		/// <summary>
		/// Stores mime message to byte[].
		/// </summary>
		/// <returns></returns>
		public byte[] ToByteData()
		{
			using(MemoryStream ms = new MemoryStream()){
				ToStream(ms);

				return ms.ToArray();
			}
		}

		#endregion

		#region method ToFile

		/// <summary>
		/// Stores mime message to specified file.
		/// </summary>
		/// <param name="fileName">File name.</param>
		public void ToFile(string fileName)
		{
			using(FileStream fs = File.Create(fileName)){
				ToStream(fs);
			}
		}

		#endregion

		#region method ToStream

		/// <summary>
		/// Stores mime message to specified stream. Stream position stays where mime writing ends.
		/// </summary>
		/// <param name="storeStream">Stream where to store mime message.</param>
		public void ToStream(Stream storeStream)
		{
			m_pMainEntity.ToStream(storeStream);
		}

		#endregion


		#region method GetEntities

		/// <summary>
		/// Gets mime entities, including nested entries. 
		/// </summary>
		/// <param name="entities"></param>
		/// <param name="allEntries"></param>
		private void GetEntities(MimeEntityCollection entities,List<MimeEntity> allEntries)
		{				
			if(entities != null){
				foreach(MimeEntity ent in entities){
					allEntries.Add(ent);

					// Add child entities, if any
					if(ent.ChildEntities.Count > 0){
						GetEntities(ent.ChildEntities,allEntries);
					}
				}
			}
		}

		#endregion


		#region Properties Implementaion

		/// <summary>
		/// Message main(top-level) entity.
		/// </summary>
		public MimeEntity MainEntity
		{
			get{ return m_pMainEntity; }
		}

		/// <summary>
		/// Gets all mime entities contained in message, including child entities.
		/// </summary>
		public MimeEntity[] MimeEntities
		{
			get{ 
				List<MimeEntity> allEntities = new List<MimeEntity>();
				allEntities.Add(m_pMainEntity);
				GetEntities(m_pMainEntity.ChildEntities,allEntities);

				return allEntities.ToArray(); 
			}
		}
		
		/// <summary>
		/// Gets attachment entities. Entity is considered as attachmnet if:<p/>
        ///     *) Content-Disposition: attachment (RFC 2822 message)<p/>
        ///     *) Content-Disposition: filename = "" is specified  (RFC 2822 message)<p/>
        ///     *) Content-Type: name = "" is specified  (old RFC 822 message)<p/>
		/// </summary>
		public MimeEntity[] Attachments
		{
			get{                
                List<MimeEntity> attachments = new List<MimeEntity>();
				MimeEntity[] entities = this.MimeEntities;
				foreach(MimeEntity entity in entities){
                    if(entity.ContentDisposition == ContentDisposition_enum.Attachment){
                        attachments.Add(entity);
                    }
                    else if(entity.ContentType_Name != null){
                        attachments.Add(entity);
                    }
                    else if(entity.ContentDisposition_FileName != null){
                        attachments.Add(entity);
                    }
				}

                return attachments.ToArray();
			}
		}
			
		/// <summary>
		/// Gets message body text. Returns null if no body text specified.
		/// </summary>
		public string BodyText
		{
			get{
                /* RFC 2045 5.2 
                    If content Content-Type: header field is missing, then it defaults to:
                        Content-type: text/plain; charset=us-ascii
                */

				if(this.MainEntity.ContentType == MediaType_enum.NotSpecified){
					if(this.MainEntity.DataEncoded != null){
						return System.Text.Encoding.ASCII.GetString(this.MainEntity.Data);
					}
				}
				else{
					MimeEntity[] entities = this.MimeEntities;
					foreach(MimeEntity entity in entities){
						if(entity.ContentType == MediaType_enum.Text_plain){
							return entity.DataText;
						}
					}
				}

				return null;
			}
		}
/*
		/// <summary>
		/// Gets body text mime entity. Returns null if no body body text entity.
		/// </summary>
		public MimeEntity BodyTextEntity
		{
			get{
				if(this.MainEntity.ContentType == MediaType_enum.NotSpecified){
					if(this.MainEntity.DataEncoded != null){
						return this.MainEntity;
					}
				}
				else{
					MimeEntity[] entities = this.MimeEntities;
					foreach(MimeEntity entity in entities){
						if(entity.ContentType == MediaType_enum.Text_plain){
							return entity;
						}
					}
				}

				return null;
			}
		}
*/
		/// <summary>
		/// Gets message body html. Returns null if no body html text specified.
		/// </summary>
		public string BodyHtml
		{
			get{
				MimeEntity[] entities = this.MimeEntities;
				foreach(MimeEntity entity in entities){
					if(entity.ContentType == MediaType_enum.Text_html){
						return entity.DataText;
					}
				}

				return null;
			}
		}
		
		#endregion

	}
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


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

Comments and Discussions