Ejemplo n.º 1
0
		void FetchSummaryItems (ImapEngine engine, ImapCommand ic, int index)
		{
			var token = engine.ReadToken (ic.CancellationToken);

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

			var ctx = (FetchSummaryContext) ic.UserData;
			IMessageSummary isummary;
			MessageSummary summary;

			if (!ctx.Results.TryGetValue (index, out isummary)) {
				summary = new MessageSummary (index);
				ctx.Results.Add (index, summary);
			} else {
				summary = (MessageSummary) isummary;
			}

			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;
				string format;
				ulong value64;
				uint value;
				int idx;

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

					switch (token.Type) {
					case ImapTokenType.QString:
					case ImapTokenType.Atom:
						summary.InternalDate = ImapUtils.ParseInternalDate ((string) token.Value);
						break;
					case ImapTokenType.Nil:
						summary.InternalDate = null;
						break;
					default:
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);
					}

					summary.Fields |= MessageSummaryItems.InternalDate;
					break;
				case "RFC822.SIZE":
					token = engine.ReadToken (ic.CancellationToken);

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

					summary.Fields |= MessageSummaryItems.MessageSize;
					summary.Size = value;
					break;
				case "BODYSTRUCTURE":
					format = string.Format (ImapEngine.GenericItemSyntaxErrorFormat, "BODYSTRUCTURE", "{0}");
					summary.Body = ImapUtils.ParseBody (engine, format, string.Empty, ic.CancellationToken);
					summary.Fields |= MessageSummaryItems.BodyStructure;
					break;
				case "BODY":
					token = engine.PeekToken (ic.CancellationToken);

					if (token.Type == ImapTokenType.OpenBracket) {
						// consume the '['
						token = engine.ReadToken (ic.CancellationToken);

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

						// References and/or other headers were requested...

						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;

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

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

						token = engine.ReadToken (ic.CancellationToken);

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

						summary.References = new MessageIdList ();

						try {
							summary.Headers = engine.ParseHeaders (engine.Stream, ic.CancellationToken);
						} catch (FormatException) {
							// consume any remaining literal data...
							ReadLiteralData (engine, ic.CancellationToken);
							summary.Headers = new HeaderList ();
						}

						if ((idx = summary.Headers.IndexOf (HeaderId.References)) != -1) {
							var references = summary.Headers[idx];
							var rawValue = references.RawValue;

							foreach (var msgid in MimeUtils.EnumerateReferences (rawValue, 0, rawValue.Length))
								summary.References.Add (msgid);
						}

						summary.Fields |= MessageSummaryItems.References;
					} else {
						summary.Fields |= MessageSummaryItems.Body;

						try {
							format = string.Format (ImapEngine.GenericItemSyntaxErrorFormat, "BODY", "{0}");
							summary.Body = ImapUtils.ParseBody (engine, format, string.Empty, ic.CancellationToken);
						} catch (ImapProtocolException ex) {
							if (!ex.UnexpectedToken)
								throw;

							// Note: GMail's IMAP implementation sometimes replies with completely broken BODY values
							// (see issue #32 for the `BODY ("ALTERNATIVE")` example), so to work around this nonsense,
							// we need to drop the remainder of this line.
							do {
								token = engine.PeekToken (ic.CancellationToken);

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

								token = engine.ReadToken (ic.CancellationToken);

								if (token.Type == ImapTokenType.Literal)
									ReadLiteralData (engine, ic.CancellationToken);
							} while (true);

							return;
						}
					}
					break;
				case "ENVELOPE":
					summary.Envelope = ImapUtils.ParseEnvelope (engine, ic.CancellationToken);
					summary.Fields |= MessageSummaryItems.Envelope;
					break;
				case "FLAGS":
					summary.Flags = ImapUtils.ParseFlagsList (engine, atom, summary.UserFlags, ic.CancellationToken);
					summary.Fields |= MessageSummaryItems.Flags;
					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 value64))
						throw ImapEngine.UnexpectedToken (ImapEngine.GenericItemSyntaxErrorFormat, atom, token);

					token = engine.ReadToken (ic.CancellationToken);

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

					summary.Fields |= MessageSummaryItems.ModSeq;
					summary.ModSeq = value64;
					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);

					summary.UniqueId = new UniqueId (ic.Folder.UidValidity, value);
					summary.Fields |= MessageSummaryItems.UniqueId;
					break;
				case "X-GM-MSGID":
					token = engine.ReadToken (ic.CancellationToken);

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

					summary.Fields |= MessageSummaryItems.GMailMessageId;
					summary.GMailMessageId = value64;
					break;
				case "X-GM-THRID":
					token = engine.ReadToken (ic.CancellationToken);

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

					summary.Fields |= MessageSummaryItems.GMailThreadId;
					summary.GMailThreadId = value64;
					break;
				case "X-GM-LABELS":
					summary.GMailLabels = ImapUtils.ParseLabelsList (engine, ic.CancellationToken);
					summary.Fields |= MessageSummaryItems.GMailLabels;
					break;
				default:
					throw ImapEngine.UnexpectedToken (ImapEngine.GenericUntaggedResponseSyntaxErrorFormat, "FETCH", token);
				}
			} while (true);

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

			if ((ctx.RequestedItems & summary.Fields) == ctx.RequestedItems)
				OnMessageSummaryFetched (summary);
		}