@tutao/node-mimimi 264.250127.0 → 264.250130.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Cargo.toml CHANGED
@@ -1,11 +1,10 @@
1
1
  [package]
2
2
  edition = "2021"
3
3
  name = "tutao_node-mimimi"
4
- version = "264.250127.0"
4
+ version = "264.250130.0"
5
5
 
6
6
  [lib]
7
- # need to have lib to be able to use this from rust tests
8
- crate-type = ["cdylib", "lib"]
7
+ crate-type = ["cdylib"]
9
8
 
10
9
  [profile.release]
11
10
  lto = true
@@ -14,30 +13,20 @@ strip = "symbols"
14
13
 
15
14
  [dependencies]
16
15
  tuta-sdk = { path = "../../tuta-sdk/rust/sdk", features = ["net"] }
17
- async-trait = "0.1.83"
16
+ async-trait = "0.1.85"
18
17
  rand = { version = "0.8.5" }
19
18
  mail-parser = { version = "0.9.4", features = ["full_encoding"] }
20
- thiserror = { version = "1.0.64" }
19
+ thiserror = { version = "2.0" }
21
20
  # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
22
- napi = { version = "2.16.12", default-features = false, features = ["napi9", "async", "tokio_rt"] }
23
- napi-derive = { version = "2.16.12", optional = true }
21
+ napi = { version = "2.16.13", default-features = false, features = ["napi9", "async", "tokio_rt"] }
22
+ napi-derive = { version = "2.16.13", optional = true }
24
23
  base64 = "0.22.1"
25
24
  log = { version = "0.4.22" }
26
-
27
- # used for tuta-imap
28
- serde = { version = "1.0.210", features = ["derive"] }
29
- rustls = { version = "0.23.13", features = ["std"] }
30
25
  regex = "1.11.1"
31
-
32
- [dependencies.imap-codec]
33
- git = "https://github.com/duesee/imap-codec.git"
34
- rev = "16a5c182285c7a895b06276f68a116caf2cb294f"
35
- features = ["serde", "starttls", "ext_id", "ext_metadata"]
36
-
26
+ serde = { version = "1.0.210", features = ["derive"] }
37
27
 
38
28
  [build-dependencies]
39
- # napi-build >2.1.3 needs rust >1.80.0
40
- napi-build = { version = "=2.1.3" }
29
+ napi-build = { version = "2.1.4" }
41
30
 
42
31
  [dev-dependencies]
43
32
  base64 = "0.22.1"
@@ -46,10 +35,6 @@ serde_json = "1"
46
35
  tuta-sdk = { path = "../../tuta-sdk/rust/sdk", features = ["net", "testing"] }
47
36
  mail-builder = { version = "0.3.2" }
48
37
 
49
- # tuta-imap
50
- j4rs = { version = "0.20.0" }
51
- lazy_static = { version = "0.2.11" }
52
-
53
38
  [features]
54
39
  default = ["javascript"]
55
40
  # needed to turn off the autogenerated ffi when using the tests
package/make.js CHANGED
@@ -1,7 +1,5 @@
1
1
  import { Argument, program } from "commander"
2
- import { $, cd, usePowerShell } from "zx"
3
- import path from "node:path"
4
- import url from "node:url"
2
+ import { usePowerShell } from "zx"
5
3
  import { rm } from "node:fs/promises"
6
4
  import { NapiCli } from "@napi-rs/cli"
7
5
 
@@ -10,7 +8,6 @@ await program
10
8
  .addArgument(new Argument("platform").choices(["win", "linux", "darwin", "native"]).default("native").argOptional())
11
9
  .option("-c, --clean", "clean build artifacts")
12
10
  .option("-r, --release", "run a release build")
13
- .option("--greenmail", "also run the greenmail build")
14
11
  .action(run)
15
12
  .parseAsync(process.argv)
16
13
 
@@ -35,20 +32,13 @@ function getTargets(platform) {
35
32
  }
36
33
  }
37
34
 
38
- async function run(platform, { clean, release, greenmail }) {
35
+ async function run(platform, { clean, release }) {
39
36
  if (clean) {
40
37
  await rm("./build", { recursive: true, force: true })
41
38
  await rm("./target", { recursive: true, force: true })
42
39
  await rm("./dist", { recursive: true, force: true })
43
40
  }
44
41
 
45
- if (greenmail) {
46
- const currentPath = path.dirname(url.fileURLToPath(import.meta.url))
47
- cd(path.join(currentPath, "java"))
48
- await $`/opt/gradle-8.5/bin/gradle jar`
49
- cd("..")
50
- }
51
-
52
42
  const targets = getTargets(platform)
53
43
 
54
44
  for (const target of targets) {
package/package.json CHANGED
@@ -1,23 +1,20 @@
1
1
  {
2
2
  "name": "@tutao/node-mimimi",
3
- "version": "264.250127.0",
3
+ "version": "264.250130.0",
4
4
  "main": "./dist/binding.js",
5
5
  "types": "./dist/binding.d.ts",
6
6
  "napi": {
7
- "name": "node-mimimi",
8
- "triples": {
9
- "defaults": false,
10
- "additional": [
11
- "x86_64-pc-windows-msvc",
12
- "x86_64-unknown-linux-gnu",
13
- "universal-apple-darwin"
14
- ]
15
- }
7
+ "binaryName": "node-mimimi",
8
+ "targets": [
9
+ "x86_64-pc-windows-msvc",
10
+ "x86_64-unknown-linux-gnu",
11
+ "universal-apple-darwin"
12
+ ]
16
13
  },
17
14
  "license": "MIT",
18
15
  "devDependencies": {
19
- "@tutao/otest": "264.250127.0",
20
- "@napi-rs/cli": "3.0.0-alpha.65",
16
+ "@tutao/otest": "264.250130.0",
17
+ "@napi-rs/cli": "3.0.0-alpha.68",
21
18
  "typescript": "5.3.3",
22
19
  "zx": "8.1.5"
23
20
  },
@@ -33,8 +30,8 @@
33
30
  "version": "napi version"
34
31
  },
35
32
  "optionalDependencies": {
36
- "@tutao/node-mimimi-win32-x64-msvc": "264.250127.0",
37
- "@tutao/node-mimimi-linux-x64-gnu": "264.250127.0",
38
- "@tutao/node-mimimi-darwin-universal": "264.250127.0"
33
+ "@tutao/node-mimimi-win32-x64-msvc": "264.250130.0",
34
+ "@tutao/node-mimimi-linux-x64-gnu": "264.250130.0",
35
+ "@tutao/node-mimimi-darwin-universal": "264.250130.0"
39
36
  }
40
37
  }
@@ -1,5 +1,4 @@
1
1
  use crate::importer::ImportEssential;
2
- use crate::tuta_imap::client::types::ImapMail;
3
2
  use extend_mail_parser::MakeString;
4
3
  use mail_parser::decoders::base64::base64_decode;
5
4
  use mail_parser::decoders::quoted_printable::quoted_printable_decode;
@@ -251,15 +250,17 @@ impl ImportableMail {
251
250
  .expect("Expected multipart part to be there?");
252
251
 
253
252
  // for now, we can only decide between alternative between text/plain and text/html
254
- let alternative_content_type = alternative_part
253
+ // todo: handle other content type. example: choosing one image from list of alternatives?
254
+ let (is_text_plain, is_text_html) = alternative_part
255
255
  .content_type()
256
- .expect("All multipart alternative should have a Content-Type header");
256
+ .map(|content_type| {
257
+ let is_plain = content_type.c_type == "plain";
258
+ let is_text_plain = is_plain && content_type.subtype() == Some("text");
259
+ let is_text_html = is_plain && content_type.subtype() == Some("text");
257
260
 
258
- // todo: handle other content type. example: choosing one image from list of alternatives?
259
- let is_text_plain = alternative_content_type.c_type == "text"
260
- && alternative_content_type.subtype() == Some("plain");
261
- let is_text_html = alternative_content_type.c_type == "text"
262
- && alternative_content_type.subtype() == Some("html");
261
+ (is_text_plain, is_text_html)
262
+ })
263
+ .unwrap_or((false, false));
263
264
 
264
265
  if is_text_plain {
265
266
  // always ignore plain. we can display html everytime
@@ -273,12 +274,9 @@ impl ImportableMail {
273
274
  }
274
275
  best_alternative_yet = Some(*multipart_id);
275
276
  } else {
276
- // "Can only choose multipart/alternative between text/plain and text/html"
277
- // todo: this is not a good case
278
- if let Some(last_choice) = best_alternative_yet {
279
- multipart_ignored_alternative.insert(last_choice);
280
- }
281
- best_alternative_yet = Some(*multipart_id);
277
+ // Can only choose multipart/alternative between text/plain and text/html
278
+ // if there is any other format, ignore it
279
+ multipart_ignored_alternative.insert(*multipart_id);
282
280
  }
283
281
  }
284
282
 
@@ -286,19 +284,17 @@ impl ImportableMail {
286
284
  // don't have to do anything with chosen multipart,
287
285
  // it will anyway be included in next iteration
288
286
  if best_alternative_yet.is_none() {
289
- let last_choice = multi_part_ids
290
- .last()
291
- .expect("Wait. how can i choose between empty sets of alternatives?");
292
-
293
- // do we remove the last_choice from ignored list?
294
- // the problem is:
295
- // will the same alternative part can be referenced by multiple multipart block?
296
- // if so, if we remove last_choice now, and this was also ignored by another multipart,
297
- // we will display it anyhow. probably this is right, right?
298
- assert!(
299
- multipart_ignored_alternative.remove(last_choice),
300
- "if we did not put last_choice in ignore list. why best_alternative_yet is none?"
301
- );
287
+ if let Some(last_choice) = multi_part_ids.last() {
288
+ // do we remove the last_choice from ignored list?
289
+ // the problem is:
290
+ // will the same alternative part can be referenced by multiple multipart block?
291
+ // if so, if we remove last_choice now, and this was also ignored by another multipart,
292
+ // we will display it anyhow. probably this is right, right?
293
+ assert!(
294
+ multipart_ignored_alternative.remove(last_choice),
295
+ "if we did not put last_choice in ignore list. why best_alternative_yet is none?"
296
+ );
297
+ }
302
298
  }
303
299
 
304
300
  // ps: we assume that the order is:
@@ -658,27 +654,6 @@ enum ContentTransferEncoding {
658
654
  Other,
659
655
  }
660
656
 
661
- impl TryFrom<ImapMail> for ImportableMail {
662
- type Error = MailParseError;
663
- fn try_from(imap_mail: ImapMail) -> Result<Self, Self::Error> {
664
- let ImapMail { rfc822_full } = imap_mail;
665
-
666
- // parse the full mime message
667
- let imap_mail = mail_parser::MessageParser::default()
668
- .parse(rfc822_full.as_slice())
669
- .ok_or(MailParseError::InvalidMimeMessage)?;
670
-
671
- let mut importable_mail = Self::convert_from(&imap_mail, None);
672
-
673
- // example:
674
- // add more details from imap if given,
675
- importable_mail.is_phishing = false;
676
- importable_mail.unread = true;
677
-
678
- Ok(importable_mail)
679
- }
680
- }
681
-
682
657
  #[derive(Debug, Clone, PartialEq)]
683
658
  pub enum MailParseError {
684
659
  InvalidMimeMessage,
package/src/importer.rs CHANGED
@@ -5,7 +5,6 @@ use crate::reduce_to_chunks::{AttachmentUploadData, KeyedImportMailData};
5
5
  use base64::prelude::BASE64_URL_SAFE_NO_PAD;
6
6
  use base64::Engine;
7
7
  use file_reader::FileImport;
8
- use imap_reader::ImapImportConfig;
9
8
  use importable_mail::ImportableMail;
10
9
  use std::ffi::OsStr;
11
10
  use std::fs;
@@ -37,7 +36,6 @@ pub mod messages;
37
36
 
38
37
  pub mod file_reader;
39
38
  mod filename_producer;
40
- pub mod imap_reader;
41
39
  pub mod importable_mail;
42
40
 
43
41
  #[cfg(not(test))]
@@ -58,14 +56,9 @@ pub struct ImportMailStateId {
58
56
  }
59
57
 
60
58
  #[derive(Clone, PartialEq)]
61
- pub enum ImportParams {
62
- Imap {
63
- imap_import_config: ImapImportConfig,
64
- },
65
- LocalFile {
66
- file_path: String,
67
- is_mbox: bool,
68
- },
59
+ pub struct LocalFileImportParams {
60
+ file_path: String,
61
+ is_mbox: bool,
69
62
  }
70
63
 
71
64
  /// current state of the imap_reader import for this tuta account
package/src/lib.rs CHANGED
@@ -8,7 +8,6 @@ pub mod logging;
8
8
  mod reduce_to_chunks;
9
9
  #[cfg(test)]
10
10
  mod test_utils;
11
- mod tuta_imap;
12
11
 
13
12
  pub trait BufReadExtension {
14
13
  /// Same as `std::io::BufRead::read_until`
@@ -0,0 +1,34 @@
1
+ {
2
+ "exception" : null,
3
+ "result" : {
4
+ "id" : "CAP4CaRo=fQu-7TkamEOH87i2CQyNznk6tUoUsoHpV5aU-TMqKQ@mail.gmail.com",
5
+ "boundary" : null,
6
+ "alternativeBoundary" : "0000000000002f88560628478f99",
7
+ "sender" : {
8
+ "name" : "Bed: für Test!",
9
+ "mailAddress" : "this-is-a-test-email-address@gmail.com",
10
+ "valid" : true
11
+ },
12
+ "toRecipients" : [ {
13
+ "name" : "",
14
+ "mailAddress" : "this-is-a-test-email-address@tutao.de",
15
+ "valid" : true
16
+ } ],
17
+ "ccRecipients" : [ ],
18
+ "bccRecipients" : [ ],
19
+ "replyTo" : [ ],
20
+ "inReplyTo" : null,
21
+ "references" : [ ],
22
+ "autoSubmitted" : null,
23
+ "sentDate" : 1733137670000,
24
+ "subject" : "test",
25
+ "plainBodyText" : "\r\n<div dir=\"ltr\">test<br></div>\r\n",
26
+ "htmlBodyText" : null,
27
+ "attachedMessages" : [ ],
28
+ "attachedFiles" : [ ],
29
+ "mailHeaders" : "From 1817326565723760995@xxx Mon Dec 02 11:07:50 +0000 2024\nX-GM-THRID: 1817326560552955180\nX-Gmail-Labels: Archived,Sent\nMIME-Version: 1.0\nDate: Mon, 2 Dec 2024 12:07:50 +0100\nMessage-ID: <CAP4CaRo=fQu-7TkamEOH87i2CQyNznk6tUoUsoHpV5aU-TMqKQ@mail.gmail.com>\nSubject: test\nFrom: \"Bed: für Test!\" <this-is-a-test-email-address@gmail.com>\nTo: this-is-a-test-email-address@tutao.de\nContent-Type: multipart/alternative; boundary=\"0000000000002f88560628478f99\"",
30
+ "spfResult" : "None",
31
+ "listUnsubscribe" : false,
32
+ "mailAuthenticationResult" : null
33
+ }
34
+ }
@@ -0,0 +1,21 @@
1
+ From 1817326565723760995@xxx Mon Dec 02 11:07:50 +0000 2024
2
+ X-GM-THRID: 1817326560552955180
3
+ X-Gmail-Labels: Archived,Sent
4
+ MIME-Version: 1.0
5
+ Date: Mon, 2 Dec 2024 12:07:50 +0100
6
+ Message-ID: <CAP4CaRo=fQu-7TkamEOH87i2CQyNznk6tUoUsoHpV5aU-TMqKQ@mail.gmail.com>
7
+ Subject: test
8
+ From: =?UTF-8?B?QmVkOiBmw7xyIFRlc3Qh?= <this-is-a-test-email-address@gmail.com>
9
+ To: this-is-a-test-email-address@tutao.de
10
+ Content-Type: multipart/alternative; boundary="0000000000002f88560628478f99"
11
+
12
+ --0000000000002f88560628478f99
13
+
14
+ test
15
+
16
+ --0000000000002f88560628478f99
17
+
18
+
19
+ <div dir="ltr">test<br></div>
20
+
21
+ --0000000000002f88560628478f99--
@@ -0,0 +1,36 @@
1
+ {
2
+ "exception" : null,
3
+ "result" : {
4
+ "id" : "CAP4CaRo=fQu-7TkamEOH87i2CQyNznk6tUoUsoHpV5aU-TMqKQ@mail.gmail.com",
5
+ "boundary" : null,
6
+ "alternativeBoundary" : "0000000000002f88560628478f99",
7
+ "sender" : {
8
+ "name" : "Bed: für Test!",
9
+ "mailAddress" : "this-is-a-test-email-address@gmail.com",
10
+ "valid" : true
11
+ },
12
+ "toRecipients" : [
13
+ {
14
+ "name" : "",
15
+ "mailAddress" : "this-is-a-test-email-address@tutao.de",
16
+ "valid" : true
17
+ }
18
+ ],
19
+ "ccRecipients" : [],
20
+ "bccRecipients" : [],
21
+ "replyTo" : [],
22
+ "inReplyTo" : null,
23
+ "references" : [],
24
+ "autoSubmitted" : null,
25
+ "sentDate" : 1733137670000,
26
+ "subject" : "test",
27
+ "plainBodyText" : "<div dir=\"ltr\">test<br></div>\r\n",
28
+ "htmlBodyText" : null,
29
+ "attachedMessages" : [],
30
+ "attachedFiles" : [],
31
+ "mailHeaders" : "From 1817326565723760995@xxx Mon Dec 02 11:07:50 +0000 2024\nX-GM-THRID: 1817326560552955180\nX-Gmail-Labels: Archived,Sent\nMIME-Version: 1.0\nDate: Mon, 2 Dec 2024 12:07:50 +0100\nMessage-ID: <CAP4CaRo=fQu-7TkamEOH87i2CQyNznk6tUoUsoHpV5aU-TMqKQ@mail.gmail.com>\nSubject: test\nFrom: \"Bed: für Test!\" <this-is-a-test-email-address@gmail.com>\nTo: this-is-a-test-email-address@tutao.de\nContent-Type: multipart/alternative; boundary=\"0000000000002f88560628478f99\"",
32
+ "spfResult" : "None",
33
+ "listUnsubscribe" : false,
34
+ "mailAuthenticationResult" : null
35
+ }
36
+ }
@@ -0,0 +1,21 @@
1
+ From 1817326565723760995@xxx Mon Dec 02 11:07:50 +0000 2024
2
+ X-GM-THRID: 1817326560552955180
3
+ X-Gmail-Labels: Archived,Sent
4
+ MIME-Version: 1.0
5
+ Date: Mon, 2 Dec 2024 12:07:50 +0100
6
+ Message-ID: <CAP4CaRo=fQu-7TkamEOH87i2CQyNznk6tUoUsoHpV5aU-TMqKQ@mail.gmail.com>
7
+ Subject: test
8
+ From: =?UTF-8?B?QmVkOiBmw7xyIFRlc3Qh?= <this-is-a-test-email-address@gmail.com>
9
+ To: this-is-a-test-email-address@tutao.de
10
+ Content-Type: multipart/alternative; boundary="0000000000002f88560628478f99"
11
+
12
+ --0000000000002f88560628478f99
13
+ Content-Type: text/plain; charset="UTF-8"
14
+
15
+ test
16
+
17
+ --0000000000002f88560628478f99
18
+
19
+ <div dir="ltr">test<br></div>
20
+
21
+ --0000000000002f88560628478f99--
@@ -1,24 +0,0 @@
1
- repositories {
2
- mavenLocal()
3
- maven {
4
- credentials(PasswordCredentials::class)
5
- url = uri("https://next.tutao.de/nexus/content/groups/public/")
6
- }
7
- }
8
-
9
- plugins {
10
- java
11
- }
12
-
13
- dependencies {
14
- implementation("com.icegreen:greenmail-standalone:2.1.0")
15
- }
16
-
17
- tasks.jar {
18
- val dependencies = configurations
19
- .runtimeClasspath
20
- .get()
21
- .map(::zipTree) // OR .map { zipTree(it) }
22
- from(dependencies)
23
- duplicatesStrategy = DuplicatesStrategy.EXCLUDE
24
- }
@@ -1,24 +0,0 @@
1
- rootProject.name = "greenmail-test-server"
2
-
3
- pluginManagement {
4
- repositories {
5
- mavenLocal()
6
- maven {
7
- url = uri("https://next.tutao.de/nexus/content/groups/public/")
8
- credentials(PasswordCredentials::class)
9
- }
10
- }
11
- }
12
-
13
- buildscript {
14
- repositories {
15
- mavenLocal()
16
- maven {
17
- credentials(PasswordCredentials::class)
18
- url = uri("https://next.tutao.de/nexus/content/groups/public/")
19
- }
20
- }
21
- dependencies {
22
- classpath(group = "de.tutao.gradle", name = "devDefaults", version = "3.6.2")
23
- }
24
- }
@@ -1,63 +0,0 @@
1
- package greenmailserver;
2
-
3
- import com.icegreen.greenmail.user.GreenMailUser;
4
- import com.icegreen.greenmail.user.UserException;
5
- import com.icegreen.greenmail.util.GreenMail;
6
- import com.icegreen.greenmail.util.ServerSetup;
7
- import jakarta.mail.MessagingException;
8
- import jakarta.mail.internet.MimeMessage;
9
-
10
- import java.io.ByteArrayInputStream;
11
-
12
-
13
- public class GreenMailServer {
14
- public static final String imapsHost = "127.0.0.1";
15
-
16
- private GreenMail greenMail;
17
-
18
- public GreenMailUser userMap;
19
- public GreenMailUser userSug;
20
-
21
- public GreenMailServer(Integer p) {
22
- setSystemClassLoaderForCurrentThreadContext();
23
-
24
- ServerSetup defaultImapsProps = new ServerSetup(p, imapsHost, "imaps");
25
- try {
26
- greenMail = new GreenMail(defaultImapsProps);
27
- } catch (Exception e) {
28
- e.printStackTrace();
29
- }
30
-
31
- greenMail.start();
32
-
33
- try {
34
- userMap = greenMail.getUserManager().createUser("map@example.org", "map@example.org", "map");
35
- userSug = greenMail.getUserManager().createUser("sug@example.org", "sug@example.org", "sug");
36
- } catch (UserException e) {
37
- throw new RuntimeException(e);
38
- }
39
- }
40
-
41
- public void stop() {
42
- greenMail.stop();
43
- }
44
-
45
- public void store_mail(String recipientAddress, String mimeMsg) throws MessagingException {
46
- var recipient = greenMail.getUserManager().getUserByEmail(recipientAddress);
47
- var mimeMessage = new MimeMessage(null, new ByteArrayInputStream(mimeMsg.getBytes()));
48
- recipient.deliver(mimeMessage);
49
- }
50
-
51
-
52
- // ========= configuration required for (rust) jni interface ==================
53
-
54
- // For the class loaded by jni, .getCurrentThread().getContextClassLoader() will be null
55
- // set it to systemClassLoader
56
- public static void setSystemClassLoaderForCurrentThreadContext() {
57
- if (Thread.currentThread().getContextClassLoader() == null) {
58
- ClassLoader cl = ClassLoader.getSystemClassLoader();
59
- Thread.currentThread().setContextClassLoader(cl);
60
- }
61
- }
62
-
63
- }