/// <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(MIME_Entity 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] * */ MIME_Encoding_EncodedWord wordEncoder = new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B, Encoding.UTF8); wordEncoder.Split = false; StringBuilder retVal = new StringBuilder(); // Multipart message if (entity.Body is MIME_b_Multipart) { retVal.Append("("); // Construct child entities. foreach (MIME_Entity childEntity in ((MIME_b_Multipart)entity.Body).BodyParts) { // Construct child entity. This can be multipart or non multipart. retVal.Append(ConstructParts(childEntity, bodystructure)); } // Add contentTypeSubMediaType if (entity.ContentType != null && entity.ContentType.SubType != null) { retVal.Append(" \"" + entity.ContentType.SubType + "\""); } 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.ContentType != null && entity.ContentType.Type != null) { retVal.Append("\"" + entity.ContentType.Type + "\""); } else { retVal.Append("NIL"); } // Add contentTypeSubMediaType if (entity.ContentType != null && entity.ContentType.SubType != null) { retVal.Append(" \"" + entity.ContentType.SubType + "\""); } else { retVal.Append(" NIL"); } // conentTypeParameters - Syntax: {("name" SP "value" *(SP "name" SP "value"))} if (entity.ContentType != null) { if (entity.ContentType.Parameters.Count > 0) { retVal.Append(" ("); bool first = true; foreach (MIME_h_Parameter parameter in entity.ContentType.Parameters) { // For the first item, don't add SP. if (first) { first = false; } else { retVal.Append(" "); } retVal.Append("\"" + parameter.Name + "\" \"" + wordEncoder.Encode(parameter.Value) + "\""); } retVal.Append(")"); } else { retVal.Append(" NIL"); } } else { retVal.Append(" NIL"); } // contentID string contentID = entity.ContentID; if (contentID != null) { retVal.Append(" \"" + wordEncoder.Encode(contentID) + "\""); } else { retVal.Append(" NIL"); } // contentDescription string contentDescription = entity.ContentDescription; if (contentDescription != null) { retVal.Append(" \"" + wordEncoder.Encode(contentDescription) + "\""); } else { retVal.Append(" NIL"); } // contentEncoding if (entity.ContentTransferEncoding != null) { retVal.Append(" \"" + wordEncoder.Encode(entity.ContentTransferEncoding) + "\""); } else { // If not specified, then must be 7bit. retVal.Append(" \"7bit\""); } // contentSize if (entity.Body is MIME_b_SinglepartBase) { retVal.Append(" " + ((MIME_b_SinglepartBase)entity.Body).EncodedData.Length.ToString()); } else { retVal.Append(" 0"); } // envelope ---> FOR ContentType: message/rfc822 ONLY ### if (entity.Body is MIME_b_MessageRfc822) { retVal.Append(" " + IMAP_Envelope.ConstructEnvelope(((MIME_b_MessageRfc822)entity.Body).Message)); // TODO: BODYSTRUCTURE,LINES } // contentLines ---> FOR ContentType: text/xxx ONLY ### if (entity.Body is MIME_b_Text) { long lineCount = 0; StreamLineReader r = new StreamLineReader(new MemoryStream(((MIME_b_SinglepartBase)entity.Body).EncodedData)); byte[] line = r.ReadLine(); while (line != null) { lineCount++; line = r.ReadLine(); } retVal.Append(" " + lineCount.ToString()); } retVal.Append(")"); } return(retVal.ToString()); }
/// <summary> /// Loads user recyclebin messages to UI. /// </summary> private void LoadData() { try{ this.Cursor = Cursors.WaitCursor; m_pMessages.Items.Clear(); DataTable dtMessages = m_pVirtualServer.RecycleBin.GetMessagesInfo(m_pUser.UserName,m_pStartDate.Value.Date,m_pEndDate.Value.Date); foreach(DataRow dr in dtMessages.Rows){ string user = dr["User"].ToString(); DateTime deleteTime = Convert.ToDateTime(dr["DeleteTime"]).Date; IMAP_Envelope envelope = new IMAP_Envelope(); if(dr["Envelope"].ToString().Length > 0){ envelope.Parse(dr["Envelope"].ToString()); } ListViewItem it = new ListViewItem(dr["Folder"].ToString()); it.SubItems.Add(envelope.Subject); if(envelope.Sender != null && envelope.Sender.DisplayName != null && envelope.Sender.DisplayName != ""){ it.SubItems.Add(envelope.Sender.DisplayName); } else{ if(envelope.Sender != null){ it.SubItems.Add(envelope.Sender.EmailAddress); } else{ it.SubItems.Add("<none>"); } } it.SubItems.Add(envelope.Date.ToString()); it.SubItems.Add(Convert.ToDateTime(dr["DeleteTime"]).ToString()); it.SubItems.Add(((decimal)(Convert.ToDecimal(dr["Size"]) / 1000)).ToString("f2")); it.ImageIndex = 0; it.Tag = dr; m_pMessages.Items.Add(it); } mt_Info.Text = "User '" + m_pUser.UserName + "' Recyclebin messages (" + dtMessages.Rows.Count + ")"; } finally{ this.Cursor = Cursors.Default; } }
/// <summary> /// Parses entity and it's child entities. /// </summary> internal void Parse(string text) { StringReader r = new StringReader(text); r.ReadToFirstChar(); // If starts with ( then multipart/xxx, otherwise normal single part entity if (r.StartsWith("(")) { // Entities are (entity1)(entity2)(...) <SP> ContentTypeSubType while (r.StartsWith("(")) { IMAP_BODY_Entity entity = new IMAP_BODY_Entity(); entity.Parse(r.ReadParenthesized()); entity.m_pParentEntity = this; m_pChildEntities.Add(entity); r.ReadToFirstChar(); } // Read multipart values. (nestedMimeEntries) contentTypeSubMediaType string contentTypeSubMediaType = r.ReadWord(); m_pContentType = new MIME_h_ContentType("multipart/" + contentTypeSubMediaType); } else { // Basic fields for non-multipart // contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine] // Content-Type string contentTypeMainMediaType = r.ReadWord(); string contentTypeSubMediaType = r.ReadWord(); if (contentTypeMainMediaType.ToUpper() != "NIL" && contentTypeSubMediaType.ToUpper() != "NIL") { m_pContentType = new MIME_h_ContentType(contentTypeMainMediaType + "/" + contentTypeSubMediaType); } // Content-Type header field parameters // Parameters syntax: "name" <SP> "value" <SP> "name" <SP> "value" <SP> ... . r.ReadToFirstChar(); string conentTypeParameters = "NIL"; if (r.StartsWith("(")) { conentTypeParameters = r.ReadParenthesized(); StringReader contentTypeParamReader = new StringReader(conentTypeParameters); while (contentTypeParamReader.Available > 0) { string parameterName = contentTypeParamReader.ReadWord(); string parameterValue = MIME_Encoding_EncodedWord.DecodeS(contentTypeParamReader.ReadWord()); m_pContentType.Parameters[parameterName] = parameterValue; } } else { // Skip NIL r.ReadWord(); } // Content-ID: string contentID = r.ReadWord(); if (contentID.ToUpper() != "NIL") { m_ContentID = contentID; } // Content-Description: string contentDescription = r.ReadWord(); if (contentDescription.ToUpper() != "NIL") { m_ContentDescription = contentDescription; } // Content-Transfer-Encoding: string contentEncoding = r.ReadWord(); if (contentEncoding.ToUpper() != "NIL") { m_ContentEncoding = contentEncoding; } // Content Encoded data size in bytes string contentSize = r.ReadWord(); if (contentSize.ToUpper() != "NIL") { m_ContentSize = Convert.ToInt32(contentSize); } // Only for ContentType message/rfc822 if (string.Equals(this.ContentType.TypeWithSubype, MIME_MediaTypes.Message.rfc822, StringComparison.InvariantCultureIgnoreCase)) { r.ReadToFirstChar(); // envelope if (r.StartsWith("(")) { m_pEnvelope = new IMAP_Envelope(); m_pEnvelope.Parse(r.ReadParenthesized()); } else { // Skip NIL, ENVELOPE wasn't included r.ReadWord(); } // TODO: // BODYSTRUCTURE // contentLine } // Only for ContentType text/xxx if (contentTypeMainMediaType.ToLower() == "text") { // contentLine string contentLines = r.ReadWord(); if (contentLines.ToUpper() != "NIL") { m_ContentLines = Convert.ToInt32(contentLines); } } } }
private void m_pGet_Click(object sender, EventArgs e) { try{ this.Cursor = Cursors.WaitCursor; m_pMessages.Items.Clear(); foreach(DataRow dr in m_pVirtualServer.RecycleBin.GetMessagesInfo(m_pUser.Text,m_pSince.Value.Date,m_pTo.Value.Date).Rows){ string user = dr["User"].ToString(); DateTime deleteTime = Convert.ToDateTime(dr["DeleteTime"]).Date; IMAP_Envelope envelope = new IMAP_Envelope(); if(dr["Envelope"].ToString().Length > 0){ envelope.Parse(dr["Envelope"].ToString()); } ListViewItem it = new ListViewItem(user); it.SubItems.Add(dr["Folder"].ToString()); it.SubItems.Add(envelope.Subject); if(envelope.Sender != null && envelope.Sender.DisplayName != null && envelope.Sender.DisplayName != ""){ it.SubItems.Add(envelope.Sender.DisplayName); } else{ if(envelope.Sender != null){ it.SubItems.Add(envelope.Sender.EmailAddress); } else{ it.SubItems.Add("<none>"); } } it.SubItems.Add(envelope.Date.ToString()); it.SubItems.Add(Convert.ToDateTime(dr["DeleteTime"]).ToString()); it.SubItems.Add(((decimal)(Convert.ToDecimal(dr["Size"]) / 1000)).ToString("f2")); it.ImageIndex = 0; it.Tag = dr; m_pMessages.Items.Add(it); } } finally{ this.Cursor = Cursors.Default; } }
/// <summary> /// Parses entity and it's child entities. /// </summary> internal void Parse(string text) { StringReader r = new StringReader(text); r.ReadToFirstChar(); // If starts with ( then multipart/xxx, otherwise normal single part entity if(r.StartsWith("(")){ // Entities are (entity1)(entity2)(...) <SP> ContentTypeSubType while(r.StartsWith("(")){ IMAP_BODY_Entity entity = new IMAP_BODY_Entity(); entity.Parse(r.ReadParenthesized()); entity.m_pParentEntity = this; m_pChildEntities.Add(entity); r.ReadToFirstChar(); } // Read multipart values. (nestedMimeEntries) contentTypeSubMediaType string contentTypeSubMediaType = r.ReadWord(); m_pContentType = MimeUtils.ParseMediaType("multipart/" + contentTypeSubMediaType); } else{ // Basic fields for non-multipart // contentTypeMainMediaType contentTypeSubMediaType (conentTypeParameters) contentID contentDescription contentEncoding contentSize [envelope] [contentLine] // Content-Type string contentTypeMainMediaType = r.ReadWord(); string contentTypeSubMediaType = r.ReadWord(); if(contentTypeMainMediaType.ToUpper() != "NIL" && contentTypeSubMediaType.ToUpper() != "NIL"){ m_pContentType = MimeUtils.ParseMediaType(contentTypeMainMediaType + "/" + contentTypeSubMediaType); } // Content-Type header field parameters // Parameters syntax: "name" <SP> "value" <SP> "name" <SP> "value" <SP> ... . r.ReadToFirstChar(); string conentTypeParameters = "NIL"; if(r.StartsWith("(")){ conentTypeParameters = r.ReadParenthesized(); StringReader contentTypeParamReader = new StringReader(MimeUtils.DecodeWords(conentTypeParameters)); List<HeaderFieldParameter> parameters = new List<HeaderFieldParameter>(); while(contentTypeParamReader.Available > 0){ string parameterName = contentTypeParamReader.ReadWord(); string parameterValue = contentTypeParamReader.ReadWord(); parameters.Add(new HeaderFieldParameter(parameterName,parameterValue)); } m_pContentTypeParams = parameters.ToArray(); } else{ // Skip NIL r.ReadWord(); } // Content-ID: string contentID = r.ReadWord(); if(contentID.ToUpper() != "NIL"){ m_ContentID = contentID; } // Content-Description: string contentDescription = r.ReadWord(); if(contentDescription.ToUpper() != "NIL"){ m_ContentDescription = contentDescription; } // Content-Transfer-Encoding: string contentEncoding = r.ReadWord(); if(contentEncoding.ToUpper() != "NIL"){ m_ContentEncoding = MimeUtils.ParseContentTransferEncoding(contentEncoding); } // Content Encoded data size in bytes string contentSize = r.ReadWord(); if(contentSize.ToUpper() != "NIL"){ m_ContentSize = Convert.ToInt32(contentSize); } // Only for ContentType message/rfc822 if(this.ContentType == MediaType_enum.Message_rfc822){ r.ReadToFirstChar(); // envelope if(r.StartsWith("(")){ m_pEnvelope = new IMAP_Envelope(); m_pEnvelope.Parse(r.ReadParenthesized()); } else{ // Skip NIL, ENVELOPE wasn't included r.ReadWord(); } // TODO: // BODYSTRUCTURE // contentLine } // Only for ContentType text/xxx if(contentTypeMainMediaType.ToLower() == "text"){ // contentLine string contentLines = r.ReadWord(); if(contentLines.ToUpper() != "NIL"){ m_ContentLines = Convert.ToInt32(contentLines); } } } }
/// <summary> /// Loads messages to UI. /// </summary> private void LoadData() { m_pMessages.BeginUpdate(); m_pMessages.Items.Clear(); DataSet ds = m_pFolder.GetMessagesInfo(); if(ds.Tables.Contains("MessagesInfo")){ foreach(DataRow dr in ds.Tables["MessagesInfo"].Rows){ IMAP_Envelope envelope = new IMAP_Envelope(); try{ envelope.Parse(dr["Envelope"].ToString()); } catch{ } ListViewItem item = new ListViewItem(envelope.Subject); item.ImageIndex = 0; item.Tag = new object[]{dr["ID"].ToString(),Convert.ToInt32(dr["UID"])}; if(envelope.Sender != null && envelope.Sender.DisplayName != null && envelope.Sender.DisplayName != ""){ item.SubItems.Add(envelope.Sender.DisplayName); } else{ if(envelope.Sender != null){ item.SubItems.Add(envelope.Sender.EmailAddress); } else{ item.SubItems.Add("<none>"); } } item.SubItems.Add(envelope.Date.ToString()); item.SubItems.Add(((decimal)(Convert.ToDecimal(dr["Size"]) / 1000)).ToString("f2")); m_pMessages.Items.Add(item); } mt_Info.Text = "User '" + m_pFolder.User.UserName + "' Folder '" + m_pFolder.FolderFullPath + "' Messages (" + ds.Tables["MessagesInfo"].Rows.Count + ")"; } m_pMessages.EndUpdate(); m_pMessages_SelectedIndexChanged(null,null); }