/// <summary>
        /// Sets body data from the specified stream.
        /// </summary>
        /// <param name="stream">Source stream.</param>
        /// <param name="transferEncoding">Specifies content-transfer-encoding to use to encode data.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stream</b> or <b>transferEncoding</b> is null reference.</exception>
        /// <exception cref="InvalidOperationException">Is raised when this method is accessed and this body is not bounded to any entity.</exception>
        public void SetData(Stream stream,string transferEncoding)
        {            
            if(stream == null){
                throw new ArgumentNullException("stream");
            }
            if(transferEncoding == null){
                throw new ArgumentNullException("transferEncoding");
            }

            if(string.Equals(transferEncoding,MIME_TransferEncodings.QuotedPrintable,StringComparison.InvariantCultureIgnoreCase)){
                using(MemoryStreamEx fs = new MemoryStreamEx(32000)){
                    QuotedPrintableStream encoder = new QuotedPrintableStream(new SmartStream(fs,false),FileAccess.ReadWrite);
                    Net_Utils.StreamCopy(stream,encoder,32000);
                    encoder.Flush();
                    fs.Position = 0;
                    SetEncodedData(transferEncoding,fs);
                }
            }
            else if(string.Equals(transferEncoding,MIME_TransferEncodings.Base64,StringComparison.InvariantCultureIgnoreCase)){
                using(MemoryStreamEx fs = new MemoryStreamEx(32000)){
                    Base64Stream encoder = new Base64Stream(fs,false,true,FileAccess.ReadWrite);                                     
                    Net_Utils.StreamCopy(stream,encoder,32000);
                    encoder.Finish();
                    fs.Position = 0;
                    SetEncodedData(transferEncoding,fs);
                }
            }            
            else if(string.Equals(transferEncoding,MIME_TransferEncodings.Binary,StringComparison.InvariantCultureIgnoreCase)){
                SetEncodedData(transferEncoding,stream);
            }
            else if(string.Equals(transferEncoding,MIME_TransferEncodings.EightBit,StringComparison.InvariantCultureIgnoreCase)){
                SetEncodedData(transferEncoding,stream);
            }
            else if(string.Equals(transferEncoding,MIME_TransferEncodings.SevenBit,StringComparison.InvariantCultureIgnoreCase)){
                SetEncodedData(transferEncoding,stream);
            }
            else{
                throw new NotSupportedException("Not supported Content-Transfer-Encoding '" + transferEncoding + "'.");
            }
        }
//
        #region method FETCH

        private void FETCH(bool uid,string cmdTag,string cmdText)
        {
            /* RFC 3501. 6.4.5. FETCH Command.
                Arguments:  sequence set
                            message data item names or macro

                Responses:  untagged responses: FETCH

                Result:     OK - fetch completed
                            NO - fetch error: can't fetch that data
                            BAD - command unknown or arguments invalid

                The FETCH command retrieves data associated with a message in the
                mailbox.  The data items to be fetched can be either a single atom
                or a parenthesized list.

                Most data items, identified in the formal syntax under the
                msg-att-static rule, are static and MUST NOT change for any
                particular message.  Other data items, identified in the formal
                syntax under the msg-att-dynamic rule, MAY change, either as a
                result of a STORE command or due to external events.

                    For example, if a client receives an ENVELOPE for a
                    message when it already knows the envelope, it can
                    safely ignore the newly transmitted envelope.

                There are three macros which specify commonly-used sets of data
                items, and can be used instead of data items.  A macro must be
                used by itself, and not in conjunction with other macros or data
                items.

                ALL
                    Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)

                FAST
                    Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)

                FULL
                    Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)

                The currently defined data items that can be fetched are:

                BODY
                    Non-extensible form of BODYSTRUCTURE.

                BODY[<section>]<<partial>>
                    The text of a particular body section.  The section
                    specification is a set of zero or more part specifiers
                    delimited by periods.  A part specifier is either a part number
                    or one of the following: HEADER, HEADER.FIELDS,
                    HEADER.FIELDS.NOT, MIME, and TEXT.  An empty section
                    specification refers to the entire message, including the
                    header.

                    Every message has at least one part number.  Non-[MIME-IMB]
                    messages, and non-multipart [MIME-IMB] messages with no
                    encapsulated message, only have a part 1.

                    Multipart messages are assigned consecutive part numbers, as
                    they occur in the message.  If a particular part is of type
                    message or multipart, its parts MUST be indicated by a period
                    followed by the part number within that nested multipart part.

                    A part of type MESSAGE/RFC822 also has nested part numbers,
                    referring to parts of the MESSAGE part's body.

                    The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and TEXT part
                    specifiers can be the sole part specifier or can be prefixed by
                    one or more numeric part specifiers, provided that the numeric
                    part specifier refers to a part of type MESSAGE/RFC822.  The
                    MIME part specifier MUST be prefixed by one or more numeric
                    part specifiers.

                    The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT part
                    specifiers refer to the [RFC-2822] header of the message or of
                    an encapsulated [MIME-IMT] MESSAGE/RFC822 message.
                    HEADER.FIELDS and HEADER.FIELDS.NOT are followed by a list of
                    field-name (as defined in [RFC-2822]) names, and return a
                    subset of the header.  The subset returned by HEADER.FIELDS
                    contains only those header fields with a field-name that
                    matches one of the names in the list; similarly, the subset
                    returned by HEADER.FIELDS.NOT contains only the header fields
                    with a non-matching field-name.  The field-matching is
                    case-insensitive but otherwise exact.  Subsetting does not
                    exclude the [RFC-2822] delimiting blank line between the header
                    and the body; the blank line is included in all header fetches,
                    except in the case of a message which has no body and no blank
                    line.

                    The MIME part specifier refers to the [MIME-IMB] header for
                    this part.

                    The TEXT part specifier refers to the text body of the message,
                    omitting the [RFC-2822] header.

                        Here is an example of a complex message with some of its
                        part specifiers:

                    HEADER     ([RFC-2822] header of the message)
                    TEXT       ([RFC-2822] text body of the message) MULTIPART/MIXED
                    1          TEXT/PLAIN
                    2          APPLICATION/OCTET-STREAM
                    3          MESSAGE/RFC822
                    3.HEADER   ([RFC-2822] header of the message)
                    3.TEXT     ([RFC-2822] text body of the message) MULTIPART/MIXED
                    3.1        TEXT/PLAIN
                    3.2        APPLICATION/OCTET-STREAM
                    4          MULTIPART/MIXED
                    4.1        IMAGE/GIF
                    4.1.MIME   ([MIME-IMB] header for the IMAGE/GIF)
                    4.2        MESSAGE/RFC822
                    4.2.HEADER ([RFC-2822] header of the message)
                    4.2.TEXT   ([RFC-2822] text body of the message) MULTIPART/MIXED
                    4.2.1      TEXT/PLAIN
                    4.2.2      MULTIPART/ALTERNATIVE
                    4.2.2.1    TEXT/PLAIN
                    4.2.2.2    TEXT/RICHTEXT
            
                    It is possible to fetch a substring of the designated text.
                    This is done by appending an open angle bracket ("<"), the
                    octet position of the first desired octet, a period, the
                    maximum number of octets desired, and a close angle bracket
                    (">") to the part specifier.  If the starting octet is beyond
                    the end of the text, an empty string is returned.
                    Any partial fetch that attempts to read beyond the end of the
                    text is truncated as appropriate.  A partial fetch that starts
                    at octet 0 is returned as a partial fetch, even if this
                    truncation happened.

                        Note: This means that BODY[]<0.2048> of a 1500-octet message
                        will return BODY[]<0> with a literal of size 1500, not
                        BODY[].

                        Note: A substring fetch of a HEADER.FIELDS or
                        HEADER.FIELDS.NOT part specifier is calculated after
                        subsetting the header.

                    The \Seen flag is implicitly set; if this causes the flags to
                    change, they SHOULD be included as part of the FETCH responses.

                BODY.PEEK[<section>]<<partial>>
                    An alternate form of BODY[<section>] that does not implicitly
                    set the \Seen flag.

                BODYSTRUCTURE
                    The [MIME-IMB] body structure of the message.  This is computed
                    by the server by parsing the [MIME-IMB] header fields in the
                    [RFC-2822] header and [MIME-IMB] headers.

                ENVELOPE
                    The envelope structure of the message.  This is computed by the
                    server by parsing the [RFC-2822] header into the component
                    parts, defaulting various fields as necessary.

                FLAGS
                    The flags that are set for this message.

                INTERNALDATE
                    The internal date of the message.

                RFC822
                    Functionally equivalent to BODY[], differing in the syntax of
                    the resulting untagged FETCH data (RFC822 is returned).

                RFC822.HEADER
                    Functionally equivalent to BODY.PEEK[HEADER], differing in the
                    syntax of the resulting untagged FETCH data (RFC822.HEADER is
                    returned).

                RFC822.SIZE
                    The [RFC-2822] size of the message.

                RFC822.TEXT
                    Functionally equivalent to BODY[TEXT], differing in the syntax
                    of the resulting untagged FETCH data (RFC822.TEXT is returned).
                UID
                    The unique identifier for the message.


                Example:    C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
                            S: * 2 FETCH ....
                            S: * 3 FETCH ....
                            S: * 4 FETCH ....
                            S: A654 OK FETCH completed
            */

            // Store start time
			long startTime = DateTime.Now.Ticks;

            if(!this.IsAuthenticated){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","Authentication required."));

                return;
            }
            if(m_pSelectedFolder == null){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"NO","Error: This command is valid only in selected state."));

                return;
            }
            
            string[] parts = cmdText.Split(new char[]{' '},2);
            if(parts.Length != 2){
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"BAD","Error in arguments."));

                return;
            }

            IMAP_t_SeqSet seqSet = null;
            try{                
                seqSet = IMAP_t_SeqSet.Parse(parts[0]);
            }
            catch{
                m_pResponseSender.SendResponseAsync(new IMAP_r_ServerStatus(cmdTag,"BAD","Error in arguments: Invalid 'sequence-set' value."));

                return;
            }

            #region Parse data-items

            List<IMAP_t_Fetch_i> dataItems     = new List<IMAP_t_Fetch_i>();
            bool                 msgDataNeeded = false;

            // Remove parenthesizes.
            string dataItemsString = parts[1].Trim();
            if(dataItemsString.StartsWith("(") && dataItemsString.EndsWith(")")){
                dataItemsString = dataItemsString.Substring(1,dataItemsString.Length - 2).Trim();
            }

            // Replace macros.
            dataItemsString = dataItemsString.Replace("ALL","FLAGS INTERNALDATE RFC822.SIZE ENVELOPE");
            dataItemsString = dataItemsString.Replace("FAST","FLAGS INTERNALDATE RFC822.SIZE"); 
            dataItemsString = dataItemsString.Replace("FULL","FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY");

            StringReader r = new StringReader(dataItemsString);

            IMAP_Fetch_DataType fetchDataType = IMAP_Fetch_DataType.MessageHeader;

            // Parse data-items.
            while(r.Available > 0){
                r.ReadToFirstChar();

                #region BODYSTRUCTURE

                if(r.StartsWith("BODYSTRUCTURE",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_BodyStructure());
                    msgDataNeeded = true;
                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage){
                        fetchDataType = IMAP_Fetch_DataType.MessageStructure;
                    }
                }

                #endregion

                #region BODY[<section>]<<partial>> and BODY.PEEK[<section>]<<partial>>

                else if(r.StartsWith("BODY[",false) || r.StartsWith("BODY.PEEK[",false)){
                    bool peek = r.StartsWith("BODY.PEEK[",false);
                    r.ReadWord();

                    #region Parse <section>

                    string section = r.ReadParenthesized();
                                                                            
                    // Full message wanted.
                    if(string.IsNullOrEmpty(section)){
                        fetchDataType = IMAP_Fetch_DataType.FullMessage;
                    }
                    else{
                        // Left-side part-items must be numbers, only last one may be (HEADER,HEADER.FIELDS,HEADER.FIELDS.NOT,MIME,TEXT).
                    
                        StringReader rSection = new StringReader(section);
                        string remainingSection = rSection.ReadWord();
                        while(remainingSection.Length > 0){
                            string[] section_parts = remainingSection.Split(new char[]{'.'},2);
                            // Not part number.
                            if(!Net_Utils.IsInteger(section_parts[0])){
                                // We must have one of the following values here (HEADER,HEADER.FIELDS,HEADER.FIELDS.NOT,MIME,TEXT).
                                if(remainingSection.Equals("HEADER",StringComparison.InvariantCultureIgnoreCase)){
                                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage && fetchDataType != IMAP_Fetch_DataType.MessageStructure){
                                        fetchDataType = IMAP_Fetch_DataType.MessageHeader;
                                    }
                                }
                                else if(remainingSection.Equals("HEADER.FIELDS",StringComparison.InvariantCultureIgnoreCase)){
                                    rSection.ReadToFirstChar();
                                    if(!rSection.StartsWith("(")){
                                        WriteLine(cmdTag + " BAD Error in arguments.");

                                        return;
                                    }
                                    rSection.ReadParenthesized();

                                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage && fetchDataType != IMAP_Fetch_DataType.MessageStructure){
                                        fetchDataType = IMAP_Fetch_DataType.MessageHeader;
                                    }
                                }
                                else if(remainingSection.Equals("HEADER.FIELDS.NOT",StringComparison.InvariantCultureIgnoreCase)){
                                    rSection.ReadToFirstChar();
                                    if(!rSection.StartsWith("(")){
                                        WriteLine(cmdTag + " BAD Error in arguments.");

                                        return;
                                    }
                                    rSection.ReadParenthesized();

                                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage && fetchDataType != IMAP_Fetch_DataType.MessageStructure){
                                        fetchDataType = IMAP_Fetch_DataType.MessageHeader;
                                    }
                                }
                                else if(remainingSection.Equals("MIME",StringComparison.InvariantCultureIgnoreCase)){
                                    fetchDataType = IMAP_Fetch_DataType.FullMessage;
                                }
                                else if(remainingSection.Equals("TEXT",StringComparison.InvariantCultureIgnoreCase)){
                                    fetchDataType = IMAP_Fetch_DataType.FullMessage;
                                }
                                // Unknown parts specifier.
                                else{
                                    WriteLine(cmdTag + " BAD Error in arguments.");

                                    return;
                                }

                                break;
                            }
                            else{
                                // For parts specifier, minimum is message structure.
                                if(fetchDataType != IMAP_Fetch_DataType.FullMessage){
                                    fetchDataType = IMAP_Fetch_DataType.MessageStructure;
                                }
                            }

                            if(section_parts.Length == 2){
                                remainingSection = section_parts[1];
                            }
                            else{
                                remainingSection = "";
                            }
                        }
                    }

                    #endregion

                    #region Parse <partial>

                    int offset   = -1;
                    int maxCount = -1;
                    // Partial data wanted.
                    if(r.StartsWith("<")){
                        string[] origin = r.ReadParenthesized().Split('.');
                        if(origin.Length > 2){
                            WriteLine(cmdTag + " BAD Error in arguments.");

                            return;
                        }

                        if(!int.TryParse(origin[0],out offset)){
                            WriteLine(cmdTag + " BAD Error in arguments.");

                            return;
                        }
                        if(origin.Length == 2){
                            if(!int.TryParse(origin[1],out maxCount)){
                                WriteLine(cmdTag + " BAD Error in arguments.");

                                return;
                            }
                        }
                    }

                    #endregion

                    if(peek){
                        dataItems.Add(new IMAP_t_Fetch_i_BodyPeek(section,offset,maxCount));
                    }
                    else{
                        dataItems.Add(new IMAP_t_Fetch_i_Body(section,offset,maxCount));
                    }
                    msgDataNeeded = true;
                }

                #endregion
                
                #region BODY

                else if(r.StartsWith("BODY",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_BodyS());
                    msgDataNeeded = true;
                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage){
                        fetchDataType = IMAP_Fetch_DataType.MessageStructure;
                    }
                }

                #endregion

                #region ENVELOPE

                else if(r.StartsWith("ENVELOPE",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Envelope());
                    msgDataNeeded = true;
                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage && fetchDataType != IMAP_Fetch_DataType.MessageStructure){
                        fetchDataType = IMAP_Fetch_DataType.MessageHeader;
                    }
                }

                #endregion
                
                #region FLAGS

                else if(r.StartsWith("FLAGS",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Flags());
                }

                #endregion

                #region INTERNALDATE

                else if(r.StartsWith("INTERNALDATE",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_InternalDate());
                }

                #endregion

                #region RFC822.HEADER

                else if(r.StartsWith("RFC822.HEADER",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Rfc822Header());
                    msgDataNeeded = true;
                    if(fetchDataType != IMAP_Fetch_DataType.FullMessage && fetchDataType != IMAP_Fetch_DataType.MessageStructure){
                        fetchDataType = IMAP_Fetch_DataType.MessageHeader;
                    }
                }

                #endregion

                #region RFC822.SIZE

                else if(r.StartsWith("RFC822.SIZE",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Rfc822Size());
                }

                #endregion

                #region RFC822.TEXT

                else if(r.StartsWith("RFC822.TEXT",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Rfc822Text());
                    msgDataNeeded = true;
                    fetchDataType = IMAP_Fetch_DataType.FullMessage;
                }

                #endregion

                #region RFC822

                else if(r.StartsWith("RFC822",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Rfc822());
                    msgDataNeeded = true;
                    fetchDataType = IMAP_Fetch_DataType.FullMessage;
                }

                #endregion

                #region UID

                else if(r.StartsWith("UID",false)){
                    r.ReadWord();
                    dataItems.Add(new IMAP_t_Fetch_i_Uid());
                }

                #endregion

                #region Unknown data-item.

                else{
                    WriteLine(cmdTag + " BAD Error in arguments: Unknown FETCH data-item.");

                    return;
                }

                #endregion
            }

            #endregion

            // UID FETCH must always return UID data-item, even if user didn't request it.
            if(uid){
                bool add = true;
                foreach(IMAP_t_Fetch_i item in dataItems){                    
                    if(item is IMAP_t_Fetch_i_Uid){
                        add = false;
                        break;
                    }
                }
                if(add){
                    dataItems.Add(new IMAP_t_Fetch_i_Uid());
                }
            }

            UpdateSelectedFolderAndSendChanges();

            IMAP_e_Fetch fetchEArgs = new IMAP_e_Fetch(
                m_pSelectedFolder.Filter(uid,seqSet),
                fetchDataType,
                new IMAP_r_ServerStatus(cmdTag,"OK","FETCH command completed in %exectime seconds.")
            );
            fetchEArgs.NewMessageData += new EventHandler<IMAP_e_Fetch.e_NewMessageData>(delegate(object s,IMAP_e_Fetch.e_NewMessageData e){                
                StringBuilder reponseBuffer = new StringBuilder();
                reponseBuffer.Append("* " + e.MessageInfo.SeqNo + " FETCH (");

                Mail_Message message = e.MessageData;

                // Return requested data-items for the returned message.
                for(int i=0;i<dataItems.Count;i++){
                    IMAP_t_Fetch_i dataItem = dataItems[i];
                                      
                    // Add data-items separator.
                    if(i > 0){
                        reponseBuffer.Append(" ");
                    }
                                       
                    #region BODY

                    if(dataItem is IMAP_t_Fetch_i_BodyS){
                        reponseBuffer.Append(ConstructBodyStructure(message,false));
                    }

                    #endregion

                    #region BODY[<section>]<<partial>> and BODY.PEEK[<section>]<<partial>>

                    else if(dataItem is IMAP_t_Fetch_i_Body || dataItem is IMAP_t_Fetch_i_BodyPeek){
                        string section  = "";
                        int    offset   = -1;
                        int    maxCount = -1;
                        if(dataItem is IMAP_t_Fetch_i_Body){
                            section  = ((IMAP_t_Fetch_i_Body)dataItem).Section;
                            offset   = ((IMAP_t_Fetch_i_Body)dataItem).Offset;
                            maxCount = ((IMAP_t_Fetch_i_Body)dataItem).MaxCount;
                        }
                        else{
                            section  = ((IMAP_t_Fetch_i_BodyPeek)dataItem).Section;
                            offset   = ((IMAP_t_Fetch_i_BodyPeek)dataItem).Offset;
                            maxCount = ((IMAP_t_Fetch_i_BodyPeek)dataItem).MaxCount;
                        }

                        using(MemoryStreamEx tmpFs = new MemoryStreamEx(32000)){
                            // Empty section, full message wanted.
                            if(string.IsNullOrEmpty(section)){
                                message.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8);
                                tmpFs.Position = 0;
                            }
                            // Message data part wanted.
                            else{
                                // Get specified MIME part.
                                MIME_Entity entity = GetMimeEntity(message,ParsePartNumberFromSection(section));
                                if(entity != null){
                                    string partSpecifier = ParsePartSpecifierFromSection(section);

                                    #region HEADER

                                    if(string.Equals(partSpecifier,"HEADER",StringComparison.InvariantCultureIgnoreCase)){                                        
                                        entity.Header.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8);
                                        // All header fetches must include header terminator(CRLF).
                                        if(tmpFs.Length >0 ){
                                            tmpFs.WriteByte((byte)'\r');
                                            tmpFs.WriteByte((byte)'\n');
                                        }
                                        tmpFs.Position = 0;
                                    }

                                    #endregion

                                    #region HEADER.FIELDS

                                    else if(string.Equals(partSpecifier,"HEADER.FIELDS",StringComparison.InvariantCultureIgnoreCase)){                            
                                        string   fieldsString = section.Split(new char[]{' '},2)[1];
                                        string[] fieldNames   = fieldsString.Substring(1,fieldsString.Length - 2).Split(' ');
                                        foreach(string filedName in fieldNames){
                                            MIME_h[] fields = entity.Header[filedName];
                                            if(fields != null){
                                                foreach(MIME_h field in fields){
                                                    byte[] fieldBytes = Encoding.UTF8.GetBytes(field.ToString(new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8));
                                                    tmpFs.Write(fieldBytes,0,fieldBytes.Length);
                                                }
                                            }
                                        }
                                        // All header fetches must include header terminator(CRLF).
                                        if(tmpFs.Length > 0){
                                            tmpFs.WriteByte((byte)'\r');
                                            tmpFs.WriteByte((byte)'\n');
                                        }
                                        tmpFs.Position = 0;
                                    }

                                    #endregion

                                    #region HEADER.FIELDS.NOT

                                    else if(string.Equals(partSpecifier,"HEADER.FIELDS.NOT",StringComparison.InvariantCultureIgnoreCase)){
                                        string   fieldsString = section.Split(new char[]{' '},2)[1];
                                        string[] fieldNames   = fieldsString.Substring(1,fieldsString.Length - 2).Split(' ');
                                        foreach(MIME_h field in entity.Header){
                                            bool contains = false;
                                            foreach(string fieldName in fieldNames){
                                                if(string.Equals(field.Name,fieldName,StringComparison.InvariantCultureIgnoreCase)){
                                                    contains = true;
                                                    break;
                                                }
                                            }

                                            if(!contains){
                                                byte[] fieldBytes = Encoding.UTF8.GetBytes(field.ToString(new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8));
                                                tmpFs.Write(fieldBytes,0,fieldBytes.Length);
                                            }
                                        }
                                        // All header fetches must include header terminator(CRLF).
                                        if(tmpFs.Length >0 ){
                                            tmpFs.WriteByte((byte)'\r');
                                            tmpFs.WriteByte((byte)'\n');
                                        }
                                        tmpFs.Position = 0;
                                    }

                                    #endregion

                                    #region MIME

                                    else if(string.Equals(partSpecifier,"MIME",StringComparison.InvariantCultureIgnoreCase)){
                                        entity.Header.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8);
                                        // All header fetches must include header terminator(CRLF).
                                        if(tmpFs.Length >0 ){
                                            tmpFs.WriteByte((byte)'\r');
                                            tmpFs.WriteByte((byte)'\n');
                                        }
                                        tmpFs.Position = 0;
                                    }

                                    #endregion

                                    #region TEXT

                                    else if(string.Equals(partSpecifier,"TEXT",StringComparison.InvariantCultureIgnoreCase)){
                                        entity.Body.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8,false);
                                        tmpFs.Position = 0;
                                    }

                                    #endregion

                                    #region part-number only

                                    else{
                                        entity.Body.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8,false);
                                        tmpFs.Position = 0;
                                    }

                                    #endregion
                                }
                            }

                            #region Send data

                            // All data wanted.
                            if(offset < 0){
                                reponseBuffer.Append("BODY[" + section + "] {" + tmpFs.Length + "}\r\n");
                                WriteLine(reponseBuffer.ToString());
                                reponseBuffer = new StringBuilder();

                                this.TcpStream.WriteStream(tmpFs);
                                LogAddWrite(tmpFs.Length,"Wrote " + tmpFs.Length + " bytes.");
                            }
                            // Partial data wanted.
                            else{                                    
                                // Offet out of range.
                                if(offset >= tmpFs.Length){
                                    reponseBuffer.Append("BODY[" + section + "]<" + offset + "> \"\"");
                                }
                                else{
                                    tmpFs.Position = offset;
                                        
                                    int count = maxCount > -1 ? (int)Math.Min(maxCount,tmpFs.Length - tmpFs.Position) : (int)(tmpFs.Length - tmpFs.Position);
                                    reponseBuffer.Append("BODY[" + section + "]<" + offset + "> {" + count + "}");
                                    WriteLine(reponseBuffer.ToString());
                                    reponseBuffer = new StringBuilder();

                                    this.TcpStream.WriteStream(tmpFs,count);
                                    LogAddWrite(tmpFs.Length,"Wrote " + count + " bytes.");
                                }
                            }

                            #endregion
                        }

                        // Set Seen flag.
                        if(!m_pSelectedFolder.IsReadOnly && dataItem is IMAP_t_Fetch_i_Body){
                            try{
                                OnStore(e.MessageInfo,IMAP_Flags_SetType.Add,new string[]{"Seen"},new IMAP_r_ServerStatus("dummy","OK","This is FETCH set Seen flag, this response not used."));
                            }
                            catch{
                            }
                        }
                    }

                    #endregion

                    #region BODYSTRUCTURE

                    else if(dataItem is IMAP_t_Fetch_i_BodyStructure){
                        reponseBuffer.Append(ConstructBodyStructure(message,true));
                    }

                    #endregion

                    #region ENVELOPE

                    else if(dataItem is IMAP_t_Fetch_i_Envelope){
                        reponseBuffer.Append(IMAP_t_Fetch_r_i_Envelope.ConstructEnvelope(message));
                    }

                    #endregion

                    #region FLAGS

                    else if(dataItem is IMAP_t_Fetch_i_Flags){
                        reponseBuffer.Append("FLAGS " + e.MessageInfo.FlagsToImapString());
                    }

                    #endregion

                    #region INTERNALDATE

                    else if(dataItem is IMAP_t_Fetch_i_InternalDate){
                        reponseBuffer.Append("INTERNALDATE \"" + IMAP_Utils.DateTimeToString(e.MessageInfo.InternalDate) + "\"");
                    }

                    #endregion

                    #region RFC822

                    else if(dataItem is IMAP_t_Fetch_i_Rfc822){
                        using(MemoryStreamEx tmpFs = new MemoryStreamEx(32000)){
                            message.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8);
                            tmpFs.Position = 0;

                            reponseBuffer.Append("RFC822 {" + tmpFs.Length + "}\r\n");
                            WriteLine(reponseBuffer.ToString());
                            reponseBuffer = new StringBuilder();

                            this.TcpStream.WriteStream(tmpFs);
                            LogAddWrite(tmpFs.Length,"Wrote " + tmpFs.Length + " bytes.");
                        }
                    }

                    #endregion

                    #region RFC822.HEADER

                    else if(dataItem is IMAP_t_Fetch_i_Rfc822Header){
                        MemoryStream ms = new MemoryStream();
                        message.Header.ToStream(ms,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8);
                        ms.Position = 0;

                        reponseBuffer.Append("RFC822.HEADER {" + ms.Length + "}\r\n");
                        WriteLine(reponseBuffer.ToString());
                        reponseBuffer = new StringBuilder();

                        this.TcpStream.WriteStream(ms);
                        LogAddWrite(ms.Length,"Wrote " + ms.Length + " bytes.");
                    }

                    #endregion

                    #region RFC822.SIZE

                    else if(dataItem is IMAP_t_Fetch_i_Rfc822Size){
                        reponseBuffer.Append("RFC822.SIZE " + e.MessageInfo.Size);
                    }

                    #endregion

                    #region RFC822.TEXT

                    else if(dataItem is IMAP_t_Fetch_i_Rfc822Text){
                        using(MemoryStreamEx tmpFs = new MemoryStreamEx(32000)){
                            message.Body.ToStream(tmpFs,new MIME_Encoding_EncodedWord(MIME_EncodedWordEncoding.B,Encoding.UTF8),Encoding.UTF8,false);
                            tmpFs.Position = 0;

                            reponseBuffer.Append("RFC822.TEXT {" + tmpFs.Length + "}\r\n");
                            WriteLine(reponseBuffer.ToString());
                            reponseBuffer = new StringBuilder();

                            this.TcpStream.WriteStream(tmpFs);
                            LogAddWrite(tmpFs.Length,"Wrote " + tmpFs.Length + " bytes.");
                        }
                    }

                    #endregion

                    #region UID

                    else if(dataItem is IMAP_t_Fetch_i_Uid){ 
                        reponseBuffer.Append("UID " + e.MessageInfo.UID);
                    }

                    #endregion
                }

                reponseBuffer.Append(")\r\n");            
                WriteLine(reponseBuffer.ToString());
            });
                        
            // We have all needed data in message info.
            if(!msgDataNeeded){
                foreach(IMAP_MessageInfo msgInfo in m_pSelectedFolder.Filter(uid,seqSet)){
                    fetchEArgs.AddData(msgInfo);
                }
            }
            // Request messages data.
            else{
                OnFetch(fetchEArgs);
            }
                                    
            WriteLine(fetchEArgs.Response.ToString().Replace("%exectime",((DateTime.Now.Ticks - startTime) / (decimal)10000000).ToString("f2")));
        }
示例#3
0
        /// <summary>
        /// Clones mail message.
        /// </summary>
        /// <returns>Returns cloned message.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        public Mail_Message Clone()
        {
            if(this.IsDisposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }

            MemoryStreamEx ms = new MemoryStreamEx(64000);
            this.ToStream(ms,null,null);
            ms.Position = 0;
            
            return Mail_Message.ParseFromStream(ms);
        }
        /// <summary>
        /// Gets attachment stream.
        /// </summary>
        /// <returns>Returns attachment stream.</returns>
        internal Stream GetStream()
        {
            if(m_pStream == null){
                m_pStream = File.OpenRead(m_FileName);
            }

            if(m_ZipCompress){
                MemoryStreamEx retVal = new MemoryStreamEx();

                using(ZipArchive archive = new ZipArchive(retVal,ZipArchiveMode.Create)){
                    ZipArchiveEntry entry = archive.CreateEntry(m_Name,CompressionLevel.Optimal);
                    using(Stream zipStream = entry.Open()){
                        Net_Utils.StreamCopy(m_pStream,zipStream,64000);
                    }
                }
                retVal.Position = 0;
                CloseStream();

                return retVal;
            }

            return m_pStream;
        }
示例#5
0
		private void NLST(string argsText)
		{
            if(m_SessionRejected){
                WriteLine("500 Bad sequence of commands: Session rejected.");

                return;
            }			
			if(!this.IsAuthenticated){
				WriteLine("530 Please authenticate firtst !");

				return;
			}

            /*
				This command causes a directory listing to be sent from
				server to user site.  The pathname should specify a
				directory or other system-specific file group descriptor; a
				null argument implies the current directory.  The server
				will return a stream of names of files and no other
				information.  The data will be transferred in ASCII or
				EBCDIC type over the data connection as valid pathname
				strings separated by <CRLF> or <NL>.  (Again the user must
				ensure that the TYPE is correct.)  This command is intended
				to return information that can be used by a program to
				further process the files automatically.  For example, in
				the implementation of a "multiple get" function.
			*/

			FTP_e_GetDirListing eArgs = new FTP_e_GetDirListing(argsText);
            OnGetDirListing(eArgs);

            // Error getting directory listing.
            if(eArgs.Error != null){
                foreach(FTP_t_ReplyLine reply in eArgs.Error){
                    WriteLine(reply.ToString());
                }
            }
            // Listing succeeded.
            else{
                // Build directory listing.
                MemoryStreamEx retVal = new MemoryStreamEx(8000);
                foreach(FTP_ListItem item in eArgs.Items){
                    byte[] data = Encoding.UTF8.GetBytes(item.Name + "\r\n");
                    retVal.Write(data,0,data.Length);
                }
                retVal.Position = 0;                

                m_pDataConnection = new DataConnection(this,retVal,false);
                m_pDataConnection.Start();
            }
		}
示例#6
0
		private void LIST(string argsText)
		{
            if(m_SessionRejected){
                WriteLine("500 Bad sequence of commands: Session rejected.");

                return;
            }
            if(!this.IsAuthenticated){
				WriteLine("530 Please authenticate firtst !");

				return;
			}

			/*
				This command causes a list to be sent from the server to the
				passive DTP.  If the pathname specifies a directory or other
				group of files, the server should transfer a list of files
				in the specified directory.  If the pathname specifies a
				file then the server should send current information on the
				file.  A null argument implies the user's current working or
				default directory.  The data transfer is over the data
				connection in type ASCII or type EBCDIC.  (The user must
				ensure that the TYPE is appropriately ASCII or EBCDIC).
				Since the information on a file may vary widely from system
				to system, this information may be hard to use automatically
				in a program, but may be quite useful to a human user.
			*/

            FTP_e_GetDirListing eArgs = new FTP_e_GetDirListing(argsText);
            OnGetDirListing(eArgs);

            // Error getting directory listing.
            if(eArgs.Error != null){
                foreach(FTP_t_ReplyLine reply in eArgs.Error){
                    WriteLine(reply.ToString());
                }
            }
            // Listing succeeded.
            else{
                // Build directory listing.
                MemoryStreamEx retVal = new MemoryStreamEx(8000);
                foreach(FTP_ListItem item in eArgs.Items){
                    if(item.IsDir){
                        byte[] data = Encoding.UTF8.GetBytes(item.Modified.ToString("MM-dd-yy HH:mm") + " <DIR> " + item.Name + "\r\n");
					    retVal.Write(data,0,data.Length);
					}
					else{
                        byte[] data = Encoding.UTF8.GetBytes(item.Modified.ToString("MM-dd-yy HH:mm") + " " + item.Size.ToString() + " " + item.Name + "\r\n");
					    retVal.Write(data,0,data.Length);
					}
                }
                retVal.Position = 0;                

                m_pDataConnection = new DataConnection(this,retVal,false);
                m_pDataConnection.Start();
            }
		}
示例#7
0
        private void StoreUserFolderMessage(string argsText)
        {
            /* C: StoreUserFolderMessage <virtualServerID> "<folderOwnerUser>" "<folder>" <sizeInBytes>
               S: +OK Send message data
               C: <messageData>
               S: +OK
             
                  Responses:
                    +OK               
                    -ERR <errorText>
            */

            try{
                string[] args = TextUtils.SplitQuotedString(argsText,' ',true);
                if(args.Length != 4){
                    WriteLine("-ERR Invalid arguments. Syntax: StoreUserFolderMessage <virtualServerID> \"<folderOwnerUser>\" \"<folder>\" <sizeInBytes>");
                    return;
                }

                foreach(VirtualServer virtualServer in this.Server.MailServer.VirtualServers){
                    if(virtualServer.ID.ToLower() == args[0].ToLower()){ 
                        // TODO: handle no existent user
                        // TODO: handle no existent folder

                        WriteLine("+OK");
                        using(MemoryStreamEx messageStream = new MemoryStreamEx(32000)){
                            this.TcpStream.ReadFixedCount(messageStream,Convert.ToInt32(args[3]));
                            messageStream.Position = 0;
                            virtualServer.API.StoreMessage(
                                "system",
                                args[1],
                                args[2],
                                messageStream,
                                DateTime.Now,
                                new string[]{"Recent"}
                            );
                        }
                                                
                        WriteLine("+OK");
                        return;
                    }
                }

                WriteLine("-ERR Specified virtual server with ID '" + args[0] + "' doesn't exist !");
            }
            catch(Exception x){
                WriteLine("-ERR " + x.Message);
            }
        }