/// <summary> /// Parses an untagged ID response. /// </summary> /// <param name="engine">The IMAP engine.</param> /// <param name="ic">The IMAP command.</param> /// <param name="index">The index.</param> public static void ParseImplementation(ImapEngine engine, ImapCommand ic, int index) { var token = engine.ReadToken(ic.CancellationToken); var implementation = new ImapImplementation(); ic.UserData = implementation; if (token.Type == ImapTokenType.Nil) { return; } if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } token = engine.PeekToken(ic.CancellationToken); while (token.Type != ImapTokenType.CloseParen) { var property = ImapUtils.ReadStringToken(engine, ic.CancellationToken); var value = ImapUtils.ReadNStringToken(engine, false, ic.CancellationToken); implementation.Properties[property] = value; token = engine.PeekToken(ic.CancellationToken); } // read the ')' token engine.ReadToken(ic.CancellationToken); }
static void ParseParameterList(StringBuilder builder, ImapEngine engine, CancellationToken cancellationToken) { ImapToken token; do { token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.CloseParen) { break; } var name = ReadStringToken(engine, cancellationToken); var value = ReadStringToken(engine, cancellationToken); builder.Append("; ").Append(name).Append('='); if (NeedsQuoting(value)) { builder.Append(MimeUtils.Quote(value)); } else { builder.Append(value); } } while (true); // read the ')' engine.ReadToken(cancellationToken); }
/// <summary> /// Parses the threads. /// </summary> /// <returns>The threads.</returns> /// <param name="engine">The IMAP engine.</param> /// <param name="cancellationToken">The cancellation token.</param> public static MessageThread[] ParseThreads(ImapEngine engine, CancellationToken cancellationToken) { var threads = new List <MessageThread> (); ImapToken token; do { token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.Eoln) { break; } token = engine.ReadToken(cancellationToken); if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } threads.Add(ParseThread(engine, cancellationToken)); } while (true); return(threads.ToArray()); }
static void ParseParameterList(StringBuilder builder, ImapEngine engine, CancellationToken cancellationToken) { ImapToken token; do { token = engine.PeekToken (cancellationToken); if (token.Type == ImapTokenType.CloseParen) break; var name = ReadStringToken (engine, cancellationToken); // Note: technically, the value should also be a 'string' token and not an 'nstring', // but issue #124 reveals a server that is sending NIL for boundary values. var value = ReadNStringToken (engine, false, cancellationToken) ?? string.Empty; builder.Append ("; ").Append (name).Append ('='); if (NeedsQuoting (value)) builder.Append (MimeUtils.Quote (value)); else builder.Append (value); } while (true); // read the ')' engine.ReadToken (cancellationToken); }
static void SkipBodyExtensions(ImapEngine engine, CancellationToken cancellationToken) { var token = engine.ReadToken (cancellationToken); switch (token.Type) { case ImapTokenType.OpenParen: do { token = engine.PeekToken (cancellationToken); if (token.Type == ImapTokenType.CloseParen) break; SkipBodyExtensions (engine, cancellationToken); } while (true); // read the ')' engine.ReadToken (cancellationToken); break; case ImapTokenType.Literal: engine.ReadLiteral (cancellationToken); break; case ImapTokenType.QString: case ImapTokenType.Atom: case ImapTokenType.Nil: break; default: throw ImapEngine.UnexpectedToken (token, false); } }
static string[] ParseContentLocation(ImapEngine engine, CancellationToken cancellationToken) { var token = engine.ReadToken(cancellationToken); var languages = new List <string> (); string language; switch (token.Type) { case ImapTokenType.Literal: language = engine.ReadLiteral(cancellationToken); languages.Add(language); break; case ImapTokenType.QString: case ImapTokenType.Atom: language = (string)token.Value; languages.Add(language); break; case ImapTokenType.Nil: return(null); case ImapTokenType.OpenParen: do { token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.CloseParen) { break; } language = ReadStringToken(engine, cancellationToken); languages.Add(language); } while (true); // read the ')' engine.ReadToken(cancellationToken); break; default: throw ImapEngine.UnexpectedToken(token, false); } return(languages.ToArray()); }
public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken) { var token = engine.ReadToken(cancellationToken); if (token.Type == ImapTokenType.Nil) { return(null); } if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.OpenParen) { return(ParseMultipart(engine, path, cancellationToken)); } var type = ParseContentType(engine, cancellationToken); var id = ReadNStringToken(engine, false, cancellationToken); var desc = ReadNStringToken(engine, true, cancellationToken); var enc = ReadStringToken(engine, cancellationToken); var octets = ReadNumber(engine, cancellationToken); BodyPartBasic body; if (type.Matches("message", "rfc822")) { var mesg = new BodyPartMessage(); mesg.Envelope = ParseEnvelope(engine, cancellationToken); mesg.Body = ParseBody(engine, path, cancellationToken); mesg.Lines = ReadNumber(engine, cancellationToken); body = mesg; } else if (type.Matches("text", "*")) { var text = new BodyPartText(); text.Lines = ReadNumber(engine, cancellationToken); body = text; } else { body = new BodyPartBasic(); } body.ContentTransferEncoding = enc; body.ContentDescription = desc; body.PartSpecifier = path; body.ContentType = type; body.ContentId = id; body.Octets = octets; // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')' token = engine.PeekToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { body.ContentMd5 = ReadNStringToken(engine, false, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentDisposition = ParseContentDisposition(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLanguage = ParseContentLocation(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLocation = ReadNStringToken(engine, false, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { SkipBodyExtensions(engine, cancellationToken); } // read the ')' token = engine.ReadToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { throw ImapEngine.UnexpectedToken(token, false); } return(body); }
static BodyPart ParseMultipart(ImapEngine engine, string path, CancellationToken cancellationToken) { var prefix = path.Length > 0 ? path + "." : string.Empty; var body = new BodyPartMultipart(); ImapToken token; int index = 1; do { body.BodyParts.Add(ParseBody(engine, prefix + index, cancellationToken)); token = engine.PeekToken(cancellationToken); index++; } while (token.Type == ImapTokenType.OpenParen); var subtype = ReadStringToken(engine, cancellationToken); body.ContentType = new ContentType("multipart", subtype); body.PartSpecifier = path; token = engine.PeekToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { token = engine.ReadToken(cancellationToken); if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } var builder = new StringBuilder(); ContentType contentType; builder.AppendFormat("{0}/{1}", body.ContentType.MediaType, body.ContentType.MediaSubtype); ParseParameterList(builder, engine, cancellationToken); if (ContentType.TryParse(builder.ToString(), out contentType)) { body.ContentType = contentType; } token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentDisposition = ParseContentDisposition(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLanguage = ParseContentLocation(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLocation = ReadNStringToken(engine, false, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { SkipBodyExtensions(engine, cancellationToken); } // read the ')' token = engine.ReadToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { throw ImapEngine.UnexpectedToken(token, false); } return(body); }
public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken) { var token = engine.ReadToken(cancellationToken); if (token.Type == ImapTokenType.Nil) { return(null); } if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.OpenParen) { return(ParseMultipart(engine, path, cancellationToken)); } var type = ParseContentType(engine, cancellationToken); var id = ReadNStringToken(engine, false, cancellationToken); var desc = ReadNStringToken(engine, true, cancellationToken); // Note: technically, body-fld-enc, is not allowed to be NIL, but we need to deal with broken servers... var enc = ReadNStringToken(engine, false, cancellationToken); var octets = ReadNumber(engine, cancellationToken); BodyPartBasic body; if (type.Matches("message", "rfc822")) { var mesg = new BodyPartMessage(); // Note: GMail's support for message/rfc822 body parts is broken. Essentially, // GMail treats message/rfc822 parts as if they were basic body parts. // // For examples, see issue #32 and issue #59. // // The workaround is to check for the expected '(' signifying an envelope token. // If we do not get an '(', then we are likely looking at the Content-MD5 token // which gets handled below. token = engine.PeekToken(cancellationToken); if (!engine.IsGMail || token.Type == ImapTokenType.OpenParen) { mesg.Envelope = ParseEnvelope(engine, cancellationToken); mesg.Body = ParseBody(engine, path, cancellationToken); mesg.Lines = ReadNumber(engine, cancellationToken); } body = mesg; } else if (type.Matches("text", "*")) { var text = new BodyPartText(); text.Lines = ReadNumber(engine, cancellationToken); body = text; } else { body = new BodyPartBasic(); } body.ContentTransferEncoding = enc; body.ContentDescription = desc; body.PartSpecifier = path; body.ContentType = type; body.ContentId = id; body.Octets = octets; // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')' token = engine.PeekToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { body.ContentMd5 = ReadNStringToken(engine, false, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentDisposition = ParseContentDisposition(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLanguage = ParseContentLanguage(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLocation = ParseContentLocation(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { SkipBodyExtensions(engine, cancellationToken); } // read the ')' token = engine.ReadToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { throw ImapEngine.UnexpectedToken(token, false); } return(body); }
public static BodyPart ParseBody(ImapEngine engine, string path, CancellationToken cancellationToken) { var token = engine.ReadToken(cancellationToken); if (token.Type == ImapTokenType.Nil) { return(null); } if (token.Type != ImapTokenType.OpenParen) { throw ImapEngine.UnexpectedToken(token, false); } token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.OpenParen) { return(ParseMultipart(engine, path, cancellationToken)); } var type = ParseContentType(engine, cancellationToken); var id = ReadNStringToken(engine, false, cancellationToken); var desc = ReadNStringToken(engine, true, cancellationToken); // Note: technically, body-fld-enc, is not allowed to be NIL, but we need to deal with broken servers... var enc = ReadNStringToken(engine, false, cancellationToken); var octets = ReadNumber(engine, cancellationToken); BodyPartBasic body; if (type.Matches("message", "rfc822")) { var mesg = new BodyPartMessage(); // Note: GMail (and potentially other IMAP servers) will send body-part-basic // expressions instead of body-part-msg expressions when they encounter // message/rfc822 MIME parts that are illegally encoded using base64 (or // quoted-printable?). According to rfc3501, IMAP servers are REQUIRED to // send body-part-msg expressions for message/rfc822 parts, however, it is // understandable why GMail (and other IMAP servers?) do what they do in this // particular case. // // For examples, see issue #32 and issue #59. // // The workaround is to check for the expected '(' signifying an envelope token. // If we do not get an '(', then we are likely looking at the Content-MD5 token // which gets handled below. token = engine.PeekToken(cancellationToken); if (token.Type == ImapTokenType.OpenParen) { mesg.Envelope = ParseEnvelope(engine, cancellationToken); mesg.Body = ParseBody(engine, path, cancellationToken); mesg.Lines = ReadNumber(engine, cancellationToken); } body = mesg; } else if (type.Matches("text", "*")) { var text = new BodyPartText(); text.Lines = ReadNumber(engine, cancellationToken); body = text; } else { body = new BodyPartBasic(); } body.ContentTransferEncoding = enc; body.ContentDescription = desc; body.PartSpecifier = path; body.ContentType = type; body.ContentId = id; body.Octets = octets; // if we are parsing a BODYSTRUCTURE, we may get some more tokens before the ')' token = engine.PeekToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { body.ContentMd5 = ReadNStringToken(engine, false, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentDisposition = ParseContentDisposition(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLanguage = ParseContentLanguage(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { body.ContentLocation = ParseContentLocation(engine, cancellationToken); token = engine.PeekToken(cancellationToken); } if (token.Type != ImapTokenType.CloseParen) { SkipBodyExtensions(engine, cancellationToken); } // read the ')' token = engine.ReadToken(cancellationToken); if (token.Type != ImapTokenType.CloseParen) { throw ImapEngine.UnexpectedToken(token, false); } return(body); }