diff --git a/DatabaseLayout.txt b/DatabaseLayout.txt
new file mode 100644
index 0000000..705a925
--- /dev/null
+++ b/DatabaseLayout.txt
@@ -0,0 +1,49 @@
+IMAP
+> Boxes
+ > Messages (ordered by uid)
+
+AETHER
+> Conversations
+ > (Parsed) Messages (indexed by MessageID)
+
+MONGO
+> Box
+ > BoxID
+ > UIDValidity
+ > UIDNext
+ > SeqNext
+ > ...
+
+> MsgUUID
+ > MessageID
+ > Box
+ > UID
+
+> Participant
+ Name
+ Image
+ Addresses
+ ...
+
+> Messages
+ > MsgUUID
+ > Subject
+ > Participant[]
+ > Time
+ > ParsedContent
+
+> Conversations
+ > Title
+ > Archived
+ > LatestMessageTime
+ > Participant[]
+ > Messages[]
+
+Box
+SEQNO / UID / SUBJECT
+
+1 / 1: aaa
+2 / 3: bbb
+--- 3 / 7: ccc
+---
+--- 3 / 8: ddd
diff --git a/client/res/logo.svg b/client/res/logo.svg
new file mode 100755
index 0000000..17ea380
--- /dev/null
+++ b/client/res/logo.svg
@@ -0,0 +1,188 @@
+
+
+
+
diff --git a/client/src/App.tsx b/client/src/App.tsx
index 7f521ec..e7c1e1e 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -68,6 +68,12 @@ export default function App() {
contacts={contacts[account.id]} conversation={conversation}/>}
}
+ {!account &&
+
+
+
+
}
);
}
diff --git a/common/package.json b/common/package.json
index 2a174c0..bafb4d9 100644
--- a/common/package.json
+++ b/common/package.json
@@ -6,7 +6,7 @@
"main": "build/Main.js",
"scripts": {
"dev": "nodemon",
- "build": "tsc --project tsconfig.json",
+ "build": "tsc --project tsconfig.json --incremental",
"clean": "find build -name '*' -not -name 'package.json' -not -path 'build/node_modules*' -not -name 'build' -delete"
},
"repository": {
diff --git a/package.json b/package.json
index f2a3efd..6a41292 100644
--- a/package.json
+++ b/package.json
@@ -30,5 +30,8 @@
"bugs": {
"url": "https://github.com/Aurailus/Aether/issues"
},
- "homepage": "https://github.com/Aurailus/Aether#readme"
+ "homepage": "https://github.com/Aurailus/Aether#readme",
+ "dependencies": {
+ "mongoose": "^5.13.8"
+ }
}
diff --git a/server/.eslintrc.js b/server/.eslintrc.js
index a94f8ec..6e38886 100755
--- a/server/.eslintrc.js
+++ b/server/.eslintrc.js
@@ -57,7 +57,6 @@ module.exports = {
}
}
],
- "@typescript-eslint/member-ordering": "error",
"@typescript-eslint/no-empty-function": "error",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-parameter-properties": "off",
diff --git a/server/package-lock.json b/server/package-lock.json
index acbdd43..9af343a 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -237,6 +237,36 @@
"integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==",
"dev": true
},
+ "@typegoose/typegoose": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/@typegoose/typegoose/-/typegoose-8.2.0.tgz",
+ "integrity": "sha512-iibEA5V2FqtadURFFT2Anq/NnP8oDnlnuMFmccJsBLxanEoNH78hAbdJ9GFoND6BakFInF9BWuhZfpo2OXOb0Q==",
+ "requires": {
+ "lodash": "^4.17.20",
+ "loglevel": "^1.7.0",
+ "reflect-metadata": "^0.1.13",
+ "semver": "^7.3.2",
+ "tslib": "^2.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "7.3.5",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
+ "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
+ "@types/bson": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz",
+ "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/imap": {
"version": "0.8.35",
"resolved": "https://registry.npmjs.org/@types/imap/-/imap-0.8.35.tgz",
@@ -261,25 +291,20 @@
"@types/node": "*"
}
},
+ "@types/mongodb": {
+ "version": "3.6.20",
+ "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz",
+ "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==",
+ "requires": {
+ "@types/bson": "*",
+ "@types/node": "*"
+ }
+ },
"@types/node": {
"version": "16.7.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.2.tgz",
"integrity": "sha512-TbG4TOx9hng8FKxaVrCisdaxKxqEwJ3zwHoCWXZ0Jw6mnvTInpaB99/2Cy4+XxpXtjNv9/TgfGSvZFyfV/t8Fw=="
},
- "@types/webidl-conversions": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz",
- "integrity": "sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q=="
- },
- "@types/whatwg-url": {
- "version": "8.2.1",
- "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.1.tgz",
- "integrity": "sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ==",
- "requires": {
- "@types/node": "*",
- "@types/webidl-conversions": "*"
- }
- },
"@typescript-eslint/eslint-plugin": {
"version": "4.29.3",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.3.tgz",
@@ -514,17 +539,55 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
- "base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
- },
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true
},
+ "bl": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
+ "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
+ "requires": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "bluebird": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
+ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
+ },
"boolean": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz",
@@ -576,21 +639,9 @@
}
},
"bson": {
- "version": "4.5.1",
- "resolved": "https://registry.npmjs.org/bson/-/bson-4.5.1.tgz",
- "integrity": "sha512-XqFP74pbTVLyLy5KFxVfTUyRrC1mgOlmu/iXHfXqfCKT59jyP9lwbotGfbN59cHBRbJSamZNkrSopjv+N0SqAA==",
- "requires": {
- "buffer": "^5.6.0"
- }
- },
- "buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "requires": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
+ "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg=="
},
"buffer-crc32": {
"version": "0.2.13",
@@ -1619,11 +1670,6 @@
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"dev": true
},
- "ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
- },
"ignore": {
"version": "5.1.8",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
@@ -1880,8 +1926,7 @@
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash.clonedeep": {
"version": "4.5.0",
@@ -1920,6 +1965,11 @@
}
}
},
+ "loglevel": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
+ "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw=="
+ },
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
@@ -1930,7 +1980,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
"requires": {
"yallist": "^4.0.0"
}
@@ -2031,54 +2080,98 @@
}
},
"mongodb": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.1.1.tgz",
- "integrity": "sha512-fbACrWEyvr6yl0sSiCGV0sqEiBwTtDJ8iSojmkDjAfw9JnOZSAkUyv9seFSPYhPPKwxp1PDtyjvBNfMDz0WBLQ==",
+ "version": "3.6.11",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.11.tgz",
+ "integrity": "sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw==",
"requires": {
- "bson": "^4.5.1",
- "denque": "^1.5.0",
- "mongodb-connection-string-url": "^2.0.0",
+ "bl": "^2.2.1",
+ "bson": "^1.1.4",
+ "denque": "^1.4.1",
+ "optional-require": "^1.0.3",
+ "safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
}
},
- "mongodb-connection-string-url": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.0.0.tgz",
- "integrity": "sha512-M0I1vyLoq5+HQTuPSJWbt+hIXsMCfE8sS1fS5mvP9R2DOMoi2ZD32yWqgBIITyu0dFu4qtS50erxKjvUeBiyog==",
- "requires": {
- "@types/whatwg-url": "^8.2.1",
- "whatwg-url": "^9.1.0"
- }
- },
"mongoose": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.0.1.tgz",
- "integrity": "sha512-WESkAtJuJqXKjiQj+HiL3Ipr6eLWx9RIrjCE2HzxScUApnFLXSHdd5gGCeEE3Pl+qcill4fGYy/uysThCMQ6PQ==",
+ "version": "5.13.8",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.8.tgz",
+ "integrity": "sha512-z3d+qei9Dem/LxRcJi0cdGPKzQnYk71oHEsEfYm17JA/vLiAbJiGuBS2hW7vkd9afkPAqu3KsPZh2ax0c5iPQw==",
"requires": {
- "bson": "^4.2.2",
+ "@types/mongodb": "^3.5.27",
+ "bson": "^1.1.4",
"kareem": "2.3.2",
- "mongodb": "4.1.1",
+ "mongodb": "3.6.11",
+ "mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.8.3",
- "mquery": "4.0.0",
+ "mquery": "3.2.5",
"ms": "2.1.2",
+ "optional-require": "1.0.x",
"regexp-clone": "1.0.0",
+ "safe-buffer": "5.2.1",
"sift": "13.5.2",
"sliced": "1.0.1"
+ },
+ "dependencies": {
+ "bson": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
+ "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg=="
+ },
+ "mongodb": {
+ "version": "3.6.11",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.11.tgz",
+ "integrity": "sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw==",
+ "requires": {
+ "bl": "^2.2.1",
+ "bson": "^1.1.4",
+ "denque": "^1.4.1",
+ "optional-require": "^1.0.3",
+ "safe-buffer": "^5.1.2",
+ "saslprep": "^1.0.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ }
}
},
+ "mongoose-legacy-pluralize": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
+ "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
+ },
"mpath": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.3.tgz",
"integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA=="
},
"mquery": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.0.tgz",
- "integrity": "sha512-nGjm89lHja+T/b8cybAby6H0YgA4qYC/lx6UlwvHGqvTq8bDaNeCwl1sY8uRELrNbVWJzIihxVd+vphGGn1vBw==",
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
+ "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
"requires": {
- "debug": "4.x",
+ "bluebird": "3.5.1",
+ "debug": "3.1.0",
"regexp-clone": "^1.0.0",
+ "safe-buffer": "5.1.2",
"sliced": "1.0.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
}
},
"ms": {
@@ -2175,6 +2268,11 @@
"wrappy": "1"
}
},
+ "optional-require": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
+ "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA=="
+ },
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -2276,8 +2374,7 @@
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress": {
"version": "2.0.3",
@@ -2311,7 +2408,8 @@
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
},
"pupa": {
"version": "2.1.1",
@@ -2468,8 +2566,7 @@
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"saslprep": {
"version": "1.0.3",
@@ -2793,14 +2890,6 @@
"nopt": "~1.0.10"
}
},
- "tr46": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
- "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
- "requires": {
- "punycode": "^2.1.1"
- }
- },
"ts-node": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz",
@@ -2881,14 +2970,6 @@
"is-typedarray": "^1.0.0"
}
},
- "typegoose": {
- "version": "5.9.1",
- "resolved": "https://registry.npmjs.org/typegoose/-/typegoose-5.9.1.tgz",
- "integrity": "sha512-D+vMhNyZeKBZHrmJFZwOodl3T9W2NOXY+hbnW/f1n60oEL8+L15eryFc9C6fAKrlnkgpui+kdQnNXsLwx2MgCw==",
- "requires": {
- "reflect-metadata": "^0.1.13"
- }
- },
"typescript": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
@@ -2985,8 +3066,7 @@
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
- "dev": true
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"v8-compile-cache": {
"version": "2.3.0",
@@ -2994,20 +3074,6 @@
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
"dev": true
},
- "webidl-conversions": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
- "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
- },
- "whatwg-url": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-9.1.0.tgz",
- "integrity": "sha512-CQ0UcrPHyomtlOCot1TL77WyMIm/bCwrJ2D6AOKGwEczU9EpyoqAokfqrf/MioU9kHcMsmJZcg1egXix2KYEsA==",
- "requires": {
- "tr46": "^2.1.0",
- "webidl-conversions": "^6.1.0"
- }
- },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3059,8 +3125,7 @@
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
},
"yauzl": {
"version": "2.10.0",
diff --git a/server/package.json b/server/package.json
index c17f3a0..98a4a28 100644
--- a/server/package.json
+++ b/server/package.json
@@ -7,7 +7,7 @@
"scripts": {
"dev": "nodemon",
"lint": "eslint -c .eslintrc.js src/**/*.ts",
- "build": "tsc --project tsconfig.json"
+ "build": "tsc --project tsconfig.json --incremental"
},
"repository": {
"type": "git",
@@ -25,7 +25,7 @@
"src"
],
"ext": ".ts,.tsx,.html",
- "exec": "npm run lint & npm run build && electron .",
+ "exec": "npm run lint & (npm run build && electron .)",
"quiet": true
},
"bugs": {
@@ -45,14 +45,14 @@
"eslint-plugin-jsdoc": "^36.0.8"
},
"dependencies": {
+ "@typegoose/typegoose": "^8.2.0",
"common": "file:../common/build",
"graphql": "^15.5.0",
"imap": "^0.8.19",
"log4js": "^6.3.0",
"md5": "^2.3.0",
- "mongodb": "^4.1.1",
- "mongoose": "^6.0.1",
- "tslib": "^2.2.0",
- "typegoose": "^5.9.1"
+ "mongodb": "^3.6.11",
+ "mongoose": "^5.13.8",
+ "tslib": "^2.2.0"
}
}
diff --git a/server/src/Account.ts b/server/src/Account.ts
index 5c3f22a..d3f1015 100644
--- a/server/src/Account.ts
+++ b/server/src/Account.ts
@@ -1,148 +1,372 @@
-import Message from './Message';
-import Conversation from './Conversation';
-import Imap, { ConnectionProperties, Message as RawMessage, MailboxType } from './Imap';
+import Imap from 'imap';
+import { ObjectID } from 'mongodb'
-interface Contact {
- name: string;
- addresses: Set;
-}
+// import Message from './Message';
+// import Conversation from './Conversation';
+import Log from './Log';
+import * as DB from './data/Data';
+import ImapController from './imap/ImapController';
+
+// interface Contact {
+// name: string;
+// addresses: Set;
+// }
export default class Account {
- private imap: Imap;
- private contacts: Contact[] = [];
- private conversations: Conversation[] = [];
-
- private name: string;
- private image: string;
private address: string;
- private unread: boolean;
+ private accountID: ObjectID;
+ private conn: ImapController;
+ // private contacts: Contact[] = [];
+ // private conversations: Conversation[] = [];
- constructor(name: string, image: string, connection: ConnectionProperties) {
- this.name = name;
- this.image = image;
- this.address = connection.username;
- this.unread = true;
+ constructor(data: DB.Account) {
+ this.accountID = data._id;
+ this.address = data.address;
+ Log.info('Created account %s', data.address);
- this.imap = new Imap(connection);
+ this.conn = new ImapController({
+ user: data.address,
+ password: data.password,
+ host: data.host,
+ port: data.port,
+ tls: data.tls
+ });
}
- async connect() {
- await this.imap.connect();
+ async init() {
+ await this.conn.connect();
- const messages = await this.fetchAllMessages();
- this.conversations = this.createConversations(messages).filter(c => c.active);
- this.contacts = this.createContacts(messages);
+ Log.perfStart('Synchronizing ' + this.address);
+ const remoteBoxes = await this.getBoxes();
+ await this.synchronizeBoxes(remoteBoxes);
+ await this.synchronizeMessages(remoteBoxes);
+ Log.perfEnd('Synchronizing ' + this.address);
+
+
+ // Log.info('Connected to %s', this.data.address);
+ // await this.synchronizeData();
+ // Log.perfEnd('Synchronizing ' + this.data.address);
+
+ // const messages = await this.fetchAllMessages();
+ // this.conversations = this.createConversations(messages).filter(c => c.active);
+ // this.contacts = this.createContacts(messages);
}
- getName() {
- return this.name;
+ async synchronizeBoxes(remoteBoxes: Map): Promise {
+ const currentBoxes = await DB.MailboxModel.find({ account: this.accountID });
+ await Promise.all([ ...remoteBoxes.values() ].map(async box => {
+ const existing = currentBoxes.filter(b => b.path === box.name)[0];
+ if (!existing) await this.addNewBox(box);
+ else await this.refreshExistingBox(box, existing);
+ }));
}
- getAddress() {
- return this.address;
+ private async addNewBox(box: Imap.Box) {
+ await DB.MailboxModel.create({
+ account: this.accountID,
+ name: box.name, // TODO: This
+ path: box.name,
+ delimiter: '.', // TODO: and this
+ type: DB.MailboxType.Inbox,
+ treeTypes: new Set([ DB.MailboxType.Inbox ]),
+ parent: undefined, // and this
+ uidValidity: box.uidvalidity,
+ uidNext: 1,
+ } as DB.Create);
}
- getImage() {
- return this.image;
+ private async refreshExistingBox(remote: Imap.Box, _existing: DB.Mailbox) {
+ Log.debug('existing box ' + remote.name);
}
- hasUnreads() {
- return this.unread;
- }
-
- getConversations() {
- return this.conversations;
- }
-
- getContacts() {
- return this.contacts;
- }
-
- getMessages(_messages: string[]): Message[] {
- return [{
- id: 'AOUEOAEu',
- date: new Date(),
- from: 'me@auri.xyz',
- to: [ 'nicole@aurailus.design' ],
- content: 'Lorem ipsum dolor sit amet.
'
- }];
- }
-
- async fetchAllMessages(): Promise {
- const boxes = (await this.imap.listBoxes()).filter(box =>
- !box.treeTypes.has(MailboxType.Spam) && !box.treeTypes.has(MailboxType.Trash));
-
- let allMeta: RawMessage[] = [];
-
- for (let box of boxes) {
- await this.imap.openBox(box.path);
- const meta = await this.imap.fetchMessages('1:*');
- Object.keys(meta).forEach(id => allMeta.push(meta[id]));
- }
-
- allMeta = allMeta.sort((a, b) => +a.date - +b.date);
- return allMeta;
- }
-
- private createConversations(messages: RawMessage[]): Conversation[] {
- const conversations: Conversation[] = [];
-
- messages.forEach(message => {
- if (message.replyTo) {
- for (let conversation of conversations) {
- for (let reference of [ ...message.references, message.replyTo ]) {
- if (conversation.messages.has(reference)) {
- conversation.date = message.date;
- conversation.messages.add(message.messageId);
- conversation.title = this.cleanSubjectLine(message.subject);
- conversation.active = conversation.active || message.active;
- message.to.forEach(p => conversation.participants.add(p.address));
- conversation.participants.add(message.from.address);
- return;
- }
- }
+ async synchronizeMessages(remoteBoxes: Map): Promise {
+ const currentBoxes = await DB.MailboxModel.find({ account: this.accountID });
+ await Promise.all(currentBoxes.map(async box => {
+ const remote = remoteBoxes.get(box.path)!;
+ console.log(box.uidNext, remote.uidnext);
+ // if (box.uidValidity !== remote.uidvalidity) {
+ // // Reacquire existing messages
+ // }
+ if (box.uidNext !== remote.uidnext) {
+ // Get new messages
+ const messages = await (await this.conn.get(box.path)).fetchMessagesByUID(`${box.uidNext}:*`);
+ await DB.MailboxModel.updateOne({ _id: box._id }, { uidNext: remote.uidnext });
+ if (messages.size > 0) {
+ console.log('adding ' + messages.size + ' messages.');
+ await DB.MessageModel.insertMany([ ...messages.keys() ].map(uid => {
+ const message = messages.get(uid)!;
+ const headers = this.parseHeaders(message.headers);
+ return {
+ account: this.accountID,
+ box: box._id,
+ uid: uid,
+ messageId: headers.get('MESSAGE-ID') ?? '[!DATE:' + (+message.attrs.date) + ']',
+ subject: this.cleanSubject(headers.get('SUBJECT')),
+ date: message.attrs.date,
+ } as DB.Message;
+ }));
}
}
-
- conversations.push({
- title: this.cleanSubjectLine(message.subject),
- messages: new Set([ message.messageId ]),
- date: message.date,
- active: message.active,
- participants: new Set([ message.from.address, ...message.to.map(p => p.address) ])
- });
- });
-
- conversations.forEach(conversation => {
- conversation.participants.delete(this.address);
- });
-
- return conversations.sort((a, b) => +a.date - +b.date);
+ }));
}
- private createContacts(messages: RawMessage[]): Contact[] {
- const contacts: Contact[] = [];
+ private async getBoxes(): Promise