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)); }
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); }
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); }
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); }