public void TestParseLargeLiteral() { var literal = new ByteStringBuilder(1 * 1024 * 1024); for (var i = 0; i < literal.Capacity; i += 16) { literal.Append("0123456789abcdef"); } WriteReceived(string.Format("{{{0}}}\r\n{1}\r\n", literal.Length, literal.ToString())); var data = receiver.Parse(); Assert.IsNull(data); data = receiver.Parse(); Assert.IsNotNull(data); Assert.AreEqual(1, data.Length); Assert.AreEqual(ImapDataFormat.Text, data[0].Format); var stream = data[0].GetTextAsStream(); Assert.IsNotInstanceOfType(typeof(MemoryStream), stream); Assert.AreEqual(literal.ToByteArray(), Smdn.IO.StreamExtensions.ReadToEnd(stream)); }
private static ImapSearchCriteria FromUri(Uri uri, bool convertLiteral, bool synchronizedLiteral, bool splitCharset, out bool containsLiteral, out string charset) { if (uri == null) throw new ArgumentNullException("uri"); containsLiteral = false; charset = null; var q = uri.Query; if (q.Length == 0) return null; else if (q.Length == 1) // '?' return new ImapSearchCriteria(string.Empty); /* * http://tools.ietf.org/html/rfc5092 * RFC 5092 - IMAP URL Scheme * * Note that quoted strings and non-synchronizing literals [LITERAL+] * are allowed in the <enc-search> content; however, synchronizing * literals are not allowed, as their presence would effectively mean * that the agent interpreting IMAP URLs needs to parse an <enc-search> * content, find all synchronizing literals, and perform proper command * continuation request handling (see Sections 4.3 and 7 of [IMAP4]). */ var query = PercentEncoding.Decode(q.Substring(1), false); var len = query.Length; var convertedQuery = new ByteStringBuilder(len); if (splitCharset) { var queryString = new ByteString(query); if (queryString.StartsWithIgnoreCase(charsetSpecification)) { // CHARSET<SP>astring<SP> var posEndOfCharset = queryString.IndexOf(Octets.SP, charsetSpecification.Length); if (posEndOfCharset < 0) { throw new ArgumentException("search criteria contains invalid charset specification", "uri"); } else { charset = queryString.Substring(charsetSpecification.Length, posEndOfCharset - charsetSpecification.Length).ToString(); query = queryString.Substring(posEndOfCharset + 1).ByteArray; len = query.Length; } } } for (var i = 0; i < len;) { if (query[i] == ImapOctets.DQuote) { /* * quoted */ var start = i; for (;;) { if (++i == len) throw new ArgumentException("search criteria contains unclosed quoted string", "uri"); if (query[i] == ImapOctets.DQuote) { break; } else if (query[i] == ImapOctets.BackSlash) { if (++i == len || !(query[i] == ImapOctets.DQuote || query[i] == ImapOctets.BackSlash)) throw new ArgumentException("search criteria contains invalid quoted string", "uri"); } } i++; convertedQuery.Append(query, start, i - start); } else if (query[i] == ImapOctets.OpenBrace) { /* * literal */ var start = i; var isLiteralSynchronizing = false; var literalLength = 0; for (;;) { if (++i == len) throw new ArgumentException("search criteria contains incomplete literal", "uri"); if (Octets.IsDecimalNumber(query[i])) { literalLength = literalLength * 10 + (query[i] - 0x30 /* '0' */); // TODO: check length } else if (query[i] == ImapOctets.CloseBrace) { // {xxx} isLiteralSynchronizing = true; break; } else if (query[i] == ImapOctets.Plus) { // {xxx+} if (++i == len || query[i] != ImapOctets.CloseBrace) throw new ArgumentException("search criteria contains incomplete non-synchronized literal", "uri"); isLiteralSynchronizing = false; break; } else { throw new ArgumentException("search criteria contains invalid literal", "uri"); } } if (++i == len || query[i] != Octets.CR) throw new ArgumentException("search criteria contains incomplete literal (CR not found)", "uri"); if (++i == len || query[i] != Octets.LF) throw new ArgumentException("search criteria contains incomplete literal (LF not found)", "uri"); if (++i == len && 0 < literalLength) throw new ArgumentException("search criteria contains incomplete literal (unexpected EOL)", "uri"); containsLiteral = true; if (convertLiteral) { if (synchronizedLiteral) convertedQuery.Append(string.Format("{{{0}}}\x0d\x0a", literalLength)); else convertedQuery.Append(string.Format("{{{0}+}}\x0d\x0a", literalLength)); convertedQuery.Append(query, i, literalLength); } else { if (synchronizedLiteral != isLiteralSynchronizing) throw new ArgumentException(synchronizedLiteral ? "search criteria contains non-synchronizing literal" : "search criteria contains synchronizing literal", "uri"); convertedQuery.Append(query, start, i - start + literalLength); } i += literalLength; } else { convertedQuery.Append(query[i++]); } } return new ImapSearchCriteria(new ImapPreformattedString(convertedQuery.ToByteArray())); }