示例#1
0
        public void TestMessageLabelsChangedEventArgs()
        {
            var labels = new string[] { "label1", "label2" };
            MessageLabelsChangedEventArgs args;
            var   uid    = new UniqueId(5);
            ulong modseq = 724;

            args = new MessageLabelsChangedEventArgs(0);
            Assert.IsNull(args.Labels);
            Assert.IsFalse(args.UniqueId.HasValue);
            Assert.IsFalse(args.ModSeq.HasValue);
            Assert.AreEqual(0, args.Index);

            args = new MessageLabelsChangedEventArgs(0, labels);
            Assert.AreEqual(labels.Length, args.Labels.Count);
            Assert.IsFalse(args.UniqueId.HasValue);
            Assert.IsFalse(args.ModSeq.HasValue);
            Assert.AreEqual(0, args.Index);

            args = new MessageLabelsChangedEventArgs(0, labels, modseq);
            Assert.AreEqual(labels.Length, args.Labels.Count);
            Assert.IsFalse(args.UniqueId.HasValue);
            Assert.AreEqual(modseq, args.ModSeq);
            Assert.AreEqual(0, args.Index);

            args = new MessageLabelsChangedEventArgs(0, uid, labels);
            Assert.AreEqual(labels.Length, args.Labels.Count);
            Assert.AreEqual(uid, args.UniqueId);
            Assert.IsFalse(args.ModSeq.HasValue);
            Assert.AreEqual(0, args.Index);

            args = new MessageLabelsChangedEventArgs(0, uid, labels, modseq);
            Assert.AreEqual(labels.Length, args.Labels.Count);
            Assert.AreEqual(uid, args.UniqueId);
            Assert.AreEqual(modseq, args.ModSeq);
            Assert.AreEqual(0, args.Index);

            Assert.Throws <ArgumentOutOfRangeException> (() => new MessageLabelsChangedEventArgs(-1));
            Assert.Throws <ArgumentOutOfRangeException> (() => new MessageLabelsChangedEventArgs(-1, labels));
            Assert.Throws <ArgumentOutOfRangeException> (() => new MessageLabelsChangedEventArgs(-1, labels, modseq));
            Assert.Throws <ArgumentOutOfRangeException> (() => new MessageLabelsChangedEventArgs(-1, uid, labels));
            Assert.Throws <ArgumentOutOfRangeException> (() => new MessageLabelsChangedEventArgs(-1, uid, labels, modseq));

            Assert.Throws <ArgumentNullException> (() => new MessageLabelsChangedEventArgs(0, null));
            Assert.Throws <ArgumentNullException> (() => new MessageLabelsChangedEventArgs(0, null, modseq));
            Assert.Throws <ArgumentNullException> (() => new MessageLabelsChangedEventArgs(0, uid, null));
            Assert.Throws <ArgumentNullException> (() => new MessageLabelsChangedEventArgs(0, uid, null, modseq));
        }
示例#2
0
		void FetchStream (ImapEngine engine, ImapCommand ic, int index)
		{
			var token = engine.ReadToken (ic.CancellationToken);
			var labels = new MessageLabelsChangedEventArgs (index);
			var flags = new MessageFlagsChangedEventArgs (index);
			var ctx = (FetchStreamContext) ic.UserData;
			var section = new StringBuilder ();
			bool labelsChanged = false;
			bool flagsChanged = false;
			var buf = new byte[4096];
			long nread = 0, size = 0;
			UniqueId? uid = null;
			Stream stream;
			int n;

			if (token.Type != ImapTokenType.OpenParen)
				throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);

			do {
				token = engine.ReadToken (ic.CancellationToken);

				if (token.Type == ImapTokenType.CloseParen || token.Type == ImapTokenType.Eoln)
					break;

				if (token.Type != ImapTokenType.Atom)
					throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);

				var atom = (string) token.Value;
				int offset = 0, length;
				ulong modseq;
				uint value;

				switch (atom) {
				case "BODY":
					token = engine.ReadToken (ic.CancellationToken);

					if (token.Type != ImapTokenType.OpenBracket)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					section.Clear ();

					do {
						token = engine.ReadToken (ic.CancellationToken);

						if (token.Type == ImapTokenType.CloseBracket)
							break;

						if (token.Type == ImapTokenType.OpenParen) {
							section.Append (" (");

							do {
								token = engine.ReadToken (ic.CancellationToken);

								if (token.Type == ImapTokenType.CloseParen)
									break;

								// the header field names will generally be atoms or qstrings but may also be literals
								switch (token.Type) {
								case ImapTokenType.Literal:
									section.Append (engine.ReadLiteral (ic.CancellationToken));
									section.Append (' ');
									break;
								case ImapTokenType.QString:
								case ImapTokenType.Atom:
									section.Append ((string) token.Value);
									break;
								default:
									throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
								}
							} while (true);

							if (section[section.Length - 1] == ' ')
								section.Length--;

							section.Append (')');
						} else if (token.Type != ImapTokenType.Atom) {
							throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
						} else {
							section.Append ((string) token.Value);
						}
					} while (true);

					if (token.Type != ImapTokenType.CloseBracket)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					token = engine.ReadToken (ic.CancellationToken);

					if (token.Type == ImapTokenType.Atom) {
						// this might be a region ("<###>")
						var expr = (string) token.Value;

						if (expr.Length > 2 && expr[0] == '<' && expr[expr.Length - 1] == '>') {
							var region = expr.Substring (1, expr.Length - 2);
							int.TryParse (region, out offset);

							token = engine.ReadToken (ic.CancellationToken);
						}
					}

					switch (token.Type) {
					case ImapTokenType.Literal:
						length = (int) token.Value;
						size += length;

						stream = CreateStream (uid, section.ToString (), offset, length);

						try {
							while ((n = engine.Stream.Read (buf, 0, buf.Length, ic.CancellationToken)) > 0) {
								stream.Write (buf, 0, n);
								nread += n;

								ctx.Report (nread, size);
							}

							stream.Position = 0;
						} catch {
							stream.Dispose ();
							throw;
						}
						break;
					case ImapTokenType.QString:
					case ImapTokenType.Atom:
						var buffer = Encoding.UTF8.GetBytes ((string) token.Value);
						length = buffer.Length;
						nread += length;
						size += length;

						stream = CreateStream (uid, section.ToString (), offset, length);

						try {
							stream.Write (buffer, 0, length);
							ctx.Report (nread, size);
							stream.Position = 0;
						} catch {
							stream.Dispose ();
							throw;
						}
						break;
					case ImapTokenType.Nil:
						stream = CreateStream (uid, section.ToString (), offset, 0);
						break;
					default:
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
					}

					if (uid.HasValue)
						ctx.Sections[section.ToString ()] = CommitStream (stream, uid.Value);
					else
						ctx.Sections[section.ToString ()] = stream;

					break;
				case "UID":
					token = engine.ReadToken (ic.CancellationToken);

					if (token.Type != ImapTokenType.Atom || !uint.TryParse ((string) token.Value, out value) || value == 0)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					uid = new UniqueId (UidValidity, value);

					foreach (var key in ctx.Sections.Keys.ToArray ())
						ctx.Sections[key] = CommitStream (ctx.Sections[key], uid.Value);

					labels.UniqueId = uid.Value;
					flags.UniqueId = uid.Value;
					break;
				case "MODSEQ":
					token = engine.ReadToken (ic.CancellationToken);

					if (token.Type != ImapTokenType.OpenParen)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					token = engine.ReadToken (ic.CancellationToken);

					if (token.Type != ImapTokenType.Atom || !ulong.TryParse ((string) token.Value, out modseq))
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					token = engine.ReadToken (ic.CancellationToken);

					if (token.Type != ImapTokenType.CloseParen)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					labels.ModSeq = modseq;
					flags.ModSeq = modseq;
					break;
				case "FLAGS":
					// even though we didn't request this piece of information, the IMAP server
					// may send it if another client has recently modified the message flags.
					flags.Flags = ImapUtils.ParseFlagsList (engine, atom, flags.UserFlags, ic.CancellationToken);
					flagsChanged = true;
					break;
				case "X-GM-LABELS":
					// even though we didn't request this piece of information, the IMAP server
					// may send it if another client has recently modified the message labels.
					labels.Labels = ImapUtils.ParseLabelsList (engine, ic.CancellationToken);
					labelsChanged = true;
					break;
				default:
					throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
				}
			} while (true);

			if (token.Type != ImapTokenType.CloseParen)
				throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);

			if (flagsChanged)
				ic.Folder.OnMessageFlagsChanged (flags);

			if (labelsChanged)
				ic.Folder.OnMessageLabelsChanged (labels);
		}
示例#3
0
		internal void OnFetch (ImapEngine engine, int index, CancellationToken cancellationToken)
		{
			var labels = new MessageLabelsChangedEventArgs (index);
			var flags = new MessageFlagsChangedEventArgs (index);
			var token = engine.ReadToken (cancellationToken);
			bool labelsChanged = false;
			bool flagsChanged = false;

			if (token.Type != ImapTokenType.OpenParen)
				throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);

			do {
				token = engine.ReadToken (cancellationToken);

				if (token.Type == ImapTokenType.CloseParen || token.Type == ImapTokenType.Eoln)
					break;

				if (token.Type != ImapTokenType.Atom)
					throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);

				var atom = (string) token.Value;
				ulong modseq;
				uint uid;

				switch (atom) {
				case "MODSEQ":
					token = engine.ReadToken (cancellationToken);

					if (token.Type != ImapTokenType.OpenParen)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					token = engine.ReadToken (cancellationToken);

					if (token.Type != ImapTokenType.Atom || !ulong.TryParse ((string) token.Value, out modseq))
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					token = engine.ReadToken (cancellationToken);

					if (token.Type != ImapTokenType.CloseParen)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					labels.ModSeq = modseq;
					flags.ModSeq = modseq;
					break;
				case "UID":
					token = engine.ReadToken (cancellationToken);

					if (token.Type != ImapTokenType.Atom || !uint.TryParse ((string) token.Value, out uid) || uid == 0)
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					labels.UniqueId = new UniqueId (UidValidity, uid);
					flags.UniqueId = new UniqueId (UidValidity, uid);
					break;
				case "FLAGS":
					flags.Flags = ImapUtils.ParseFlagsList (engine, atom, flags.UserFlags, cancellationToken);
					flagsChanged = true;
					break;
				case "X-GM-LABELS":
					labels.Labels = ImapUtils.ParseLabelsList (engine, cancellationToken);
					labelsChanged = true;
					break;
				default:
					throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
				}
			} while (true);

			if (token.Type != ImapTokenType.CloseParen)
				throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);

			if (flagsChanged)
				OnMessageFlagsChanged (flags);

			if (labelsChanged)
				OnMessageLabelsChanged (labels);
		}
示例#4
0
        static void FetchMessageBody(ImapEngine engine, ImapCommand ic, int index)
        {
            var streams = (Dictionary<string, Stream>) ic.UserData;
            var token = engine.ReadToken (ic.CancellationToken);
            var labels = new MessageLabelsChangedEventArgs (index);
            var flags = new MessageFlagsChangedEventArgs (index);
            bool labelsChanged = false;
            bool flagsChanged = false;
            var buf = new byte[4096];
            string specifier;
            Stream stream;
            int nread;

            if (token.Type != ImapTokenType.OpenParen)
                throw ImapEngine.UnexpectedToken (token, false);

            do {
                token = engine.ReadToken (ic.CancellationToken);

                if (token.Type == ImapTokenType.CloseParen || token.Type == ImapTokenType.Eoln)
                    break;

                if (token.Type != ImapTokenType.Atom)
                    throw ImapEngine.UnexpectedToken (token, false);

                var atom = (string) token.Value;
                ulong modseq;
                uint uid;

                switch (atom) {
                case "BODY":
                    token = engine.ReadToken (ic.CancellationToken);

                    if (token.Type != ImapTokenType.OpenBracket)
                        throw ImapEngine.UnexpectedToken (token, false);

                    specifier = string.Empty;

                    do {
                        token = engine.ReadToken (ic.CancellationToken);

                        if (token.Type == ImapTokenType.CloseBracket)
                            break;

                        if (token.Type == ImapTokenType.OpenParen) {
                            do {
                                token = engine.ReadToken (ic.CancellationToken);

                                if (token.Type == ImapTokenType.CloseParen)
                                    break;

                                if (token.Type != ImapTokenType.Atom)
                                    throw ImapEngine.UnexpectedToken (token, false);
                            } while (true);
                        } else if (token.Type != ImapTokenType.Atom) {
                            throw ImapEngine.UnexpectedToken (token, false);
                        } else {
                            specifier += (string) token.Value;
                        }
                    } while (true);

                    if (token.Type != ImapTokenType.CloseBracket)
                        throw ImapEngine.UnexpectedToken (token, false);

                    token = engine.ReadToken (ic.CancellationToken);

                    if (token.Type == ImapTokenType.Atom) {
                        var region = (string) token.Value;

                        if (region[0] != '<' || region[region.Length - 1] != '>')
                            throw ImapEngine.UnexpectedToken (token, false);

                        token = engine.ReadToken (ic.CancellationToken);
                    }

                    switch (token.Type) {
                    case ImapTokenType.Literal:
                        stream = new MemoryBlockStream ();

                        while ((nread = engine.Stream.Read (buf, 0, buf.Length, ic.CancellationToken)) > 0)
                            stream.Write (buf, 0, nread);

                        streams[specifier] = stream;
                        stream.Position = 0;
                        break;
                    case ImapTokenType.QString:
                    case ImapTokenType.Atom:
                        stream = new MemoryStream (Encoding.UTF8.GetBytes ((string) token.Value), false);
                        break;
                    default:
                        throw ImapEngine.UnexpectedToken (token, false);
                    }

                    break;
                case "UID":
                    token = engine.ReadToken (ic.CancellationToken);

                    if (token.Type != ImapTokenType.Atom || !uint.TryParse ((string) token.Value, out uid) || uid == 0)
                        throw ImapEngine.UnexpectedToken (token, false);

                    labels.UniqueId = new UniqueId (uid);
                    flags.UniqueId = new UniqueId (uid);
                    break;
                case "MODSEQ":
                    token = engine.ReadToken (ic.CancellationToken);

                    if (token.Type != ImapTokenType.OpenParen)
                        throw ImapEngine.UnexpectedToken (token, false);

                    token = engine.ReadToken (ic.CancellationToken);

                    if (token.Type != ImapTokenType.Atom || !ulong.TryParse ((string) token.Value, out modseq) || modseq == 0)
                        throw ImapEngine.UnexpectedToken (token, false);

                    token = engine.ReadToken (ic.CancellationToken);

                    if (token.Type != ImapTokenType.CloseParen)
                        throw ImapEngine.UnexpectedToken (token, false);

                    labels.ModSeq = modseq;
                    flags.ModSeq = modseq;
                    break;
                case "FLAGS":
                    // even though we didn't request this piece of information, the IMAP server
                    // may send it if another client has recently modified the message flags.
                    flags.Flags = ImapUtils.ParseFlagsList (engine, flags.UserFlags, ic.CancellationToken);
                    flagsChanged = true;
                    break;
                case "X-GM-LABELS":
                    // even though we didn't request this piece of information, the IMAP server
                    // may send it if another client has recently modified the message labels.
                    labels.Labels = ImapUtils.ParseLabelsList (engine, ic.CancellationToken);
                    labelsChanged = true;
                    break;
                default:
                    throw ImapEngine.UnexpectedToken (token, false);
                }
            } while (true);

            if (token.Type != ImapTokenType.CloseParen)
                throw ImapEngine.UnexpectedToken (token, false);

            if (flagsChanged)
                ic.Folder.OnMessageFlagsChanged (flags);

            if (labelsChanged)
                ic.Folder.OnMessageLabelsChanged (labels);
        }