diff options
-rw-r--r-- | Readme.md | 8 | ||||
-rw-r--r-- | app/imap.js | 38 | ||||
-rw-r--r-- | app/src/pages/Home.vue | 16 | ||||
-rw-r--r-- | app/src/store.js | 14 | ||||
-rw-r--r-- | package.json | 5 | ||||
-rw-r--r-- | test/test.js | 82 |
6 files changed, 146 insertions, 17 deletions
@@ -1 +1,9 @@ - https://busylog.net/telnet-imap-commands-note/ + +## Test + +``` +cd test/docker +docker-compose up -d +npm run test +``` diff --git a/app/imap.js b/app/imap.js index 1ac76a4..f2e8cc2 100644 --- a/app/imap.js +++ b/app/imap.js @@ -3,6 +3,7 @@ const { ImapFlow } = require('imapflow'); ipcMain.on('imap:listTree:from', listTreeFrom); ipcMain.on('imap:listTree:to', listTreeTo); +ipcMain.on('imap:migrate', migrate); async function connect (options) { const client = new ImapFlow({ @@ -32,3 +33,40 @@ async function listTreeTo (event, options) { event.reply('imap:listTree:to:reply', await client.listTree()); await client.logout(); } + +async function migrate (event, { from, to }) { + const fromClient = await connect(from); + const toClient = await connect(to); + + const fromFolders = (await fromClient.list()).filter((folder) => folder.subscribed); + for (const fromFolder of fromFolders) { + try { + await toClient.mailboxCreate(fromFolder.path); + } catch (e) {} + + const fromMailbox = await fromClient.getMailboxLock(fromFolder.path); + const toMailbox = await toClient.getMailboxLock(fromFolder.path); + try { + const toMsgsGenerator = await toClient.fetch('1:*', { flags: true, envelope: true, source: true }); + const toMsgs = []; + for await (const toMsg of toMsgsGenerator) { + toMsgs.push(toMsg); + } + const fromMsgsGenerator = await fromClient.fetch('1:*', { flags: true, envelope: true, source: true }); + + for await (const fromMsg of fromMsgsGenerator) { + if (toMsgs.some((toMsg) => Buffer.compare(toMsg.source, fromMsg.source) === 0)) { + continue; + } + + await toClient.append(fromFolder.path, fromMsg.source, Array.from(fromMsg.flags), fromMsg.envelope.date); + } + } finally { + fromMailbox.release(); + toMailbox.release(); + } + } + + await fromClient.logout(); + await toClient.logout(); +} diff --git a/app/src/pages/Home.vue b/app/src/pages/Home.vue index 2fe4030..bfe92bf 100644 --- a/app/src/pages/Home.vue +++ b/app/src/pages/Home.vue @@ -12,17 +12,11 @@ <ul v-if="from.folders"> <Folders :folder="from.folders" /> </ul> - <code> - {{ from.folders }} - </code> <h1>TO</h1> <ul v-if="to.folders"> <Folders :folder="to.folders" /> </ul> - <code> - {{ to.folders }} - </code> </div> </template> @@ -79,7 +73,10 @@ export default { }, async migrate () { - + this.$electron.ipcRenderer.send('imap:migrate', { + from: JSON.parse(JSON.stringify(this.from)), + to: JSON.parse(JSON.stringify(this.to)), + }); }, }, }; @@ -96,4 +93,9 @@ body { display: flex; justify-content: space-between; } + +ul { + padding-left: 1em; + list-style-type: dot; +} </style> diff --git a/app/src/store.js b/app/src/store.js index db5a9fa..818689b 100644 --- a/app/src/store.js +++ b/app/src/store.js @@ -5,15 +5,15 @@ export default createStore({ return { from: { server: 'localhost', - port: '3143', - username: 'd@cool.de', - password: 'lolo11', + port: 3143, + username: 'from@example.org', + password: 'password', }, to: { - server: '', - port: '', - username: '', - password: '', + server: 'localhost', + port: 31432, + username: 'to@example.org', + password: 'password', }, }; }, diff --git a/package.json b/package.json index 964c484..c202375 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,9 @@ "main": "app/main.js", "scripts": { "start": "electron ./app/main.js", - "build": "webpack", - "watch": "npm run build -- --watch", + "watch": "webpack --watch", "lint": "eslint .", - "test": "echo \"Error: no test specified\" && exit 1" + "test": "node ./test/test.js" }, "author": "", "license": "ISC", diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..dad4b9f --- /dev/null +++ b/test/test.js @@ -0,0 +1,82 @@ +const { ImapFlow } = require('imapflow'); + +const clientFrom = new ImapFlow({ + host: 'localhost', + port: 3143, + auth: { + user: 'from@example.org', + pass: 'password', + }, +}); + +const clientTo = new ImapFlow({ + host: 'localhost', + port: 31432, + auth: { + user: 'to@example.org', + pass: 'password', + }, +}); + +(async () => { + await clientFrom.connect(); + await clientTo.connect(); + + const fromMailboxes = [ + 'From Test Parent.From Test Child', + 'From Test Parent.From Test Child 2.From Test Child Inner', + ]; + const toMailboxes = [ + 'To Test Parent.To Test Child', + 'To Test Parent.To Test Child 2.To Test Child Inner', + ]; + for (const mailbox of fromMailboxes) { + try { + await clientFrom.mailboxDelete(mailbox); + } catch (e) {} + try { + await clientTo.mailboxDelete(mailbox); + } catch (e) {} + + try { + await clientFrom.mailboxCreate(mailbox); + } catch (e) {} + } + for (const mailbox of toMailboxes) { + try { + await clientTo.mailboxDelete(mailbox); + } catch (e) {} + + try { + await clientTo.mailboxCreate(mailbox); + } catch (e) {} + } + + await clientFrom.append('INBOX', + 'From: test@example.org\r\n' + + 'To: from@example.org\r\n' + + 'Subject: FROM INBOX MESSAGE SUBJECT\r\n' + + '\r\n' + + 'FROM INBOX MESSAGE BODY', [], new Date()); + + await clientFrom.append('From Test Parent.From Test Child', + 'From: test@example.org\r\n' + + 'To: from@example.org\r\n' + + 'Subject: FROM TEST CHILD MESSAGE FLAGGED SUBJECT\r\n' + + '\r\n' + + 'FROM TEST CHILD MESSAGE FLAGGED BODY', ['\\FLAGGED'], new Date()); + + await clientFrom.append('From Test Parent.From Test Child', + 'From: test@example.org\r\n' + + 'To: from@example.org\r\n' + + 'Subject: FROM TEST CHILD MESSAGE DRAFT SUBJECT\r\n' + + '\r\n' + + 'FROM TEST CHILD MESSAGE DRAFT BODY', ['\\DRAFT'], new Date()); + + await clientFrom.append('From Test Parent.From Test Child 2.From Test Child Inner', + 'From: test@example.org\r\n' + + 'To: from@example.org\r\n' + + 'Subject: FROM TEST CHILD 2 INNER MESSAGE SEEN SUBJECT\r\n' + + '\r\n' + + 'FROM TEST CHILD 2 INNER MESSAGE SEEN BODY', ['\\SEEN'], new Date()); +})(); |