Beispiel #1
0
        /// <summary>
        /// Returns parsed IMAP SEARCH <b>SENTBEFORE (string)</b> key.
        /// </summary>
        /// <param name="r">String reader.</param>
        /// <returns>Returns parsed IMAP SEARCH <b>SENTBEFORE (string)</b> key.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when parsing fails.</exception>
        internal static IMAP_Search_Key_SentBefore Parse(StringReader r)
        {
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }

            string word = r.ReadWord();

            if (!string.Equals(word, "SENTBEFORE", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ParseException("Parse error: Not a SEARCH 'SENTBEFORE' key.");
            }
            string value = r.ReadWord();

            if (value == null)
            {
                throw new ParseException("Parse error: Invalid 'SENTBEFORE' value.");
            }
            DateTime date;

            try{
                date = IMAP_Utils.ParseDate(value);
            }
            catch {
                throw new ParseException("Parse error: Invalid 'SENTBEFORE' value.");
            }

            return(new IMAP_Search_Key_SentBefore(date));
        }
        /// <summary>
        /// Parses STATUS response from status-response string.
        /// </summary>
        /// <param name="response">Satatus response string.</param>
        /// <returns>Returns parsed STATUS response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public static IMAP_r_u_Status Parse(string response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            /* RFC 3501 7.2.4 STATUS Response.
             *  Contents:   name
             *              status parenthesized list
             *
             *  The STATUS response occurs as a result of an STATUS command.  It
             *  returns the mailbox name that matches the STATUS specification and
             *  the requested mailbox status information.
             *
             *  Example:    S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
             */

            StringReader r = new StringReader(response);

            // Eat "*"
            r.ReadWord();
            // Eat "STATUS"
            r.ReadWord();

            int  messages  = 0;
            int  recent    = 0;
            long uidNext   = 0;
            long folderUid = 0;
            int  unseen    = 0;

            string folder = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord()));

            string[] items = r.ReadParenthesized().Split(' ');
            for (int i = 0; i < items.Length; i += 2)
            {
                if (items[i].Equals("MESSAGES", StringComparison.InvariantCultureIgnoreCase))
                {
                    messages = Convert.ToInt32(items[i + 1]);
                }
                else if (items[i].Equals("RECENT", StringComparison.InvariantCultureIgnoreCase))
                {
                    recent = Convert.ToInt32(items[i + 1]);
                }
                else if (items[i].Equals("UIDNEXT", StringComparison.InvariantCultureIgnoreCase))
                {
                    uidNext = Convert.ToInt64(items[i + 1]);
                }
                else if (items[i].Equals("UIDVALIDITY", StringComparison.InvariantCultureIgnoreCase))
                {
                    folderUid = Convert.ToInt64(items[i + 1]);
                }
                else if (items[i].Equals("UNSEEN", StringComparison.InvariantCultureIgnoreCase))
                {
                    unseen = Convert.ToInt32(items[i + 1]);
                }
            }

            return(new IMAP_r_u_Status(folder, messages, recent, uidNext, folderUid, unseen));
        }
Beispiel #3
0
        /// <summary>
        /// Parses LSUB response from lsub-response string.
        /// </summary>
        /// <param name="lSubResponse">LSub response string.</param>
        /// <returns>Returns parsed lsub response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>lSubResponse</b> is null reference.</exception>
        public static IMAP_r_u_LSub Parse(string lSubResponse)
        {
            if (lSubResponse == null)
            {
                throw new ArgumentNullException("lSubResponse");
            }

            /* RFC 3501 7.2.3. LSUB Response.
             *  Contents:   name attributes
             *              hierarchy delimiter
             *              name
             *
             *  The LSUB response occurs as a result of an LSUB command.  It
             *  returns a single name that matches the LSUB specification.  There
             *  can be multiple LSUB responses for a single LSUB command.  The
             *  data is identical in format to the LIST response.
             *
             *  Example:    S: * LSUB () "." #news.comp.mail.misc
             */

            StringReader r = new StringReader(lSubResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "LSUB"
            r.ReadWord();

            string attributes = r.ReadParenthesized();
            string delimiter  = r.ReadWord();
            string folder     = TextUtils.UnQuoteString(IMAP_Utils.DecodeMailbox(r.ReadToEnd().Trim()));

            return(new IMAP_r_u_LSub(folder, delimiter[0], attributes == string.Empty ? new string[0] : attributes.Split(' ')));
        }
Beispiel #4
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * LSUB (\Noselect) "/" ~/Mail/foo

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* LSUB (");
            if (m_pFolderAttributes != null)
            {
                for (int i = 0; i < m_pFolderAttributes.Length; i++)
                {
                    if (i > 0)
                    {
                        retVal.Append(" ");
                    }
                    retVal.Append(m_pFolderAttributes[i]);
                }
            }
            retVal.Append(") ");
            retVal.Append("\"" + m_Delimiter + "\" ");
            retVal.Append(IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            retVal.Append("\r\n");

            return(retVal.ToString());
        }
Beispiel #5
0
        /// <summary>
        /// Parses MYRIGHTS response from MYRIGHTS-response string.
        /// </summary>
        /// <param name="myRightsResponse">MYRIGHTS response line.</param>
        /// <returns>Returns parsed MYRIGHTS response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>myRightsResponse</b> is null reference.</exception>
        public static IMAP_r_u_MyRights Parse(string myRightsResponse)
        {
            if (myRightsResponse == null)
            {
                throw new ArgumentNullException("myRightsResponse");
            }

            /* RFC 4314 3.8. MYRIGHTS Response.
             *  Data:       mailbox name
             *              rights
             *
             *  The MYRIGHTS response occurs as a result of a MYRIGHTS command.  The
             *  first string is the mailbox name for which these rights apply.  The
             *  second string is the set of rights that the client has.
             *
             *  Section 2.1.1 details additional server requirements related to
             *  handling of the virtual "d" and "c" rights.
             *
             *  Example:    C: A003 MYRIGHTS INBOX
             *              S: * MYRIGHTS INBOX rwiptsldaex
             *              S: A003 OK Myrights complete
             */

            StringReader r = new StringReader(myRightsResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "MYRIGHTS"
            r.ReadWord();

            string folder = IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord(true));
            string rights = r.ReadToEnd().Trim();

            return(new IMAP_r_u_MyRights(folder, rights));
        }
        /// <summary>
        /// Returns parsed IMAP SEARCH <b>HEADER (field-name) (string)</b> key.
        /// </summary>
        /// <param name="r">String reader.</param>
        /// <returns>Returns parsed IMAP SEARCH <b>HEADER (field-name) (string)</b> key.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when parsing fails.</exception>
        internal static IMAP_Search_Key_Header Parse(StringReader r)
        {
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }

            string word = r.ReadWord();

            if (!string.Equals(word, "HEADER", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ParseException("Parse error: Not a SEARCH 'HEADER' key.");
            }
            string fieldName = IMAP_Utils.ReadString(r);

            if (fieldName == null)
            {
                throw new ParseException("Parse error: Invalid 'HEADER' field-name value.");
            }
            string value = IMAP_Utils.ReadString(r);

            if (value == null)
            {
                throw new ParseException("Parse error: Invalid 'HEADER' string value.");
            }

            return(new IMAP_Search_Key_Header(fieldName, value));
        }
Beispiel #7
0
        /// <summary>
        /// Encodes mailbox name.
        /// </summary>
        /// <param name="mailbox">Mailbox name.</param>
        /// <param name="encoding">Mailbox name encoding mechanism.</param>
        /// <returns>Renturns encoded mailbox name.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>mailbox</b> is null reference.</exception>
        public static string EncodeMailbox(string mailbox, IMAP_Mailbox_Encoding encoding)
        {
            if (mailbox == null)
            {
                throw new ArgumentNullException("mailbox");
            }

            /* RFC 5738 3.
             *  string        =/ utf8-quoted
             *  utf8-quoted   = "*" DQUOTE *UQUOTED-CHAR DQUOTE
             *  UQUOTED-CHAR  = QUOTED-CHAR / UTF8-2 / UTF8-3 / UTF8-4
             */

            if (encoding == IMAP_Mailbox_Encoding.ImapUtf7)
            {
                return("\"" + IMAP_Utils.Encode_IMAP_UTF7_String(mailbox) + "\"");
            }
            else if (encoding == IMAP_Mailbox_Encoding.ImapUtf8)
            {
                return("*\"" + mailbox + "\"");
            }
            else
            {
                return("\"" + mailbox + "\"");
            }
        }
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* STATUS");
            retVal.Append(" " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            retVal.Append(" (");
            bool firstItem = true;

            if (m_MessageCount >= 0)
            {
                retVal.Append("MESSAGES " + m_MessageCount);
                firstItem = false;
            }
            if (m_RecentCount >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("RECENT " + m_RecentCount);
                firstItem = false;
            }
            if (m_UidNext >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("UIDNEXT " + m_UidNext);
                firstItem = false;
            }
            if (m_FolderUid >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("UIDVALIDITY " + m_FolderUid);
                firstItem = false;
            }
            if (m_UnseenCount >= 0)
            {
                if (!firstItem)
                {
                    retVal.Append(' ');
                }
                retVal.Append("UNSEEN " + m_UnseenCount);
                firstItem = false;
            }
            retVal.Append(")\r\n");

            return(retVal.ToString());
        }
Beispiel #9
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * MYRIGHTS INBOX rwiptsldaex

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* MYRIGHTS " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding) + " \"" + m_pRights + "\"\r\n");

            return(retVal.ToString());
        }
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * LISTRIGHTS ~/Mail/saved smith la r swicdkxte

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* LISTRIGHTS " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding) + " \"" + m_RequiredRights + "\" " + m_OptionalRights + "\r\n");

            return(retVal.ToString());
        }
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * QUOTAROOT INBOX ""

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* QUOTAROOT " + IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            foreach (string root in m_QuotaRoots)
            {
                retVal.Append(" \"" + root + "\"");
            }
            retVal.Append("\r\n");

            return(retVal.ToString());
        }
        /// <summary>
        /// Parses LISTRIGHTS response from LISTRIGHTS-response string.
        /// </summary>
        /// <param name="listRightsResponse">LISTRIGHTS response line.</param>
        /// <returns>Returns parsed LISTRIGHTS response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>listRightsResponse</b> is null reference.</exception>
        public static IMAP_r_u_ListRights Parse(string listRightsResponse)
        {
            if (listRightsResponse == null)
            {
                throw new ArgumentNullException("listRightsResponse");
            }

            /* RFC 4314 3.7. LISTRIGHTS Response.
             *  Data:       mailbox name
             *              identifier
             *              required rights
             *              list of optional rights
             *
             *  The LISTRIGHTS response occurs as a result of a LISTRIGHTS command.
             *  The first two strings are the mailbox name and identifier for which
             *  this rights list applies.  Following the identifier is a string
             *  containing the (possibly empty) set of rights the identifier will
             *  always be granted in the mailbox.
             *
             *  Following this are zero or more strings each containing a set of
             *  rights the identifier can be granted in the mailbox.  Rights
             *  mentioned in the same string are tied together.  The server MUST
             *  either grant all tied rights to the identifier in the mailbox or
             *  grant none.  Section 2.1.1 details additional server requirements
             *  related to handling of the virtual "d" and "c" rights.
             *
             *  The same right MUST NOT be listed more than once in the LISTRIGHTS
             *  command.
             *
             *  Example:    C: a001 LISTRIGHTS ~/Mail/saved smith
             *              S: * LISTRIGHTS ~/Mail/saved smith la r swicdkxte
             *              S: a001 OK Listrights completed
             */

            StringReader r = new StringReader(listRightsResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "LISTRIGHTS"
            r.ReadWord();

            string folder     = IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord(true));
            string identifier = r.ReadWord(true);
            string reqRights  = r.ReadWord(true);
            string optRights  = r.ReadWord(true);

            return(new IMAP_r_u_ListRights(folder, identifier, reqRights, optRights));
        }
Beispiel #13
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            // Example:    S: * ACL INBOX Fred rwipslda test rwipslda

            StringBuilder retVal = new StringBuilder();

            retVal.Append("* ACL ");
            retVal.Append(IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
            foreach (IMAP_Acl_Entry e in m_pEntries)
            {
                retVal.Append(" \"" + e.Identifier + "\" \"" + e.Rights + "\"");
            }
            retVal.Append("\r\n");

            return(retVal.ToString());
        }
        /// <summary>
        /// Parses QUOTAROOT response from quotaRoot-response string.
        /// </summary>
        /// <param name="response">QUOTAROOT response string.</param>
        /// <returns>Returns parsed QUOTAROOT response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public static IMAP_r_u_QuotaRoot Parse(string response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            /* RFC 2087 5.2. QUOTAROOT Response.
             *  Data:       mailbox name
             *              zero or more quota root names
             *
             *  This response occurs as a result of a GETQUOTAROOT command.  The
             *  first string is the mailbox and the remaining strings are the
             *  names of the quota roots for the mailbox.
             *
             *  Example:    S: * QUOTAROOT INBOX ""
             *              S: * QUOTAROOT comp.mail.mime
             */

            StringReader r = new StringReader(response);

            // Eat "*"
            r.ReadWord();
            // Eat "QUOTAROOT"
            r.ReadWord();

            string        folderName = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord()));
            List <string> quotaRoots = new List <string>();

            while (r.Available > 0)
            {
                string quotaRoot = r.ReadWord();
                if (quotaRoot != null)
                {
                    quotaRoots.Add(quotaRoot);
                }
                else
                {
                    break;
                }
            }

            return(new IMAP_r_u_QuotaRoot(folderName, quotaRoots.ToArray()));
        }
Beispiel #15
0
        /// <summary>
        /// Parses ACL response from acl-response string.
        /// </summary>
        /// <param name="aclResponse">ACL response.</param>
        /// <returns>Returns parsed ACL response.</returns>
        /// <exception cref="ArgumentNullException">Is raised wehn <b>aclResponse</b> is null reference.</exception>
        public static IMAP_r_u_Acl Parse(string aclResponse)
        {
            if (aclResponse == null)
            {
                throw new ArgumentNullException("aclResponse");
            }

            /* RFC 4314 3.6. ACL Response.
             *  Data:       mailbox name
             *              zero or more identifier rights pairs
             *
             *  The ACL response occurs as a result of a GETACL command.  The first
             *  string is the mailbox name for which this ACL applies.  This is
             *  followed by zero or more pairs of strings; each pair contains the
             *  identifier for which the entry applies followed by the set of rights
             *  that the identifier has.
             *
             *  Example:    C: A002 GETACL INBOX
             *              S: * ACL INBOX Fred rwipsldexta
             *              S: A002 OK Getacl complete
             */

            StringReader r = new StringReader(aclResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "ACL"
            r.ReadWord();

            string folderName = TextUtils.UnQuoteString(IMAP_Utils.Decode_IMAP_UTF7_String(r.ReadWord()));

            string[] items = r.ReadToEnd().Split(' ');
            List <IMAP_Acl_Entry> entries = new List <IMAP_Acl_Entry>();

            for (int i = 0; i < items.Length; i += 2)
            {
                entries.Add(new IMAP_Acl_Entry(items[i], items[i + 1]));
            }

            return(new IMAP_r_u_Acl(folderName, entries.ToArray()));
        }
Beispiel #16
0
        /// <summary>
        /// Returns parsed IMAP SEARCH <b>FROM (string)</b> key.
        /// </summary>
        /// <param name="r">String reader.</param>
        /// <returns>Returns parsed IMAP SEARCH <b>FROM (string)</b> key.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>r</b> is null reference.</exception>
        /// <exception cref="ParseException">Is raised when parsing fails.</exception>
        internal static IMAP_Search_Key_From Parse(StringReader r)
        {
            if (r == null)
            {
                throw new ArgumentNullException("r");
            }

            string word = r.ReadWord();

            if (!string.Equals(word, "FROM", StringComparison.InvariantCultureIgnoreCase))
            {
                throw new ParseException("Parse error: Not a SEARCH 'FROM' key.");
            }
            string value = IMAP_Utils.ReadString(r);

            if (value == null)
            {
                throw new ParseException("Parse error: Invalid 'FROM' value.");
            }

            return(new IMAP_Search_Key_From(value));
        }
Beispiel #17
0
        /// <summary>
        /// Returns this as string.
        /// </summary>
        /// <param name="encoding">Specifies how mailbox name is encoded.</param>
        /// <returns>Returns this as string.</returns>
        public override string ToString(IMAP_Mailbox_Encoding encoding)
        {
            /*
             *  Example:  S: * LIST (\Noselect) "/" ~/Mail/foo
             *
             *            C: A101 LIST "" ""
             *            S: * LIST (\Noselect) "/" ""
             *            S: A101 OK LIST Completed
             */

            // Hierarchy delimiter request.
            if (string.IsNullOrEmpty(m_FolderName))
            {
                return("* LIST (\\Noselect) \"/\" \"\"\r\n");
            }
            else
            {
                StringBuilder retVal = new StringBuilder();
                retVal.Append("* LIST (");
                if (m_pFolderAttributes != null)
                {
                    for (int i = 0; i < m_pFolderAttributes.Length; i++)
                    {
                        if (i > 0)
                        {
                            retVal.Append(" ");
                        }
                        retVal.Append(m_pFolderAttributes[i]);
                    }
                }
                retVal.Append(") ");
                retVal.Append("\"" + m_Delimiter + "\" ");
                retVal.Append(IMAP_Utils.EncodeMailbox(m_FolderName, encoding));
                retVal.Append("\r\n");

                return(retVal.ToString());
            }
        }
Beispiel #18
0
        /// <summary>
        /// Parses LIST response from list-response string.
        /// </summary>
        /// <param name="listResponse">List response string.</param>
        /// <returns>Returns parsed list response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>listResponse</b> is null reference.</exception>
        public static IMAP_r_u_List Parse(string listResponse)
        {
            if (listResponse == null)
            {
                throw new ArgumentNullException("listResponse");
            }

            /* RFC 3501 7.2.2. LIST Response.
             *  Contents:   name attributes
             *              hierarchy delimiter
             *              name
             *
             *  The LIST response occurs as a result of a LIST command.  It
             *  returns a single name that matches the LIST specification.  There
             *  can be multiple LIST responses for a single LIST command.
             *
             *  Four name attributes are defined:
             *
             *  \Noinferiors
             *      It is not possible for any child levels of hierarchy to exist
             *      under this name; no child levels exist now and none can be
             *      created in the future.
             *
             *  \Noselect
             *      It is not possible to use this name as a selectable mailbox.
             *
             *  \Marked
             *      The mailbox has been marked "interesting" by the server; the
             *      mailbox probably contains messages that have been added since
             *      the last time the mailbox was selected.
             *
             *  \Unmarked
             *      The mailbox does not contain any additional messages since the
             *      last time the mailbox was selected.
             *
             *  If it is not feasible for the server to determine whether or not
             *  the mailbox is "interesting", or if the name is a \Noselect name,
             *  the server SHOULD NOT send either \Marked or \Unmarked.
             *
             *  The hierarchy delimiter is a character used to delimit levels of
             *  hierarchy in a mailbox name.  A client can use it to create child
             *  mailboxes, and to search higher or lower levels of naming
             *  hierarchy.  All children of a top-level hierarchy node MUST use
             *  the same separator character.  A NIL hierarchy delimiter means
             *  that no hierarchy exists; the name is a "flat" name.
             *
             *  The name represents an unambiguous left-to-right hierarchy, and
             *  MUST be valid for use as a reference in LIST and LSUB commands.
             *  Unless \Noselect is indicated, the name MUST also be valid as an
             *  argument for commands, such as SELECT, that accept mailbox names.
             *
             *  Example:    S: * LIST (\Noselect) "/" ~/Mail/foo
             */

            StringReader r = new StringReader(listResponse);

            // Eat "*"
            r.ReadWord();
            // Eat "LIST"
            r.ReadWord();

            string attributes = r.ReadParenthesized();
            string delimiter  = r.ReadWord();
            string folder     = IMAP_Utils.DecodeMailbox(r.ReadToEnd().Trim());

            return(new IMAP_r_u_List(folder, delimiter[0], attributes == string.Empty ? new string[0] : attributes.Split(' ')));
        }