Rfc 2822 Mime Entity.
예제 #1
0
		/// <summary>
		/// Creates a new mime entity to the end of the collection.
		/// </summary>
		/// <returns></returns>
		public MimeEntity Add()
		{
			MimeEntity entity = new MimeEntity();
			Add(entity);

			return entity;
		}
예제 #2
0
		/// <summary>
		/// Inserts a new mime entity into the collection at the specified location.
		/// </summary>
		/// <param name="index">The location in the collection where you want to add the mime entity.</param>
		/// <param name="entity">Mime entity.</param>
		public void Insert(int index,MimeEntity entity)
		{
			// Allow to add only for multipart/xxx...
			if((m_pOwnerEntity.ContentType & MediaType_enum.Multipart) == 0){
				throw new Exception("You don't have Content-Type: multipart/xxx. Only Content-Type: multipart/xxx can have nested mime entities !");
			}
			// Check boundary, this is required parameter for multipart/xx
			if(m_pOwnerEntity.ContentType_Boundary == null || m_pOwnerEntity.ContentType_Boundary.Length == 0){
				throw new Exception("Please specify Boundary property first !");
			}

			m_pEntities.Insert(index,entity);
		}
예제 #3
0
		/// <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";
		}
예제 #4
0
		/// <summary>
		/// Parses mime entity from stream.
		/// </summary>
		/// <param name="stream">Data stream from where to read data.</param>
		/// <param name="toBoundary">Entity data is readed to specified boundary.</param>
		/// <returns>Returns false if last entity. Returns true for mulipart entity, if there are more entities.</returns>
		internal bool Parse(SmartStream stream,string toBoundary)
		{
			// Clear header fields
			m_pHeader.Clear();
			m_pHeaderFieldCache.Clear();

			// Parse header
			m_pHeader.Parse(stream);

			// Parse entity and child entities if any (Conent-Type: multipart/xxx...)
            
			// Multipart entity
			if((this.ContentType & MediaType_enum.Multipart) != 0){
				// There must be be boundary ID (rfc 1341 7.2.1  The Content-Type field for multipart entities requires one parameter,
                // "boundary", which is used to specify the encapsulation boundary.)
				string boundaryID = this.ContentType_Boundary;
				if(boundaryID == null){
					// This is invalid message, just skip this mime entity
				}
				else{
					// There is one or more mime entities

                    // Find first boundary start position
                    SmartStream.ReadLineAsyncOP args = new SmartStream.ReadLineAsyncOP(new byte[8000],SizeExceededAction.JunkAndThrowException);
                    stream.ReadLine(args,false);
                    if(args.Error != null){
                        throw args.Error;
                    }
                    string lineString = args.LineUtf8;
				
					while(lineString != null){
						if(lineString.StartsWith("--" + boundaryID)){
							break;
						}
						
                        stream.ReadLine(args,false);
                        if(args.Error != null){
                            throw args.Error;
                        }
                        lineString = args.LineUtf8;
					}
					// This is invalid entity, boundary start not found. Skip that entity.
					if(string.IsNullOrEmpty(lineString)){
						return false;
					}
					
					// Start parsing child entities of this entity
					while(true){					
						// Parse and add child entity
						MimeEntity childEntity = new MimeEntity();					
						this.ChildEntities.Add(childEntity);
				
						// This is last entity, stop parsing
						if(childEntity.Parse(stream,boundaryID) == false){
							break;
						}
						// else{
						// There are more entities, parse them
					}
					
					// This entity is child of mulipart entity.
					// All this entity child entities are parsed,
					// we need to move stream position to next entity start.
					if(!string.IsNullOrEmpty(toBoundary)){
                        stream.ReadLine(args,false);
                        if(args.Error != null){
                            throw args.Error;
                        }
                        lineString = args.LineUtf8;

						while(lineString != null){
							if(lineString.StartsWith("--" + toBoundary)){
								break;
							}
							
							stream.ReadLine(args,false);
                            if(args.Error != null){
                                throw args.Error;
                            }
                            lineString = args.LineUtf8;
						}
						
						// Invalid boundary end, there can't be more entities 
						if(string.IsNullOrEmpty(lineString)){
							return false;
						}
					
						// See if last boundary or there is more. Last boundary ends with --
						if(lineString.EndsWith(toBoundary + "--")){
							return false; 
						}
						// else{
						// There are more entities					
						return true;
					}
				}
			}
			// Singlepart entity.
			else{
                // Boundary is specified, read data to specified boundary.
                if(!string.IsNullOrEmpty(toBoundary)){
                    MemoryStream entityData = new MemoryStream();
                    SmartStream.ReadLineAsyncOP readLineOP = new SmartStream.ReadLineAsyncOP(new byte[32000],SizeExceededAction.JunkAndThrowException);

                    // Read entity data while get boundary end tag --boundaryID-- or EOS.
                    while(true){                        
                        stream.ReadLine(readLineOP,false);
                        if(readLineOP.Error != null){
                            throw readLineOP.Error;
                        }
                        // End of stream reached. Normally we should get boundary end tag --boundaryID--, but some x mailers won't add it, so
                        // if we reach EOS, consider boundary closed.
                        if(readLineOP.BytesInBuffer == 0){
                            // Just return data what was readed.
                            m_EncodedData = entityData.ToArray();
                            return false;
                        }
                        // We readed a line.
                        else{
                            // We have boundary start/end tag or just "--" at the beginning of line.
                            if(readLineOP.LineBytesInBuffer >= 2 && readLineOP.Buffer[0] == '-' && readLineOP.Buffer[1] == '-'){
                                string lineString = readLineOP.LineUtf8;
                                // We have boundary end tag, no more boundaries.
                                if(lineString == "--" + toBoundary + "--"){
                                    m_EncodedData = entityData.ToArray();
                                    return false;
                                }
                                // We have new boundary start.
                                else if(lineString == "--" + toBoundary){
                                    m_EncodedData = entityData.ToArray();
                                    return true;
                                }
                                else{
                                    // Just skip
                                }
                            }

                            // Write readed line.
                            entityData.Write(readLineOP.Buffer,0,readLineOP.BytesInBuffer);                    
                        }
                    }
                }
				// Boundary isn't specified, read data to the stream end. 
				else{
                    MemoryStream ms = new MemoryStream();
                    stream.ReadAll(ms);
                    m_EncodedData = ms.ToArray();
				}
			}
			
			return false;
		}
 /// <summary>
 /// Gets specified mime entity header.
 /// Note: Header terminator blank line is included.
 /// </summary>
 /// <param name="entity">Mime entity.</param>
 /// <returns></returns>
 public static byte[] GetMimeEntityHeader(MimeEntity entity)
 {
     return System.Text.Encoding.ASCII.GetBytes(entity.HeaderString + "\r\n");
 }
 /// <summary>
 /// Returns header fields lines except requested.
 /// Note: Header terminator blank line is included.
 /// </summary>
 /// <param name="fieldsStr">Header fields to skip.</param>
 /// <param name="entity">Entity which header field lines to get.</param>
 /// <returns></returns>
 public static byte[] ParseHeaderFieldsNot(string fieldsStr,MimeEntity entity)
 {
     return ParseHeaderFieldsNot(fieldsStr,System.Text.Encoding.Default.GetBytes(entity.HeaderString));
 }
예제 #7
0
		/// <summary>
		/// Default constructor.
		/// </summary>
		/// <param name="ownerEntity">Mime entity what owns this collection.</param>
		internal MimeEntityCollection(MimeEntity ownerEntity)
		{
			m_pOwnerEntity = ownerEntity;

			m_pEntities = new List<MimeEntity>();
		}
예제 #8
0
		/// <summary>
		/// Removes specified mime entity from the collection.
		/// </summary>
		/// <param name="entity">Mime entity to remove.</param>
		public void Remove(MimeEntity entity)
		{
			m_pEntities.Remove(entity);
		}
예제 #9
0
		/// <summary>
		/// Gets if collection contains specified mime entity.
		/// </summary>
		/// <param name="entity">Mime entity.</param>
		/// <returns></returns>
		public bool Contains(MimeEntity entity)
		{
			return m_pEntities.Contains(entity);
		}
        /// <summary>
        /// Construct secified mime entity ENVELOPE string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <returns></returns>
        public static string ConstructEnvelope(MimeEntity entity)
        {
            /* RFC 3501 7.4.2
                ENVELOPE
                    A parenthesized list that describes the envelope structure of a
                    message.  This is computed by the server by parsing the
                    [RFC-2822] header into the component parts, defaulting various
                    fields as necessary.

                    The fields of the envelope structure are in the following
                    order: date, subject, from, sender, reply-to, to, cc, bcc,
                    in-reply-to, and message-id.  The date, subject, in-reply-to,
                    and message-id fields are strings.  The from, sender, reply-to,
                    to, cc, and bcc fields are parenthesized lists of address
                    structures.

                    An address structure is a parenthesized list that describes an
                    electronic mail address.  The fields of an address structure
                    are in the following order: personal name, [SMTP]
                    at-domain-list (source route), mailbox name, and host name.

                    [RFC-2822] group syntax is indicated by a special form of
                    address structure in which the host name field is NIL.  If the
                    mailbox name field is also NIL, this is an end of group marker
                    (semi-colon in RFC 822 syntax).  If the mailbox name field is
                    non-NIL, this is a start of group marker, and the mailbox name
                    field holds the group name phrase.

                    If the Date, Subject, In-Reply-To, and Message-ID header lines
                    are absent in the [RFC-2822] header, the corresponding member
                    of the envelope is NIL; if these header lines are present but
                    empty the corresponding member of the envelope is the empty
                    string.

                        Note: some servers may return a NIL envelope member in the
                        "present but empty" case.  Clients SHOULD treat NIL and
                        empty string as identical.

                        Note: [RFC-2822] requires that all messages have a valid
                        Date header.  Therefore, the date member in the envelope can
                        not be NIL or the empty string.

                        Note: [RFC-2822] requires that the In-Reply-To and
                        Message-ID headers, if present, have non-empty content.
                        Therefore, the in-reply-to and message-id members in the
                        envelope can not be the empty string.

                    If the From, To, cc, and bcc header lines are absent in the
                    [RFC-2822] header, or are present but empty, the corresponding
                    member of the envelope is NIL.

                    If the Sender or Reply-To lines are absent in the [RFC-2822]
                    header, or are present but empty, the server sets the
                    corresponding member of the envelope to be the same value as
                    the from member (the client is not expected to know to do
                    this).

                        Note: [RFC-2822] requires that all messages have a valid
                        From header.  Therefore, the from, sender, and reply-to
                        members in the envelope can not be NIL.

                    ENVELOPE ("date" "subject" from sender reply-to to cc bcc "in-reply-to" "messageID")
            */

            // NOTE: all header fields and parameters must in ENCODED form !!!

            StringBuilder retVal = new StringBuilder();
            retVal.Append("(");

            // date
            if(entity.Header.Contains("Date:")){
                retVal.Append(TextUtils.QuoteString(MimeUtils.DateTimeToRfc2822(entity.Date)));
            }
            else{
                retVal.Append("NIL");
            }

            // subject
            if(entity.Subject != null){
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.Subject)));
            }
            else{
                retVal.Append(" NIL");
            }

            // from
            if(entity.From != null && entity.From.Count > 0){
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else{
                retVal.Append(" NIL");
            }

            // sender
            //	NOTE: There is confusing part, according rfc 2822 Sender: is MailboxAddress and not AddressList.
            if(entity.Sender != null){
                retVal.Append(" (");

                retVal.Append(ConstructAddress(entity.Sender));

                retVal.Append(")");
            }
            else if(entity.From != null){
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else{
                retVal.Append(" NIL");
            }

            // reply-to
            if(entity.ReplyTo != null){
                retVal.Append(" " + ConstructAddresses(entity.ReplyTo));
            }
            else if(entity.From != null){
                retVal.Append(" " + ConstructAddresses(entity.From));
            }
            else{
                retVal.Append(" NIL");
            }

            // to
            if(entity.To != null && entity.To.Count > 0){
                retVal.Append(" " + ConstructAddresses(entity.To));
            }
            else{
                retVal.Append(" NIL");
            }

            // cc
            if(entity.Cc != null && entity.Cc.Count > 0){
                retVal.Append(" " + ConstructAddresses(entity.Cc));
            }
            else{
                retVal.Append(" NIL");
            }

            // bcc
            if(entity.Bcc != null && entity.Bcc.Count > 0){
                retVal.Append(" " + ConstructAddresses(entity.Bcc));
            }
            else{
                retVal.Append(" NIL");
            }

            // in-reply-to
            if(entity.InReplyTo != null){
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.InReplyTo)));
            }
            else{
                retVal.Append(" NIL");
            }

            // message-id
            if(entity.MessageID != null){
                retVal.Append(" " + TextUtils.QuoteString(MimeUtils.EncodeHeaderField(entity.MessageID)));
            }
            else{
                retVal.Append(" NIL");
            }

            retVal.Append(")");

            return retVal.ToString();
        }
        /// <summary>
        /// Constructs specified entity and it's childentities bodystructure string.
        /// </summary>
        /// <param name="entity">Mime entity.</param>
        /// <param name="bodystructure">Specifies if to construct BODY or BODYSTRUCTURE.</param>
        /// <returns></returns>
        private static string ConstructParts(MimeEntity entity,bool bodystructure)
        {
            /* RFC 3501 7.4.2 BODYSTRUCTURE
                              BODY A form of BODYSTRUCTURE without extension data.

                A parenthesized list that describes the [MIME-IMB] body
                structure of a message.  This is computed by the server by
                parsing the [MIME-IMB] header fields, defaulting various fields
                as necessary.

                For example, a simple text message of 48 lines and 2279 octets
                can have a body structure of: ("TEXT" "PLAIN" ("CHARSET"
                "US-ASCII") NIL NIL "7BIT" 2279 48)

                Multiple parts are indicated by parenthesis nesting.  Instead
                of a body type as the first element of the parenthesized list,
                there is a sequence of one or more nested body structures.  The
                second element of the parenthesized list is the multipart
                subtype (mixed, digest, parallel, alternative, etc.).

                For example, a two part message consisting of a text and a
                BASE64-encoded text attachment can have a body structure of:
                (("TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152
                23)("TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff")
                "<*****@*****.**>" "Compiler diff"
                "BASE64" 4554 73) "MIXED")

                Extension data follows the multipart subtype.  Extension data
                is never returned with the BODY fetch, but can be returned with
                a BODYSTRUCTURE fetch.  Extension data, if present, MUST be in
                the defined order.  The extension data of a multipart body part
                are in the following order:

                body parameter parenthesized list
                    A parenthesized list of attribute/value pairs [e.g., ("foo"
                    "bar" "baz" "rag") where "bar" is the value of "foo", and
                    "rag" is the value of "baz"] as defined in [MIME-IMB].

                body disposition
                    A parenthesized list, consisting of a disposition type
                    string, followed by a parenthesized list of disposition
                    attribute/value pairs as defined in [DISPOSITION].

                body language
                    A string or parenthesized list giving the body language
                    value as defined in [LANGUAGE-TAGS].

                body location
                    A string list giving the body content URI as defined in [LOCATION].

                Any following extension data are not yet defined in this
                version of the protocol.  Such extension data can consist of
                zero or more NILs, strings, numbers, or potentially nested
                parenthesized lists of such data.  Client implementations that
                do a BODYSTRUCTURE fetch MUST be prepared to accept such
                extension data.  Server implementations MUST NOT send such
                extension data until it has been defined by a revision of this
                protocol.

                The basic fields of a non-multipart body part are in the
                following order:

                body type
                    A string giving the content media type name as defined in [MIME-IMB].

                body subtype
                     A string giving the content subtype name as defined in [MIME-IMB].

                body parameter parenthesized list
                    A parenthesized list of attribute/value pairs [e.g., ("foo"
                    "bar" "baz" "rag") where "bar" is the value of "foo" and
                    "rag" is the value of "baz"] as defined in [MIME-IMB].

                body id
                    A string giving the content id as defined in [MIME-IMB].

                body description
                    A string giving the content description as defined in [MIME-IMB].

                body encoding
                    A string giving the content transfer encoding as defined in	[MIME-IMB].

                body size
                    A number giving the size of the body in octets.  Note that
                    this size is the size in its transfer encoding and not the
                    resulting size after any decoding.

                A body type of type MESSAGE and subtype RFC822 contains,
                immediately after the basic fields, the envelope structure,
                body structure, and size in text lines of the encapsulated
                message.

                A body type of type TEXT contains, immediately after the basic
                fields, the size of the body in text lines.  Note that this
                size is the size in its content transfer encoding and not the
                resulting size after any decoding.

                Extension data follows the basic fields and the type-specific
                fields listed above.  Extension data is never returned with the
                BODY fetch, but can be returned with a BODYSTRUCTURE fetch.
                Extension data, if present, MUST be in the defined order.

                The extension data of a non-multipart body part are in the
                following order:

                body MD5
                    A string giving the body MD5 value as defined in [MD5].

                body disposition
                    A parenthesized list with the same content and function as
                    the body disposition for a multipart body part.

                body language
                    A string or parenthesized list giving the body language
                    value as defined in [LANGUAGE-TAGS].

                body location
                    A string list giving the body content URI as defined in [LOCATION].

                Any following extension data are not yet defined in this
                version of the protocol, and would be as described above under
                multipart extension data.

                // We don't construct extention fields like rfc says:
                    Server implementations MUST NOT send such
                    extension data until it has been defined by a revision of this
                    protocol.

                contentTypeMainMediaType - Example: 'TEXT'
                contentTypeSubMediaType  - Example: 'PLAIN'
                conentTypeParameters     - Example: '("CHARSET" "iso-8859-1" ...)'
                contentID                - Content-ID: header field value.
                contentDescription       - Content-Description: header field value.
                contentEncoding          - Content-Transfer-Encoding: header field value.
                contentSize              - mimeEntity ENCODED data size
                [envelope]               - NOTE: included only if contentType = "message" !!!
                [contentLines]           - number of ENCODED data lines. NOTE: included only if contentType = "text" !!!

                // Basic fields for multipart
                (nestedMimeEntries) contentTypeSubMediaType

                // Basic fields for non-multipart
                contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine]

            */

            StringBuilder retVal = new StringBuilder();
            // Multipart message
            if((entity.ContentType & MediaType_enum.Multipart) != 0){
                retVal.Append("(");

                // Construct child entities.
                foreach(MimeEntity childEntity in entity.ChildEntities){
                    // Construct child entity. This can be multipart or non multipart.
                    retVal.Append(ConstructParts(childEntity,bodystructure));
                }

                // Add contentTypeSubMediaType
                string contentType = entity.ContentTypeString.Split(';')[0];
                if(contentType.Split('/').Length == 2){
                    retVal.Append(" \"" + contentType.Split('/')[1].Replace(";","") + "\"");
                }
                else{
                    retVal.Append(" NIL");
                }

                retVal.Append(")");
            }
            // Single part message
            else{
                retVal.Append("(");

                // NOTE: all header fields and parameters must in ENCODED form !!!

                // Add contentTypeMainMediaType
                if(entity.ContentTypeString != null){
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if(contentType.Split('/').Length == 2){
                        retVal.Append("\"" + entity.ContentTypeString.Split('/')[0] + "\"");
                    }
                    else{
                        retVal.Append(" NIL");
                    }
                }
                else{
                    retVal.Append(" NIL");
                }

                // contentTypeSubMediaType
                if(entity.ContentTypeString != null){
                    string contentType = entity.ContentTypeString.Split(';')[0];
                    if(contentType.Split('/').Length == 2){
                        retVal.Append(" \"" + contentType.Split('/')[1].Replace(";","") + "\"");
                    }
                    else{
                        retVal.Append(" NIL");
                    }
                }
                else{
                    retVal.Append(" NIL");
                }

                // conentTypeParameters - Syntax: {("name" SP "value" *(SP "name" SP "value"))}
                if(entity.ContentTypeString != null){
                    ParametizedHeaderField contentTypeParameters = new ParametizedHeaderField(entity.Header.GetFirst("Content-Type:"));
                    if(contentTypeParameters.Parameters.Count > 0){
                        retVal.Append(" (");

                        bool first = true;
                        foreach(HeaderFieldParameter param in contentTypeParameters.Parameters){
                            // For first item, don't add SP
                            if(!first){
                                retVal.Append(" ");
                            }
                            else{
                                // Clear first flag
                                first = false;
                            }

                            retVal.Append("\"" + param.Name + "\" \"" + MimeUtils.EncodeHeaderField(param.Value) + "\"");
                        }

                        retVal.Append(")");
                    }
                    else{
                        retVal.Append(" NIL");
                    }
                }
                else{
                    retVal.Append(" NIL");
                }

                // contentID
                string contentID = entity.ContentID;
                if(contentID != null){
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentID) + "\"");
                }
                else{
                    retVal.Append(" NIL");
                }

                // contentDescription
                string contentDescription = entity.ContentDescription;
                if(contentDescription != null){
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentDescription) + "\"");
                }
                else{
                    retVal.Append(" NIL");
                }

                // contentEncoding
                HeaderField contentEncoding = entity.Header.GetFirst("Content-Transfer-Encoding:");
                if(contentEncoding != null){
                    retVal.Append(" \"" + MimeUtils.EncodeHeaderField(contentEncoding.Value) + "\"");
                }
                else{
                    // If not specified, then must be 7bit.
                    retVal.Append(" \"7bit\"");
                }

                // contentSize
                if(entity.DataEncoded != null){
                    retVal.Append(" " + entity.DataEncoded.Length.ToString());
                }
                else{
                    retVal.Append(" 0");
                }

                // envelope ---> FOR ContentType: message/rfc822 ONLY ###
                if((entity.ContentType & MediaType_enum.Message_rfc822) != 0){
                    retVal.Append(" " + IMAP_Envelope.ConstructEnvelope(entity));

                    // TODO: BODYSTRUCTURE,LINES
                }

                // contentLines ---> FOR ContentType: text/xxx ONLY ###
                if((entity.ContentType & MediaType_enum.Text) != 0){
                    if(entity.DataEncoded != null){
                        long lineCount = 0;
                        StreamLineReader r = new StreamLineReader(new MemoryStream(entity.DataEncoded));
                        byte[] line = r.ReadLine();
                        while(line != null){
                            lineCount++;

                            line = r.ReadLine();
                        }

                        retVal.Append(" " + lineCount.ToString());
                    }
                    else{
                        retVal.Append(" 0");
                    }
                }

                retVal.Append(")");
            }

            return retVal.ToString();
        }
예제 #12
0
        private static string ConstructSinglePart(MimeEntity ent,bool bodystructure)
        {
            string str =  "(";

            // contentType
            str += "\"" + ent.ContentTypeString.Split('/')[0] + "\" ";

            // conentSubType
            string contentType = ent.ContentTypeString.Split(';')[0];
            if(contentType.Split('/').Length == 2){
                str += "\"" + contentType.Split('/')[1].Replace(";","") + "\" ";
            }
            else{
                str += "NIL ";
            }

            // conentTypeSubFields
            string longContentType = ent.ContentTypeString;
            if(longContentType.IndexOf(";") > -1){
                str += "(";
                string[] fields = longContentType.Split(';');
                for(int i=1;i<fields.Length;i++){
                    string[] nameValue = fields[i].Replace("\"","").Trim().Split(new char[]{'='},2);

                    str += "\"" + nameValue[0] + "\" \"" + nameValue[1] + "\"";

                    if(i < fields.Length - 1){
                        str += " ";
                    }
                }
                str += ") ";
            }
            else{
                // if content is attachment and content type name field is missing, use filename for it
                string fileName = ent.ContentDisposition_FileName;
                if(fileName != null){
                    str += "(\"name\" \"" + fileName + "\") ";
                }
                else{
                    str += "NIL ";
                }
            }

            // contentID
            string contentID = ent.ContentID;
            if(contentID != null){
                str += "\"" + contentID + "\" ";
            }
            else{
                str += "NIL ";
            }

            // contentDescription
            string contentDescription = ent.ContentDescription;
            if(contentDescription != null){
                str += "\"" + contentDescription + "\" ";
            }
            else{
                str += "NIL ";
            }

            // contentEncoding
            if(ent.Header.GetFirst("Content-Transfer-Encoding:") != null){
                str += "\"" + ent.Header.GetFirst("Content-Transfer-Encoding:").Value + "\" ";
            }
            else{
                str += "NIL ";
            }

            // contentSize
            str += ent.DataEncoded.Length + " ";

            // envelope NOTE: included only if contentType = "message" !!!

            // contentLines NOTE: included only if contentType = "text" !!!
            if((ent.ContentType & MediaType_enum.Text) != 0){
                StreamLineReader r = new StreamLineReader(new MemoryStream(ent.DataEncoded));
                int nLines = 0;
                byte[] line = new byte[0];
                while(line != null){
                    line = r.ReadLine();
                    nLines++;
                }
                str += nLines;
            }

            // Need to add extended fields
            if(bodystructure){
                str += " ";

                // md5
                str += "NIL ";

                // contentDisposition
                if(ent.Header.GetFirst("Content-Disposition:") != null){
                    string contDispos = ent.Header.GetFirst("Content-Disposition:").Value;

                    str += "(";

                    string[] fields = contDispos.Split(';');

                    str += "\"" + fields[0] + "\" ";

                    if(fields.Length > 1){
                        str += "(";
                        for(int i=1;i<fields.Length;i++){
                            string[] nameValue = fields[i].Replace("\"","").Trim().Split(new char[]{'='},2);

                            str += "\"" + nameValue[0] + "\" \"" + nameValue[1] + "\"";

                            if(i < fields.Length - 1){
                                str += " ";
                            }
                        }
                        str += ")";
                    }
                    else{
                        str += "NIL";
                    }

                    str += ") ";
                }
                else{
                    str += "NIL ";
                }

                // contentLanguage
                str += "NIL";
            }

            str += ")";

            return str;
        }
예제 #13
0
        private static string ConstructMultiPart(MimeEntity ent,bool bodystructure)
        {
            string str = "(";

            str += ConstructParts(ent.ChildEntities,bodystructure);

            str += " ";

            // conentSubType
            string contentType = ent.ContentTypeString.Split(';')[0];
            if(contentType.Split('/').Length == 2){
                str += "\"" + contentType.Split('/')[1].Replace(";","") + "\"";
            }
            else{
                str += "NIL";
            }

            // Need to add extended fields
            if(bodystructure){
                str += " ";

                // conentTypeSubFields
                string longContentType = ent.ContentTypeString;
                if(longContentType.IndexOf(";") > -1){
                    str += "(";
                    string[] fields = longContentType.Split(';');
                    for(int i=1;i<fields.Length;i++){
                        string[] nameValue = fields[i].Replace("\"","").Trim().Split(new char[]{'='},2);

                        str += "\"" + nameValue[0] + "\" \"" + nameValue[1] + "\"";

                        if(i < fields.Length - 1){
                            str += " ";
                        }
                    }
                    str += ") ";
                }

                // contentDisposition
                str += "NIL ";

                // contentLanguage
                str += "NIL";
            }

            str += ")";

            return str;
        }
예제 #14
0
        /// <summary>
        /// Parses mime entity from stream.
        /// </summary>
        /// <param name="stream">Data stream from where to read data.</param>
        /// <param name="toBoundary">Entity data is readed to specified boundary.</param>
        /// <returns>Returns false if last entity. Returns true for mulipart entity, if there are more entities.</returns>
        internal bool Parse(Stream stream,String toBoundary)
        {
            // Clear header fields
            m_pHeader.Clear();
            m_pHeaderFieldCache.Clear();

            // Parse header
            m_pHeader.Parse(stream);

            // Parse entity and child entities if any (Conent-Type: multipart/xxx...)

            // Multipart entity
            if((this.ContentType & MediaType_enum.Multipart) != 0){
                // There must be be boundary ID (rfc 1341 7.2.1  The Content-Type field for multipart entities requires one parameter, "boundary", which is used to specify the encapsulation boundary.)
                String boundaryID = this.ContentType_Boundary;
                if(boundaryID == null){
                    // This is invalid message, just skip this mime entity
                }
                else{
                    // There is one or more mime entities

                    // Find first boundary start position
                    StreamLineReader reader = new StreamLineReader(stream);
                    byte[] lineData = reader.ReadLine();
                    while(lineData != null){
                        string line = System.Text.Encoding.Default.GetString(lineData);
                        if(line.StartsWith("--" + boundaryID)){
                            break;
                        }

                        lineData = reader.ReadLine();
                    }
                    // This is invalid entity, boundary start not found. Skip that entity.
                    if(lineData == null){
                        return false;
                    }

                    // Start parsing child entities ot this entity
                    while(true){
                        // Parse and add child entity
                        MimeEntity childEntity = new MimeEntity();
                        this.ChildEntities.Add(childEntity);

                        // This is last entity, stop parsing
                        if(childEntity.Parse(stream,boundaryID) == false){
                            break;
                        }
                        // else{
                        // There are more entities, parse them
                    }

                    // This entity is child of mulipart entity.
                    // All this entity child entities are parsed,
                    // we need to move stream position to next entity start.
                    if(toBoundary != null && toBoundary.Length > 0){
                        lineData = reader.ReadLine();
                        while(lineData != null){
                            String line = System.Text.Encoding.Default.GetString(lineData);
                            if(line.StartsWith("--" + toBoundary)){
                                break;
                            }

                            lineData = reader.ReadLine();
                        }

                        // Invalid boundary end, there can't be more entities
                        if(lineData == null){
                            return false;
                        }

                        // This was last entity
                        if(System.Text.Encoding.Default.GetString(lineData).EndsWith("--")){
                            return false;
                        }
                        // else{
                        // There are more entities
                        return true;
                    }
                }
            }
            // Singlepart entity
            else{
                // Boundary is specified, read data to specified boundary.
                if(toBoundary != null && toBoundary.Length > 0){
                    MemoryStream entityData = new MemoryStream();
                    StreamLineReader reader = new StreamLineReader(stream);
                    byte[] lineData = reader.ReadLine();
                    while(lineData != null){
                        String line = System.Text.Encoding.Default.GetString(lineData);
                        if(line.StartsWith("--" + toBoundary)){
                            break;
                        }

                        // Write line to buffer
                        entityData.Write(lineData,0,lineData.Length);
                        entityData.Write(new byte[]{(byte)'\r',(byte)'\n'},0,2);

                        lineData = reader.ReadLine();
                    }

                    // This is invalid entity, unexpected end of entity. Skip that entity.
                    if(lineData == null){
                        if(this.ParentEntity != null){
                            this.ParentEntity.ChildEntities.Remove(this);
                        }
                        return false;
                    }

                    m_EncodedData = entityData.ToArray();

                    // See if last boundary or there is more. Last boundary ends with --
                    if(System.Text.Encoding.Default.GetString(lineData).EndsWith("--")){
                        return false;
                    }

                    return true;
                }
                // Boundary isn't specified, read data to the stream end.
                else{
                    m_EncodedData = new byte[stream.Length];
                    stream.Read(m_EncodedData,0,m_EncodedData.Length);
                }
            }

            return false;
        }
예제 #15
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="ownerEntity">Mime entity what owns this collection.</param>
        internal MimeEntityCollection(MimeEntity ownerEntity)
        {
            m_pOwnerEntity = ownerEntity;

            m_pEntities = new ArrayList();
        }
 /// <summary>
 /// 调用lumisoft发送邮件
 /// </summary>
 /// <param name="fromEmailAddr">发送者的邮件地址</param>
 /// <param name="toEmailAddr">给谁发的邮件地址</param>
 /// <param name="subjectText">主题</param>
 /// <param name="bodyText">正文</param>
 /// <param name="filePath">附件路径</param>
 /// <returns>成功与否</returns>
 public static bool SendMailByLumisoft(string fromEmailAddr, string toEmailAddr, string subjectText, string bodyText, string filePath)
 {
     Mime m = new Mime();
     MimeEntity mainEntity = m.MainEntity;
     // Force to create From: header field
     mainEntity.From = new AddressList();
     mainEntity.From.Add(new MailboxAddress(fromEmailAddr, fromEmailAddr));
     // Force to create To: header field
     mainEntity.To = new AddressList();
     mainEntity.To.Add(new MailboxAddress(toEmailAddr, toEmailAddr));
     mainEntity.Subject = subjectText;
     //添加正文
     mainEntity.ContentType = MediaType_enum.Multipart_mixed;
     MimeEntity textEntity = mainEntity.ChildEntities.Add();
     textEntity.ContentType = MediaType_enum.Text_html;
     textEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;
     textEntity.DataText = bodyText;
     //发送附件
     if (!string.IsNullOrEmpty(filePath))
     {
         MimeEntity attachmentEntity = new MimeEntity();
         attachmentEntity.ContentType = MediaType_enum.Application_octet_stream;
         attachmentEntity.ContentDisposition = ContentDisposition_enum.Attachment;
         attachmentEntity.ContentTransferEncoding = ContentTransferEncoding_enum.Base64;
         attachmentEntity.ContentDisposition_FileName = filePath;
         attachmentEntity.DataFromFile(filePath);
         mainEntity.ChildEntities.Add(attachmentEntity);
     }
     try
     {
         SMTP_Client.QuickSend(m);
         return true;
     }
     catch (Exception e)
     {
         //Console.Write(e.StackTrace);
         return false;
     }
 }