/// <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; }
/// <summary> /// Adds specified mime entity to the end of the collection. /// </summary> /// <param name="entity">Mime entity to add to the collection.</param> public void Add(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.Add(entity); }
/// <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"; }
/// <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> /// 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>(); }
/// <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); }
/// <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); }