From f63a362c9bdfc52aba536d485c13c6dbbfbfdbce Mon Sep 17 00:00:00 2001 From: Thomas Markiewicz Date: Wed, 7 Aug 2019 22:43:40 -0500 Subject: [PATCH 01/10] Added unit tests that duplicate the issues --- lib/imap_client.dart | 2 + lib/src/imap_folder.dart | 5 +- pubspec.yaml | 2 + test/imap_bodystructure_test.dart | 151 ++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+), 2 deletions(-) create mode 100644 test/imap_bodystructure_test.dart diff --git a/lib/imap_client.dart b/lib/imap_client.dart index 35f2df7..5b5ff5f 100644 --- a/lib/imap_client.dart +++ b/lib/imap_client.dart @@ -8,6 +8,8 @@ import 'dart:convert'; import 'package:logging/logging.dart'; +import 'package:meta/meta.dart'; + part "src/buffer_awaiter.dart"; part "src/imap_buffer.dart"; diff --git a/lib/src/imap_folder.dart b/lib/src/imap_folder.dart index 3d1806e..330aad4 100644 --- a/lib/src/imap_folder.dart +++ b/lib/src/imap_folder.dart @@ -145,7 +145,7 @@ class ImapFolder extends _ImapCommandable { ")", untaggedHandlers: { "FETCH": (ImapBuffer buffer, {int number}) async { - await _processFetch(buffer, number, result); + await processFetch(buffer, number, result); } }); return result; @@ -265,7 +265,8 @@ class ImapFolder extends _ImapCommandable { } /// Sorts data retrieved from a fetch response into [result] - void _processFetch(ImapBuffer buffer, int number, Map result) async { + @visibleForTesting + void processFetch(ImapBuffer buffer, int number, Map result) async { result[number] = {}; ImapWord word = await buffer.readWord(expected: ImapWordType.parenOpen); word = await buffer.readWord(); diff --git a/pubspec.yaml b/pubspec.yaml index f0a2f3c..06bd6cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,8 @@ environment: dependencies: logging: ^0.11.3 pedantic: ^1.4.0 + meta: ^1.1.7 dev_dependencies: test: ^1.3.0 + mockito: ^4.1.0 diff --git a/test/imap_bodystructure_test.dart b/test/imap_bodystructure_test.dart new file mode 100644 index 0000000..7a34a00 --- /dev/null +++ b/test/imap_bodystructure_test.dart @@ -0,0 +1,151 @@ +import 'package:imap_client/imap_client.dart'; +import 'package:test/test.dart'; +import 'package:mockito/mockito.dart'; +import 'dart:async'; + +/* +SEE: + * http://sgerwk.altervista.org/imapbodystructure.html + * section: "text + html with images +*/ + +void main() { + var _folder; + var _buffer; + int _number; + var _result; + + setUp(() { + _folder = ImapFolder(null, "TestFolder"); + _buffer = ImapBuffer(); + _number = 0; + _result = Map(); + }); + + test('Can parse body structure of single-part email', () async { + var response = """( + BODYSTRUCTURE("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 1315 42 NIL NIL NIL NIL) + )\n + """; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of text + html', () async { + var response = + """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2234 63 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2987 52 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "d3438gr7324") NIL NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of mail with images', () async { + var response = + """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 119 2 NIL ("INLINE" NIL) NIL)("IMAGE" "JPEG" ("NAME" "4356415.jpg") "<0__=rhksjt>" NIL "BASE64" 143804 NIL ("INLINE" ("FILENAME" "4356415.jpg")) NIL) "RELATED" ("BOUNDARY" "0__=5tgd3d") ("INLINE" NIL) NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of text + html with images', () async { + var response = + """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed") NIL NIL "QUOTED-PRINTABLE" 2815 73 NIL NIL NIL NIL)(("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4171 66 NIL NIL NIL NIL)("IMAGE" "JPEG" ("NAME" "image.jpg") "<3245dsf7435>" NIL "BASE64" 189906 NIL NIL NIL NIL)("IMAGE" "GIF" ("NAME" "other.gif") "<32f6324f>" NIL "BASE64" 1090 NIL NIL NIL NIL) "RELATED" ("BOUNDARY" "--=sdgqgt") NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "--=u5sfrj") NIL NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of mail with images', () async { + var response = + """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of mail with attachment', () async { + var response = + """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4692 69 NIL NIL NIL NIL)("APPLICATION" "PDF" ("NAME" "pages.pdf") NIL NIL "BASE64" 38838 NIL ("attachment" ("FILENAME" "pages.pdf")) NIL NIL) "MIXED" ("BOUNDARY" "----=6fgshr") NIL NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of alternative with attachment', () async { + var response = + """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 403 6 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 421 6 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=fghgf3") NIL NIL NIL)("APPLICATION" "MSWORD" ("NAME" "letter.doc") NIL NIL "BASE64" 110000 NIL ("attachment" ("FILENAME" "letter.doc" "SIZE" "80384")) NIL NIL) "MIXED" ("BOUNDARY" "----=y34fgl") NIL NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test( + 'Can parse body structure of alternative between text and html with images', + () async { + var response = + """(BODYSTRUCTURE (((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 833 30 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 3412 62 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "2__=fgrths") NIL NIL)("IMAGE" "GIF" ("NAME" "485039.gif") "<2__=lgkfjr>" NIL "BASE64" 64 NIL ("INLINE" ("FILENAME" "485039.gif")) NIL) "RELATED" ("BOUNDARY" "1__=fgrths") NIL NIL)("APPLICATION" "PDF" ("NAME" "title.pdf") "<1__=lgkfjr>" NIL "BASE64" 333980 NIL ("ATTACHMENT" ("FILENAME" "title.pdf")) NIL) "MIXED" ("BOUNDARY" "0__=fgrths") NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of single-element lists', () async { + var response = + """(BODYSTRUCTURE (("TEXT" "HTML" NIL NIL NIL "7BIT" 151 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----=rfsewr") NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('Can parse body structure of CASE 3: Text with inline image', () async { + var response = + """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); +} + +/* + + +* 11 FETCH (BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL)) + + + +( + ("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL) + ( + ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL) + ("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL)) + + + + + +SEE: + * http://sgerwk.altervista.org/imapbodystructure.html + * section: "text + html with images + " + +( + "text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL +) +( + ( + "text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL + ) + ( + "image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL + ) + "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL +) +"alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL + + + + + + +( + ( + "TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152 23 + ) + ( + "TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff") "<960723163407.20117h@cac.washington.edu>" "Compiler diff" "BASE64" 4554 73 + ) + "MIXED" +) + +*/ From 7bcd5996eeeafd265477d17d1bc5478556a4cbc0 Mon Sep 17 00:00:00 2001 From: Thomas Markiewicz Date: Thu, 8 Aug 2019 10:29:06 -0500 Subject: [PATCH 02/10] Fixed code and all BODYSTRUCTURE testcases pass now --- lib/src/imap_folder.dart | 43 +++++++++++-- test/imap_bodystructure_test.dart | 101 +++++++----------------------- 2 files changed, 61 insertions(+), 83 deletions(-) diff --git a/lib/src/imap_folder.dart b/lib/src/imap_folder.dart index 330aad4..3bd675f 100644 --- a/lib/src/imap_folder.dart +++ b/lib/src/imap_folder.dart @@ -416,11 +416,16 @@ class ImapFolder extends _ImapCommandable { throw new SyntaxErrorException("Expected number, got $word"); } } else if (word.type == ImapWordType.parenOpen) { - value = new List(); - word = await buffer.readWord(); - while (word.type != ImapWordType.parenClose) { - value.add(word.value); + if (extCount == 1) { + // "DISPOSITION" + value = await _processDispositionSubfields(buffer); + } else { + value = new List(); word = await buffer.readWord(); + while (word.type != ImapWordType.parenClose) { + value.add(word.value); + word = await buffer.readWord(); + } } } else { throw new SyntaxErrorException( @@ -504,6 +509,36 @@ class ImapFolder extends _ImapCommandable { }; } + static Future> _processDispositionSubfields( + ImapBuffer buffer) async { + Map subfieldMap = new Map(); + + // expects prenOpen to be consumes already + ImapWord word = await buffer.readWord(); + while (word.type != ImapWordType.parenClose) { + if (word.type != ImapWordType.nil) { + assert(word.type == ImapWordType.string); + String key = word.value; + word = await buffer.readWord(); + if (word.type != ImapWordType.nil) { + Map values = new Map(); + assert(word.type == ImapWordType.parenOpen); + word = await buffer.readWord(); + while (word.type != ImapWordType.parenClose) { + values[word.value] = + (await buffer.readWord(expected: ImapWordType.string)).value; + word = await buffer.readWord(); + } + subfieldMap.addAll({key: values}); + } + } + + word = await buffer.readWord(); + } + + return subfieldMap; + } + /* Other helpers */ diff --git a/test/imap_bodystructure_test.dart b/test/imap_bodystructure_test.dart index 7a34a00..e84297e 100644 --- a/test/imap_bodystructure_test.dart +++ b/test/imap_bodystructure_test.dart @@ -1,13 +1,5 @@ import 'package:imap_client/imap_client.dart'; import 'package:test/test.dart'; -import 'package:mockito/mockito.dart'; -import 'dart:async'; - -/* -SEE: - * http://sgerwk.altervista.org/imapbodystructure.html - * section: "text + html with images -*/ void main() { var _folder; @@ -22,7 +14,13 @@ void main() { _result = Map(); }); - test('Can parse body structure of single-part email', () async { + /* + Test cases are based on the following examples: + + http://sgerwk.altervista.org/imapbodystructure.html + */ + + test('single-part email', () async { var response = """( BODYSTRUCTURE("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 1315 42 NIL NIL NIL NIL) )\n @@ -31,121 +29,66 @@ void main() { await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of text + html', () async { + test('text + html', () async { var response = """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2234 63 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2987 52 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "d3438gr7324") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of mail with images', () async { + test('mail with images', () async { var response = """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 119 2 NIL ("INLINE" NIL) NIL)("IMAGE" "JPEG" ("NAME" "4356415.jpg") "<0__=rhksjt>" NIL "BASE64" 143804 NIL ("INLINE" ("FILENAME" "4356415.jpg")) NIL) "RELATED" ("BOUNDARY" "0__=5tgd3d") ("INLINE" NIL) NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of text + html with images', () async { + test('text + html with images', () async { var response = """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed") NIL NIL "QUOTED-PRINTABLE" 2815 73 NIL NIL NIL NIL)(("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4171 66 NIL NIL NIL NIL)("IMAGE" "JPEG" ("NAME" "image.jpg") "<3245dsf7435>" NIL "BASE64" 189906 NIL NIL NIL NIL)("IMAGE" "GIF" ("NAME" "other.gif") "<32f6324f>" NIL "BASE64" 1090 NIL NIL NIL NIL) "RELATED" ("BOUNDARY" "--=sdgqgt") NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "--=u5sfrj") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of mail with images', () async { + test('text + html with "inline" images', () async { var response = - """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\n"""; + """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of mail with attachment', () async { + test('mail with images', () async { var response = - """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4692 69 NIL NIL NIL NIL)("APPLICATION" "PDF" ("NAME" "pages.pdf") NIL NIL "BASE64" 38838 NIL ("attachment" ("FILENAME" "pages.pdf")) NIL NIL) "MIXED" ("BOUNDARY" "----=6fgshr") NIL NIL NIL))\n"""; + """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of alternative with attachment', () async { + test('mail with attachment', () async { var response = - """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 403 6 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 421 6 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=fghgf3") NIL NIL NIL)("APPLICATION" "MSWORD" ("NAME" "letter.doc") NIL NIL "BASE64" 110000 NIL ("attachment" ("FILENAME" "letter.doc" "SIZE" "80384")) NIL NIL) "MIXED" ("BOUNDARY" "----=y34fgl") NIL NIL NIL))\n"""; + """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4692 69 NIL NIL NIL NIL)("APPLICATION" "PDF" ("NAME" "pages.pdf") NIL NIL "BASE64" 38838 NIL ("attachment" ("FILENAME" "pages.pdf")) NIL NIL) "MIXED" ("BOUNDARY" "----=6fgshr") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test( - 'Can parse body structure of alternative between text and html with images', - () async { + test('alternative and attachment', () async { var response = - """(BODYSTRUCTURE (((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 833 30 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 3412 62 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "2__=fgrths") NIL NIL)("IMAGE" "GIF" ("NAME" "485039.gif") "<2__=lgkfjr>" NIL "BASE64" 64 NIL ("INLINE" ("FILENAME" "485039.gif")) NIL) "RELATED" ("BOUNDARY" "1__=fgrths") NIL NIL)("APPLICATION" "PDF" ("NAME" "title.pdf") "<1__=lgkfjr>" NIL "BASE64" 333980 NIL ("ATTACHMENT" ("FILENAME" "title.pdf")) NIL) "MIXED" ("BOUNDARY" "0__=fgrths") NIL NIL))\n"""; + """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 403 6 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 421 6 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=fghgf3") NIL NIL NIL)("APPLICATION" "MSWORD" ("NAME" "letter.doc") NIL NIL "BASE64" 110000 NIL ("attachment" ("FILENAME" "letter.doc" "SIZE" "80384")) NIL NIL) "MIXED" ("BOUNDARY" "----=y34fgl") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of single-element lists', () async { + test('all together', () async { var response = - """(BODYSTRUCTURE (("TEXT" "HTML" NIL NIL NIL "7BIT" 151 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----=rfsewr") NIL NIL))\n"""; + """(BODYSTRUCTURE (((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 833 30 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 3412 62 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "2__=fgrths") NIL NIL)("IMAGE" "GIF" ("NAME" "485039.gif") "<2__=lgkfjr>" NIL "BASE64" 64 NIL ("INLINE" ("FILENAME" "485039.gif")) NIL) "RELATED" ("BOUNDARY" "1__=fgrths") NIL NIL)("APPLICATION" "PDF" ("NAME" "title.pdf") "<1__=lgkfjr>" NIL "BASE64" 333980 NIL ("ATTACHMENT" ("FILENAME" "title.pdf")) NIL) "MIXED" ("BOUNDARY" "0__=fgrths") NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); - test('Can parse body structure of CASE 3: Text with inline image', () async { + test('single-element lists', () async { var response = - """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; + """(BODYSTRUCTURE (("TEXT" "HTML" NIL NIL NIL "7BIT" 151 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----=rfsewr") NIL NIL))\n"""; _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); } - -/* - - -* 11 FETCH (BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL)) - - - -( - ("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL) - ( - ("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL) - ("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL)) - - - - - -SEE: - * http://sgerwk.altervista.org/imapbodystructure.html - * section: "text + html with images - " - -( - "text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL -) -( - ( - "text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL - ) - ( - "image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL - ) - "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL -) -"alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL - - - - - - -( - ( - "TEXT" "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 1152 23 - ) - ( - "TEXT" "PLAIN" ("CHARSET" "US-ASCII" "NAME" "cc.diff") "<960723163407.20117h@cac.washington.edu>" "Compiler diff" "BASE64" 4554 73 - ) - "MIXED" -) - -*/ From a273bde1f81ef1ddde9f9a8ae180010f12e69995 Mon Sep 17 00:00:00 2001 From: Thomas Markiewicz Date: Thu, 8 Aug 2019 10:41:28 -0500 Subject: [PATCH 03/10] Added another test for email with inline pgp signature --- test/imap_bodystructure_test.dart | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/test/imap_bodystructure_test.dart b/test/imap_bodystructure_test.dart index e84297e..d764130 100644 --- a/test/imap_bodystructure_test.dart +++ b/test/imap_bodystructure_test.dart @@ -18,6 +18,9 @@ void main() { Test cases are based on the following examples: http://sgerwk.altervista.org/imapbodystructure.html + + These just check to make sure no exceptions are thrown, but could be expanded to verify expected _result + */ test('single-part email', () async { @@ -50,13 +53,6 @@ void main() { await _folder.processFetch(_buffer, _number, _result); }); - test('text + html with "inline" images', () async { - var response = - """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; - _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); - }); - test('mail with images', () async { var response = """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\n"""; @@ -91,4 +87,20 @@ void main() { _buffer.addAll(response.codeUnits); await _folder.processFetch(_buffer, _number, _result); }); + + //--- other test variations + + test('text + html with "inline" images', () async { + var response = + """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); + + test('"inline" pgp signature', () async { + var response = + """(BODYSTRUCTURE (("application" "pgp-encrypted" NIL NIL NIL "7bit" 12 NIL NIL NIL NIL)("application" "octet-stream" ("name" "encrypted.asc") NIL NIL "7bit" 933 NIL ("inline" ("filename" "encrypted.asc")) NIL NIL) "encrypted" ("boundary" "5ceef4c9_74b0dc51_1a6" "protocol" "application/pgp-encrypted") NIL NIL NIL))\n"""; + _buffer.addAll(response.codeUnits); + await _folder.processFetch(_buffer, _number, _result); + }); } From 247a4b7612309cd77134184c2180aad9c2f8b91f Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Thu, 8 Aug 2019 22:59:59 +0200 Subject: [PATCH 04/10] Test fetch method instead of testing private method directly --- lib/src/imap_folder.dart | 5 ++-- pubspec.yaml | 1 - test/imap_bodystructure_test.dart | 40 +++++++++++++++---------------- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/lib/src/imap_folder.dart b/lib/src/imap_folder.dart index 3bd675f..b50468c 100644 --- a/lib/src/imap_folder.dart +++ b/lib/src/imap_folder.dart @@ -145,7 +145,7 @@ class ImapFolder extends _ImapCommandable { ")", untaggedHandlers: { "FETCH": (ImapBuffer buffer, {int number}) async { - await processFetch(buffer, number, result); + await _processFetch(buffer, number, result); } }); return result; @@ -265,8 +265,7 @@ class ImapFolder extends _ImapCommandable { } /// Sorts data retrieved from a fetch response into [result] - @visibleForTesting - void processFetch(ImapBuffer buffer, int number, Map result) async { + void _processFetch(ImapBuffer buffer, int number, Map result) async { result[number] = {}; ImapWord word = await buffer.readWord(expected: ImapWordType.parenOpen); word = await buffer.readWord(); diff --git a/pubspec.yaml b/pubspec.yaml index 06bd6cb..98a8146 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,6 @@ environment: dependencies: logging: ^0.11.3 pedantic: ^1.4.0 - meta: ^1.1.7 dev_dependencies: test: ^1.3.0 diff --git a/test/imap_bodystructure_test.dart b/test/imap_bodystructure_test.dart index d764130..de8c15e 100644 --- a/test/imap_bodystructure_test.dart +++ b/test/imap_bodystructure_test.dart @@ -1,17 +1,17 @@ import 'package:imap_client/imap_client.dart'; +import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; +class MockEngine extends Mock implements ImapEngine {} + void main() { - var _folder; + ImapFolder _folder; + ImapEngine engine = MockEngine(); var _buffer; - int _number; - var _result; setUp(() { - _folder = ImapFolder(null, "TestFolder"); + _folder = ImapFolder(engine, "TestFolder"); _buffer = ImapBuffer(); - _number = 0; - _result = Map(); }); /* @@ -24,68 +24,66 @@ void main() { */ test('single-part email', () async { - var response = """( - BODYSTRUCTURE("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 1315 42 NIL NIL NIL NIL) - )\n - """; + var response = + """(BODYSTRUCTURE("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 1315 42 NIL NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('text + html', () async { var response = """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2234 63 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2987 52 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "d3438gr7324") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('mail with images', () async { var response = """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 119 2 NIL ("INLINE" NIL) NIL)("IMAGE" "JPEG" ("NAME" "4356415.jpg") "<0__=rhksjt>" NIL "BASE64" 143804 NIL ("INLINE" ("FILENAME" "4356415.jpg")) NIL) "RELATED" ("BOUNDARY" "0__=5tgd3d") ("INLINE" NIL) NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('text + html with images', () async { var response = """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed") NIL NIL "QUOTED-PRINTABLE" 2815 73 NIL NIL NIL NIL)(("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4171 66 NIL NIL NIL NIL)("IMAGE" "JPEG" ("NAME" "image.jpg") "<3245dsf7435>" NIL "BASE64" 189906 NIL NIL NIL NIL)("IMAGE" "GIF" ("NAME" "other.gif") "<32f6324f>" NIL "BASE64" 1090 NIL NIL NIL NIL) "RELATED" ("BOUNDARY" "--=sdgqgt") NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "--=u5sfrj") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('mail with images', () async { var response = """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('mail with attachment', () async { var response = """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4692 69 NIL NIL NIL NIL)("APPLICATION" "PDF" ("NAME" "pages.pdf") NIL NIL "BASE64" 38838 NIL ("attachment" ("FILENAME" "pages.pdf")) NIL NIL) "MIXED" ("BOUNDARY" "----=6fgshr") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('alternative and attachment', () async { var response = """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 403 6 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 421 6 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=fghgf3") NIL NIL NIL)("APPLICATION" "MSWORD" ("NAME" "letter.doc") NIL NIL "BASE64" 110000 NIL ("attachment" ("FILENAME" "letter.doc" "SIZE" "80384")) NIL NIL) "MIXED" ("BOUNDARY" "----=y34fgl") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('all together', () async { var response = """(BODYSTRUCTURE (((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 833 30 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 3412 62 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "2__=fgrths") NIL NIL)("IMAGE" "GIF" ("NAME" "485039.gif") "<2__=lgkfjr>" NIL "BASE64" 64 NIL ("INLINE" ("FILENAME" "485039.gif")) NIL) "RELATED" ("BOUNDARY" "1__=fgrths") NIL NIL)("APPLICATION" "PDF" ("NAME" "title.pdf") "<1__=lgkfjr>" NIL "BASE64" 333980 NIL ("ATTACHMENT" ("FILENAME" "title.pdf")) NIL) "MIXED" ("BOUNDARY" "0__=fgrths") NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('single-element lists', () async { var response = """(BODYSTRUCTURE (("TEXT" "HTML" NIL NIL NIL "7BIT" 151 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----=rfsewr") NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); //--- other test variations @@ -94,13 +92,13 @@ void main() { var response = """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); test('"inline" pgp signature', () async { var response = """(BODYSTRUCTURE (("application" "pgp-encrypted" NIL NIL NIL "7bit" 12 NIL NIL NIL NIL)("application" "octet-stream" ("name" "encrypted.asc") NIL NIL "7bit" 933 NIL ("inline" ("filename" "encrypted.asc")) NIL NIL) "encrypted" ("boundary" "5ceef4c9_74b0dc51_1a6" "protocol" "application/pgp-encrypted") NIL NIL NIL))\n"""; _buffer.addAll(response.codeUnits); - await _folder.processFetch(_buffer, _number, _result); + await _folder.fetch([], messageIds: [1]); }); } From f2e1147b02d28b0d8b76ebcb5c2f69b6395e58ea Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Thu, 8 Aug 2019 23:05:00 +0200 Subject: [PATCH 05/10] Remove unused package import --- lib/imap_client.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/imap_client.dart b/lib/imap_client.dart index 5b5ff5f..35f2df7 100644 --- a/lib/imap_client.dart +++ b/lib/imap_client.dart @@ -8,8 +8,6 @@ import 'dart:convert'; import 'package:logging/logging.dart'; -import 'package:meta/meta.dart'; - part "src/buffer_awaiter.dart"; part "src/imap_buffer.dart"; From 0a9ae56a9d872328ed2f961567036a6c867784f0 Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Fri, 9 Aug 2019 03:11:38 +0200 Subject: [PATCH 06/10] Make assertions real exceptions --- lib/src/imap_folder.dart | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/src/imap_folder.dart b/lib/src/imap_folder.dart index b50468c..3aeefcf 100644 --- a/lib/src/imap_folder.dart +++ b/lib/src/imap_folder.dart @@ -516,12 +516,18 @@ class ImapFolder extends _ImapCommandable { ImapWord word = await buffer.readWord(); while (word.type != ImapWordType.parenClose) { if (word.type != ImapWordType.nil) { - assert(word.type == ImapWordType.string); + if (word.type != ImapWordType.string) { + throw new InvalidFormatException( + "Expected ), NIL or string, but got ${word.type}"); + } String key = word.value; word = await buffer.readWord(); if (word.type != ImapWordType.nil) { Map values = new Map(); - assert(word.type == ImapWordType.parenOpen); + if (word.type != ImapWordType.parenOpen) { + throw new InvalidFormatException( + "Expected (, but got ${word.type}"); + } word = await buffer.readWord(); while (word.type != ImapWordType.parenClose) { values[word.value] = From 1b26e1d152fa1b2cff764ce5fc08526a231453ab Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Fri, 9 Aug 2019 04:10:03 +0200 Subject: [PATCH 07/10] Fix test not using input --- test/imap_bodystructure_test.dart | 93 ++++++++++++++++++------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/test/imap_bodystructure_test.dart b/test/imap_bodystructure_test.dart index de8c15e..9cbd6a7 100644 --- a/test/imap_bodystructure_test.dart +++ b/test/imap_bodystructure_test.dart @@ -1,17 +1,45 @@ +import 'dart:async'; +import 'dart:io'; + import 'package:imap_client/imap_client.dart'; import 'package:mockito/mockito.dart'; import 'package:test/test.dart'; -class MockEngine extends Mock implements ImapEngine {} +class FakeSocket extends Fake implements Socket { + StreamController> input; + String nextResponse; + + FakeSocket(this.input); + + @override + StreamSubscription> listen(void onData(List event), + {Function onError, void onDone(), bool cancelOnError}) { + return input.stream.listen(onData); + } + + @override + void write(Object object) async { + if(object is String) { + if(object.startsWith("A2")) { + input.add("A2 OK\r\n".codeUnits); + } else if(object.contains("FETCH")) { + input.add("$nextResponse\r\n".codeUnits); + } + } + } +} void main() { + StreamController> server = new StreamController.broadcast(); + FakeSocket socket = new FakeSocket(server); + ImapEngine engine; ImapFolder _folder; - ImapEngine engine = MockEngine(); - var _buffer; setUp(() { - _folder = ImapFolder(engine, "TestFolder"); - _buffer = ImapBuffer(); + server.stream.drain(); + engine = new ImapEngine(socket); + _folder = new ImapFolder(engine, "TestFolder"); + server.add("* OK [CAPABILITY Imap4rev1]\r\nA1 OK\r\n".codeUnits); }); /* @@ -24,81 +52,70 @@ void main() { */ test('single-part email', () async { - var response = - """(BODYSTRUCTURE("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 1315 42 NIL NIL NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 1315 42 NIL NIL NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('text + html', () async { - var response = - """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2234 63 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2987 52 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "d3438gr7324") NIL NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2234 63 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 2987 52 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "d3438gr7324") NIL NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('mail with images', () async { - var response = - """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 119 2 NIL ("INLINE" NIL) NIL)("IMAGE" "JPEG" ("NAME" "4356415.jpg") "<0__=rhksjt>" NIL "BASE64" 143804 NIL ("INLINE" ("FILENAME" "4356415.jpg")) NIL) "RELATED" ("BOUNDARY" "0__=5tgd3d") ("INLINE" NIL) NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 119 2 NIL ("INLINE" NIL) NIL)("IMAGE" "JPEG" ("NAME" "4356415.jpg") "<0__=rhksjt>" NIL "BASE64" 143804 NIL ("INLINE" ("FILENAME" "4356415.jpg")) NIL) "RELATED" ("BOUNDARY" "0__=5tgd3d") ("INLINE" NIL) NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('text + html with images', () async { - var response = - """(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed") NIL NIL "QUOTED-PRINTABLE" 2815 73 NIL NIL NIL NIL)(("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4171 66 NIL NIL NIL NIL)("IMAGE" "JPEG" ("NAME" "image.jpg") "<3245dsf7435>" NIL "BASE64" 189906 NIL NIL NIL NIL)("IMAGE" "GIF" ("NAME" "other.gif") "<32f6324f>" NIL "BASE64" 1090 NIL NIL NIL NIL) "RELATED" ("BOUNDARY" "--=sdgqgt") NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "--=u5sfrj") NIL NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1" "FORMAT" "flowed") NIL NIL "QUOTED-PRINTABLE" 2815 73 NIL NIL NIL NIL)(("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4171 66 NIL NIL NIL NIL)("IMAGE" "JPEG" ("NAME" "image.jpg") "<3245dsf7435>" NIL "BASE64" 189906 NIL NIL NIL NIL)("IMAGE" "GIF" ("NAME" "other.gif") "<32f6324f>" NIL "BASE64" 1090 NIL NIL NIL NIL) "RELATED" ("BOUNDARY" "--=sdgqgt") NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "--=u5sfrj") NIL NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('mail with images', () async { - var response = - """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 471 28 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 1417 36 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "1__=hqjksdm") NIL NIL)("IMAGE" "GIF" ("NAME" "image.gif") "<1__=cxdf2f>" NIL "BASE64" 50294 NIL ("INLINE" ("FILENAME" "image.gif")) NIL) "RELATED" ("BOUNDARY" "0__=hqjksdm") NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('mail with attachment', () async { - var response = - """(BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4692 69 NIL NIL NIL NIL)("APPLICATION" "PDF" ("NAME" "pages.pdf") NIL NIL "BASE64" 38838 NIL ("attachment" ("FILENAME" "pages.pdf")) NIL NIL) "MIXED" ("BOUNDARY" "----=6fgshr") NIL NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 4692 69 NIL NIL NIL NIL)("APPLICATION" "PDF" ("NAME" "pages.pdf") NIL NIL "BASE64" 38838 NIL ("attachment" ("FILENAME" "pages.pdf")) NIL NIL) "MIXED" ("BOUNDARY" "----=6fgshr") NIL NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('alternative and attachment', () async { - var response = - """(BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 403 6 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 421 6 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=fghgf3") NIL NIL NIL)("APPLICATION" "MSWORD" ("NAME" "letter.doc") NIL NIL "BASE64" 110000 NIL ("attachment" ("FILENAME" "letter.doc" "SIZE" "80384")) NIL NIL) "MIXED" ("BOUNDARY" "----=y34fgl") NIL NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE ((("TEXT" "PLAIN" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 403 6 NIL NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 421 6 NIL NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=fghgf3") NIL NIL NIL)("APPLICATION" "MSWORD" ("NAME" "letter.doc") NIL NIL "BASE64" 110000 NIL ("attachment" ("FILENAME" "letter.doc" "SIZE" "80384")) NIL NIL) "MIXED" ("BOUNDARY" "----=y34fgl") NIL NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('all together', () async { - var response = - """(BODYSTRUCTURE (((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 833 30 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 3412 62 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "2__=fgrths") NIL NIL)("IMAGE" "GIF" ("NAME" "485039.gif") "<2__=lgkfjr>" NIL "BASE64" 64 NIL ("INLINE" ("FILENAME" "485039.gif")) NIL) "RELATED" ("BOUNDARY" "1__=fgrths") NIL NIL)("APPLICATION" "PDF" ("NAME" "title.pdf") "<1__=lgkfjr>" NIL "BASE64" 333980 NIL ("ATTACHMENT" ("FILENAME" "title.pdf")) NIL) "MIXED" ("BOUNDARY" "0__=fgrths") NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (((("TEXT" "PLAIN" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 833 30 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "ISO-8859-1") NIL NIL "QUOTED-PRINTABLE" 3412 62 NIL ("INLINE" NIL) NIL) "ALTERNATIVE" ("BOUNDARY" "2__=fgrths") NIL NIL)("IMAGE" "GIF" ("NAME" "485039.gif") "<2__=lgkfjr>" NIL "BASE64" 64 NIL ("INLINE" ("FILENAME" "485039.gif")) NIL) "RELATED" ("BOUNDARY" "1__=fgrths") NIL NIL)("APPLICATION" "PDF" ("NAME" "title.pdf") "<1__=lgkfjr>" NIL "BASE64" 333980 NIL ("ATTACHMENT" ("FILENAME" "title.pdf")) NIL) "MIXED" ("BOUNDARY" "0__=fgrths") NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('single-element lists', () async { - var response = - """(BODYSTRUCTURE (("TEXT" "HTML" NIL NIL NIL "7BIT" 151 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----=rfsewr") NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("TEXT" "HTML" NIL NIL NIL "7BIT" 151 0 NIL NIL NIL) "MIXED" ("BOUNDARY" "----=rfsewr") NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); //--- other test variations test('text + html with "inline" images', () async { - var response = - """(BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("text" "plain" ("charset" "utf-8") NIL NIL "7bit" 160 10 NIL NIL NIL NIL)(("text" "html" ("charset" "utf-8") NIL NIL "7bit" 452 15 NIL NIL NIL NIL)("image" "png" ("name" "kmdhkbcgedflagom.png") "" NIL "base64" 29594 NIL ("inline" ("filename" "kmdhkbcgedflagom.png")) NIL NIL) "related" ("boundary" "------------4F31590A57C94ECEEA4EE609") NIL NIL NIL) "alternative" ("boundary" "------------E4A51DD138E4E2F27347C5BC") NIL ("en-US") NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); test('"inline" pgp signature', () async { - var response = - """(BODYSTRUCTURE (("application" "pgp-encrypted" NIL NIL NIL "7bit" 12 NIL NIL NIL NIL)("application" "octet-stream" ("name" "encrypted.asc") NIL NIL "7bit" 933 NIL ("inline" ("filename" "encrypted.asc")) NIL NIL) "encrypted" ("boundary" "5ceef4c9_74b0dc51_1a6" "protocol" "application/pgp-encrypted") NIL NIL NIL))\n"""; - _buffer.addAll(response.codeUnits); + socket.nextResponse = + """* 1 FETCH (BODYSTRUCTURE (("application" "pgp-encrypted" NIL NIL NIL "7bit" 12 NIL NIL NIL NIL)("application" "octet-stream" ("name" "encrypted.asc") NIL NIL "7bit" 933 NIL ("inline" ("filename" "encrypted.asc")) NIL NIL) "encrypted" ("boundary" "5ceef4c9_74b0dc51_1a6" "protocol" "application/pgp-encrypted") NIL NIL NIL))\r\nA1 OK\r\n"""; await _folder.fetch([], messageIds: [1]); }); } From d1dd69abc788f3e1132828978a61172a5b49af5c Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Fri, 9 Aug 2019 04:10:51 +0200 Subject: [PATCH 08/10] Fix typo --- lib/src/imap_folder.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/imap_folder.dart b/lib/src/imap_folder.dart index 3aeefcf..1ef9113 100644 --- a/lib/src/imap_folder.dart +++ b/lib/src/imap_folder.dart @@ -512,7 +512,7 @@ class ImapFolder extends _ImapCommandable { ImapBuffer buffer) async { Map subfieldMap = new Map(); - // expects prenOpen to be consumes already + // expects prenOpen to be consumed already ImapWord word = await buffer.readWord(); while (word.type != ImapWordType.parenClose) { if (word.type != ImapWordType.nil) { From ae44e2cacb46aa58dc00b1b6bf04d965d07cb05b Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Fri, 9 Aug 2019 04:13:48 +0200 Subject: [PATCH 09/10] Fix formatting mistake --- test/imap_bodystructure_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/imap_bodystructure_test.dart b/test/imap_bodystructure_test.dart index 9cbd6a7..5f34492 100644 --- a/test/imap_bodystructure_test.dart +++ b/test/imap_bodystructure_test.dart @@ -19,10 +19,10 @@ class FakeSocket extends Fake implements Socket { @override void write(Object object) async { - if(object is String) { - if(object.startsWith("A2")) { + if (object is String) { + if (object.startsWith("A2")) { input.add("A2 OK\r\n".codeUnits); - } else if(object.contains("FETCH")) { + } else if (object.contains("FETCH")) { input.add("$nextResponse\r\n".codeUnits); } } From 84194ca22213b9c0e7e61e6eba24cf59f3dc9a7c Mon Sep 17 00:00:00 2001 From: michaelspiss Date: Fri, 9 Aug 2019 04:29:01 +0200 Subject: [PATCH 10/10] Bump version number --- CHANGELOG.md | 4 ++++ pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 253ea30..e306154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.5 + +- Fix bodystructure parsing errors (issues #16, #18) + ## 0.2.4 - Fix #14 by using `utf8.decode` instead of standard `String.fromCharCodes` diff --git a/pubspec.yaml b/pubspec.yaml index 98a8146..2e3755b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: imap_client description: An interface to get emails via the imap protocol (version 4rev1) -version: 0.2.4 +version: 0.2.5 homepage: https://github.com/michaelspiss/imap_client author: Michael Spiss documentation: