/// <summary> /// Deletes specified message from recycle bin. /// </summary> /// <param name="messageID">Message ID which to restore.</param> public static void DeleteRecycleBinMessage(string messageID) { using(FileStream fs = GetFile()){ int delRowCount = 0; StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while(line != null){ // Skip comment lines if(!line.StartsWith("#")){ // Skip deleted row if(line.StartsWith("\0")){ delRowCount++; } else{ string[] row = TextUtils.SplitQuotedString(line,' '); // Delete row if(row[0] == messageID){ string user = row[2]; string folder = TextUtils.UnQuoteString(row[3]); // Delete message File.Delete(m_RecycleBinPath + messageID + ".eml"); // Delete row byte[] linebytes = new byte[fs.Position - pos - 2]; fs.Position = pos; fs.Write(linebytes,0,linebytes.Length); fs.Position += 2; // CRLF delRowCount++; break; } } } pos = fs.Position; line = r.ReadLineString(); } // There are many deleted rows, vacuum(remove deleted rows) flags database. if(delRowCount > 500){ Vacuum(fs); } } }
/// <summary> /// Deletes specified message all users flags. /// </summary> /// <param name="folder">Folder.</param> /// <param name="uid">Message UID.</param> public static void DeleteFlags(string folder,int uid) { using(FileStream fs = GetFlagsFile(null,folder)){ int delRowCount = 0; StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while(line != null){ // Skip comment lines if(!line.StartsWith("#")){ // Skip deleted row if(line.StartsWith("\0")){ delRowCount++; } else{ string[] userID_uid_flags = line.Split(' '); // Delete row if(Convert.ToInt32(userID_uid_flags[1]) == uid){ byte[] linebytes = new byte[fs.Position - pos - 2]; fs.Position = pos; fs.Write(linebytes,0,linebytes.Length); fs.Position += 2; // CRLF delRowCount++; } } } pos = fs.Position; line = r.ReadLineString(); } // There are many deleted rows, vacuum(remove deleted rows) flags database. if(delRowCount > 500){ Vacuum(fs); } } }
/// <summary> /// Default constructor. /// </summary> /// <param name="fs">Message file stream.</param> public _InternalHeader(FileStream fs) { m_pFile = fs; StreamLineReader r = new StreamLineReader(fs); string line = r.ReadLineString(); if(line!= null && line.ToLower() == "<internalheader>"){ line = r.ReadLineString(); while(line.ToLower() != "</internalheader>"){ if(line.ToLower().StartsWith("#-messageflags:")){ m_MessageFlags = (IMAP_MessageFlags)Enum.Parse(typeof(IMAP_MessageFlags),line.Substring(15).Trim()); } else if(line.ToLower().StartsWith("#-envelope:")){ m_Envelope = line.Substring(11).Trim(); } else if(line.ToLower().StartsWith("#-body:")){ m_Body = line.Substring(7).Trim(); } line = r.ReadLineString(); } // Remove internal header if(fs.CanWrite){ byte[] data = new byte[fs.Length - fs.Position]; fs.Read(data,0,data.Length); fs.Position = 0; fs.Write(data,0,data.Length); fs.SetLength(data.Length); fs.Position = 0; } } // Internal header doesn't exist else{ fs.Position = 0; } }
/// <summary> /// Vacuums flags database, deletes deleted rows empty used space from file. /// </summary> /// <param name="fs">Database file stream.</param> private static void Vacuum(FileStream fs) { MemoryStream buffer = new MemoryStream(); fs.Position = 0; StreamLineReader r = new StreamLineReader(fs); string line = r.ReadLineString(); while(line != null){ // Skip deleted rows if(!line.StartsWith("\0")){ byte[] lineBytes = System.Text.Encoding.ASCII.GetBytes(line + "\r\n"); buffer.Write(lineBytes,0,lineBytes.Length); } line = r.ReadLineString(); } fs.SetLength(buffer.Length); fs.Position = 0; buffer.WriteTo(fs); }
/// <summary> /// Restores specified message from recycle bin. /// </summary> /// <param name="messageID">Message ID which to restore.</param> /// <param name="api">Reference to API.</param> public static void RestoreFromRecycleBin(string messageID,IMailServerApi api) { using(FileStream fs = GetFile()){ int delRowCount = 0; StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while(line != null){ // Skip comment lines if(!line.StartsWith("#")){ // Skip deleted row if(line.StartsWith("\0")){ delRowCount++; } else{ string[] row = TextUtils.SplitQuotedString(line,' '); // Delete row if(row[0] == messageID){ string user = row[2]; string folder = TextUtils.UnQuoteString(row[3]); // Store message back to original user folder using(FileStream stream = File.OpenRead(m_RecycleBinPath + messageID + ".eml")){ // If folder doesn't exist, create it if(!api.FolderExists(user + "/" + folder)){ api.CreateFolder("system",user,folder); } api.StoreMessage("system",user,folder,stream,DateTime.Now,new string[]{"Recent"}); } // Delete row byte[] linebytes = new byte[fs.Position - pos - 2]; fs.Position = pos; fs.Write(linebytes,0,linebytes.Length); fs.Position += 2; // CRLF delRowCount++; // Delete recycle bin message File.Delete(m_RecycleBinPath + messageID + ".eml"); break; } } } pos = fs.Position; line = r.ReadLineString(); } // There are many deleted rows, vacuum(remove deleted rows) flags database. if(delRowCount > 500){ Vacuum(fs); } } }
/// <summary> /// Gets recycle bin message stream. NOTE: This method caller must take care of closing stream. /// </summary> /// <param name="messageID">Message ID if of message what to get.</param> /// <returns></returns> public static Stream GetRecycleBinMessage(string messageID) { using(FileStream fs = GetFile()){ int delRowCount = 0; StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while(line != null){ // Skip comment lines if(!line.StartsWith("#")){ // Skip deleted row if(line.StartsWith("\0")){ delRowCount++; } else{ string[] row = TextUtils.SplitQuotedString(line,' '); // Delete row if(row[0] == messageID){ string user = row[2]; string folder = TextUtils.UnQuoteString(row[3]); // Store message back to original user folder FileStream stream = File.OpenRead(m_RecycleBinPath + messageID + ".eml"); return stream; } } } pos = fs.Position; line = r.ReadLineString(); } } throw new Exception("Specified message doesn't exist !"); }
/// <summary> /// Sets specified message flags for specified user. /// </summary> /// <param name="userID">User ID.</param> /// <param name="folder">Folder.</param> /// <param name="uid">Message UID.</param> /// <param name="flags">Message flags.</param> public static void SetFlags(string userID,string folder,int uid,IMAP_MessageFlags flags) { using(FileStream fs = GetFlagsFile(userID,folder)){ StreamLineReader r = new StreamLineReader(fs); long pos = fs.Position; string line = r.ReadLineString(); while(line != null){ // Skip comment lines if(!line.StartsWith("#")){ string[] userID_uid_flags = line.Split(' '); // Update user message flags if(userID_uid_flags[0] == userID && Convert.ToInt32(userID_uid_flags[1]) == uid){ fs.Position = pos; byte[] record1 = System.Text.Encoding.ASCII.GetBytes(userID + " " + uid.ToString("d10") + " " + ((int)flags).ToString("d4") + "\r\n"); fs.Write(record1,0,record1.Length); return; } } pos = fs.Position; line = r.ReadLineString(); } // If we reach here, then specified user has no flags for specified message, add new record. byte[] record = System.Text.Encoding.ASCII.GetBytes(userID + " " + uid.ToString("d10") + " " + ((int)flags).ToString("d4") + "\r\n"); fs.Write(record,0,record.Length); } }