diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index 2ac235c..8c89ba6 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -630,6 +630,60 @@ EmailDAO.prototype.setFlags = function(options, callback) { } }; +/** + * Moves a message to another folder + * + * @param {Object} options.folder The origin folder + * @param {Object} options.destination The destination folder + * @param {Object} options.message The message that should be moved + * @param {Function} callback(error) Invoked when the message was moved, or an error occurred + */ +EmailDAO.prototype.moveMessage = function(options, callback) { + var self = this, + folder = options.folder, + destination = options.destination, + message = options.message; + + self.busy(); + + if (!self._account.online) { + // no action if we're not online + done({ + errMsg: 'Client is currently offline!', + code: 42 + }); + return; + } + + folder.messages.splice(folder.messages.indexOf(message), 1); + + // delete from IMAP + self._imapMoveMessage({ + folder: folder, + destination: destination, + uid: message.uid + }, function(err) { + if (err) { + // re-add the message to the folder in case of an error, only makes sense if IMAP errors + folder.messages.unshift(message); + done(err); + return; + } + + // delete from local indexed db, will be synced when new folder is opened + self._localDeleteMessage({ + folder: folder, + uid: message.uid + }, done); + }); + + function done(err) { + self.done(); // stop the spinner + updateUnreadCount(folder); // update the unread count, if necessary + callback(err); + } +}; + /** * Streams message content * @param {Object} options.message The message for which to retrieve the body @@ -1089,7 +1143,6 @@ EmailDAO.prototype.encrypt = function(options, callback) { self.done(); callback(err); }); - }; @@ -1552,14 +1605,30 @@ EmailDAO.prototype._imapDeleteMessage = function(options, callback) { return; } - // move the message to the trash folder - this._imapClient.moveMessage({ - path: options.folder.path, - destination: trash.path, + this._imapMoveMessage({ + folder: options.folder, + destination: trash, uid: options.uid }, callback); }; +/** + * Move stuff around on the server + * + * @param {String} options.folder The folder + * @param {Number} options.destination The destination folder + * @param {String} options.uid the message's uid + * @param {Function} callback (error) The callback when the message is moved + */ +EmailDAO.prototype._imapMoveMessage = function(options, callback) { + this._imapClient.moveMessage({ + path: options.folder.path, + destination: options.destination.path, + uid: options.uid + }, callback); +}; + + /** * Get list messsage headers without the body * @@ -1692,7 +1761,7 @@ EmailDAO.prototype._localDeleteMessage = function(options, callback) { /** * Uploads a message to the sent folder, if necessary. * Calls back immediately if ignoreUploadOnSent == true or not sent folder was found. - * + * * @param {String} options.message The rfc2822 compatible raw ASCII e-mail source * @param {Function} callback (error) The callback when the imap client is done uploading */ @@ -1724,7 +1793,6 @@ EmailDAO.prototype._uploadToSent = function(options, callback) { - // // // Helper Functions diff --git a/test/integration/email-dao-test.js b/test/integration/email-dao-test.js index b59b73a..570a098 100644 --- a/test/integration/email-dao-test.js +++ b/test/integration/email-dao-test.js @@ -17,7 +17,7 @@ describe('Email DAO integration tests', function() { chai.Assertion.includeStack = true; var emailDao, imapClient, imapMessages, imapFolders, imapServer, smtpServer, smtpClient, userStorage, - mockKeyPair, inbox; + mockKeyPair, inbox, spam; var testAccount = { user: 'safewithme.testuser@gmail.com', @@ -28,38 +28,13 @@ describe('Email DAO integration tests', function() { before(function(done) { imapMessages = [{ - raw: 'Message-id: \r\nSubject: hello 1\r\n\r\nWorld 1!', - internaldate: '14-Sep-2013 21:22:28 -0300', - uid: 500 - }, { - raw: 'Message-id: \r\nSubject: hello 2\r\n\r\nWorld 2!', - flags: ['\\Seen'], - uid: 600 - }, { - raw: 'Message-id: \r\nSubject: hello 3\r\n\r\nWorld 3!' - }, { - raw: 'From: sender name \r\n' + - 'To: Receiver name \r\n' + - 'Subject: hello 4\r\n' + - 'Message-Id: \r\n' + - 'Date: Fri, 13 Sep 2013 15:01:00 +0300\r\n' + - '\r\n' + - 'World 4!' - }, { - raw: 'Message-id: \r\nSubject: hello 5\r\n\r\nWorld 5!' - }, { - raw: 'Message-id: Subject: hello 6\r\n\r\nWorld 6!' - }, { - raw: 'Message-id: \nFrom: safewithme.testuser@gmail.com\nTo: safewithme.testuser@gmail.com\nSubject: enigmail encrypted pgp/mime with attachment\nContent-Type: multipart/encrypted;\n protocol=\"application/pgp-encrypted\";\n boundary=\"abc\"\n\nThis is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)\n--abc\nContent-Type: application/pgp-encrypted\nContent-Description: PGP/MIME version identification\n\nVersion: 1\n\n--abc\nContent-Type: application/octet-stream; name=\"encrypted.asc\"\nContent-Description: OpenPGP encrypted message\nContent-Disposition: inline; filename=\"encrypted.asc\"\n\n-----BEGIN PGP MESSAGE-----\nVersion: GnuPG/MacGPG2 v2.0.22 (Darwin)\nComment: GPGTools - http://gpgtools.org\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\n\n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\n=ZQ8O\n-----END PGP MESSAGE-----\n\n--abc--\n', - internaldate: '14-Sep-2013 20:22:28 -0300', + raw: 'Message-id: \r\nSubject: hello 3\r\n\r\nWorld 3!', uid: 800 }, { - raw: "Message-id: \nFrom: safewithme.testuser@gmail.com\nTo: safewithme.testuser@gmail.com\nSubject: enigmail encrypted signed pgp/mime with attachment\nContent-Type: multipart/encrypted;\n protocol=\"application/pgp-encrypted\";\n boundary=\"abc\"\n\nThis is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)\n--abc\nContent-Type: application/pgp-encrypted\nContent-Description: PGP/MIME version identification\n\nVersion: 1\n\n--abc\nContent-Type: application/octet-stream; name=\"encrypted.asc\"\nContent-Description: OpenPGP encrypted message\nContent-Disposition: inline; filename=\"encrypted.asc\"\n\n-----BEGIN PGP MESSAGE-----\nVersion: GnuPG/MacGPG2 v2.0.22 (Darwin)\nComment: GPGTools - http://gpgtools.org\nComment: Using GnuPG with Thunderbird - http://www.enigmail.net/\n\n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\nyjGWLplWnA==\n=p4q6\n-----END PGP MESSAGE-----\n\n--abc--\n", - internaldate: '14-Sep-2013 22:22:28 -0300', + raw: 'Message-id: \r\nSubject: hello 5\r\n\r\nWorld 5!', uid: 801 }, { raw: 'Delivered-To: throwaway.felix@gmail.com\r\nReceived: by 10.42.174.3 with SMTP id t3csp241492icz;\r\n Wed, 25 Jun 2014 05:45:10 -0700 (PDT)\r\nX-Received: by 10.180.20.206 with SMTP id p14mr10320792wie.26.1403700309809;\r\n Wed, 25 Jun 2014 05:45:09 -0700 (PDT)\r\nReturn-Path: \r\nReceived: from mail-wi0-f172.google.com (mail-wi0-f172.google.com [209.85.212.172])\r\n by mx.google.com with ESMTPS id d9si4992982wje.76.2014.06.25.05.44.59\r\n for \r\n (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);\r\n Wed, 25 Jun 2014 05:44:59 -0700 (PDT)\r\nReceived-SPF: pass (google.com: domain of mail@felixhammerl.com designates 209.85.212.172 as permitted sender) client-ip=209.85.212.172;\r\nAuthentication-Results: mx.google.com;\r\n spf=pass (google.com: domain of mail@felixhammerl.com designates 209.85.212.172 as permitted sender) smtp.mail=mail@felixhammerl.com\r\nReceived: by mail-wi0-f172.google.com with SMTP id hi2so7776737wib.11\r\n for ; Wed, 25 Jun 2014 05:44:59 -0700 (PDT)\r\nX-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;\r\n d=1e100.net; s=20130820;\r\n h=x-gm-message-state:from:content-type:subject:message-id:date:to\r\n :mime-version;\r\n bh=s4NMXN5u+JHQKeYuoCYcsqfFEEqH1GauOiEzb6O3ma0=;\r\n b=khBrYuEYLBy6IZOWmdXQi4lvi9PhH67+zvkfZUJ5aV/SyWZUHNsuXsnJThI0Fj7Xbx\r\n XbeSDiZCJhD1XZgkVoERUmKFIgRmQURgm44SC6ZgBgDJvHXB2gVapPUAPIWIM9S8OuqH\r\n n5YKWob9M4GO6jV5WrTGx+tiDP6GiRO0dM4/nGe+MC+xAvVMPtqESxhNu6L6gGXJHVXC\r\n XMVx6ZP64SsLrFOCEqGCea49bPi7ee474nT+uL2zNc69fbpkqdRzRGSrru+11Buf6ZDV\r\n gcTsA9Xrmpy0DwIUxkIDyyxaEgAMc9qnprM2f0CYuub26RnSryeLCdX4KRfcQaVEFKTd\r\n 38AQ==\r\nX-Gm-Message-State: ALoCoQmv6i9holEFjurNeEf5WgK5j3TDeENKMSkaBtsR08RK6tt9BShN8lvr0y0ktwghZqRf6823\r\nX-Received: by 10.194.174.35 with SMTP id bp3mr1720884wjc.33.1403700299213;\r\n Wed, 25 Jun 2014 05:44:59 -0700 (PDT)\r\nReturn-Path: \r\nReceived: from [192.168.16.29] (host-88-217-174-118.customer.m-online.net. [88.217.174.118])\r\n by mx.google.com with ESMTPSA id wk8sm7294078wjb.22.2014.06.25.05.44.58\r\n for \r\n (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128);\r\n Wed, 25 Jun 2014 05:44:58 -0700 (PDT)\r\nFrom: Felix Hammerl \r\nContent-Type: multipart/alternative; boundary="Apple-Mail=_F62EFD38-9B1E-4FAC-A419-2C6F1F765727"\r\nSubject: asd\r\nMessage-Id: \r\nDate: Wed, 25 Jun 2014 14:44:56 +0200\r\nTo: throwaway.felix@gmail.com\r\nMime-Version: 1.0 (Mac OS X Mail 7.3 1878.2)\r\nX-Mailer: Apple Mail (2.1878.2)\r\n\r\n\r\n--Apple-Mail=_F62EFD38-9B1E-4FAC-A419-2C6F1F765727\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/plain;\r\n charset=us-ascii\r\n\r\nasd\r\n--Apple-Mail=_F62EFD38-9B1E-4FAC-A419-2C6F1F765727\r\nContent-Type: multipart/related;\r\n type="text/html";\r\n boundary="Apple-Mail=_0A59F0C0-A5CC-4402-B716-0D94B95BA062"\r\n\r\n\r\n--Apple-Mail=_0A59F0C0-A5CC-4402-B716-0D94B95BA062\r\nContent-Transfer-Encoding: 7bit\r\nContent-Type: text/html;\r\n charset=us-ascii\r\n\r\nasd\r\n--Apple-Mail=_0A59F0C0-A5CC-4402-B716-0D94B95BA062\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: inline;\r\n filename=image.jpg\r\nContent-Type: image/jpg;\r\n x-unix-mode=0644;\r\n name="image.jpg"\r\nContent-Id: <20154202-BB6F-49D7-A1BB-17E9937B42B5>\r\n\r\n/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdC\r\nIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA9tYAAQAA\r\nAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFj\r\ncHJ0AAABUAAAADNkZXNjAAABhAAAAGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAA\r\nABRnWFlaAAACLAAAABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAAD\r\nTAAAAIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAAAAxyVFJD\r\nAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENvcHlyaWdodCAoYykgMTk5\r\nOCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAAAAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEA\r\nAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAA\r\nAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAA\r\nAA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAFklFQyBo\r\ndHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\r\nAAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt\r\nIHNSR0IAAAAAAAAAAAAAAC5JRUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAt\r\nIHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcg\r\nQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENv\r\nbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAA\r\nABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAA\r\nAAABAAAAAAAAAAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAK\r\nAA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUA\r\nmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEy\r\nATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMC\r\nDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMh\r\nAy0DOANDA08DWgNmA3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4E\r\njASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3\r\nBkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgfCDII\r\nRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woRCicKPQpUCmoKgQqY\r\nCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUAN\r\nWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBh\r\nEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT\r\n5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReu\r\nF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7G2MbihuyG9oc\r\nAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCY\r\nIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZcl\r\nxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2\r\nK2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIx\r\nSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDec\r\nN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+\r\noD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXe\r\nRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN\r\n3E4lTm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYP\r\nVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1f\r\nD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/\r\naJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfBy\r\nS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyB\r\nfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuH\r\nn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLj\r\nk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3nWSd0p5Anq6f\r\nHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1\r\nq+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm4\r\n0blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZG\r\nxsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnU\r\ny9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM4lPi2+Nj\r\n4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozz\r\nGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QCMRXhpZgAA\r\nTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIA\r\nAIdpAAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAOgAQADAAAAAQABAACgAgAEAAAAAQAA\r\nAAGgAwAEAAAAAQAAAAEAAAAA/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwKDAwLCgsL\r\nDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJBQUJFA0LDRQUFBQUFBQU\r\nFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU/8AAEQgAAQABAwEiAAIR\r\nAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAAB\r\nfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5\r\nOkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeo\r\nqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMB\r\nAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYS\r\nQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNU\r\nVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5\r\nusLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8AzKKKKyPQ\r\nP//Z\r\n\r\n--Apple-Mail=_0A59F0C0-A5CC-4402-B716-0D94B95BA062--\r\n\r\n--Apple-Mail=_F62EFD38-9B1E-4FAC-A419-2C6F1F765727--', - internaldate: '14-Sep-2013 22:22:28 -0300', uid: 802 }, { description: "Apple Mail (attachment - PGP/MIME): Encrypted", @@ -118,7 +93,8 @@ describe('Email DAO integration tests', function() { raw: "MIME-Version: 1.0\r\nReceived: by 10.195.18.8 with HTTP; Fri, 4 Jul 2014 06:58:43 -0700 (PDT)\r\nDate: Fri, 4 Jul 2014 15:58:43 +0200\r\nDelivered-To: safewithme.testuser@gmail.com\r\nMessage-ID: \r\nSubject: \r\nFrom: safewithme testuser \r\nTo: safewithme testuser \r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n-----BEGIN PGP MESSAGE-----\r\nVersion: Mailvelope v0.9.0\r\nComment: Email security by Mailvelope - https://www.mailvelope.com\r\n\r\nwcBMA9f7k/zfv8I8AQf9F/Gm4HqJ/RlU2w+qIbJ4Va2PFR04OITlZIuUAWms\r\nPhPo4cGFbgxQnBzD7goswvNLXfEo4Q6/wxqT/wuwLGQdQJDoEduQxO5p77c1\r\n+dw/sa+pcr4jdwjebjV45NODVGDxgSF+YIwwKN3XXF6VqcisLLYBONYTHIU8\r\nKdTYR+R8SXSpMGISLUyyeY3Jaw5Et8cEoo0a1z8Fx04Ycv2Gw9Io0NVEqxYR\r\n86HUCLsOSARZC1aJ6hf9wheB528o0wuM6ESJ1LWnMWudyrkMjAiW6AiH89G8\r\npykTuYvc/GH3q7eEKNtY5khuZwi2Z7VJFrTeaEt4cb6HxlUlECudYw79uAHu\r\nt9JGATfaNeUpZV2xLEPBhsW5VrY4nDpbWVLp9stAKNFEiH6Ai/rgNwJ2A9Xr\r\nnWAji8YlIOOdO1iNVaYEQWEW1s5Hw5rYB83LKg==\r\n=ungD\r\n-----END PGP MESSAGE-----\r\n", uid: 816 }, { - raw: 'Message-id: Subject: hello 6\r\n\r\nWorld 6!' + raw: 'Message-id: \r\nSubject: moveme\r\n\r\nmoveme!', + uid: 900 }]; imapFolders = { @@ -287,7 +263,15 @@ describe('Email DAO integration tests', function() { inbox = emailDao._account.folders.filter(function(folder) { return folder.path === 'INBOX'; }).pop(); + spam = emailDao._account.folders.filter(function(folder) { + return folder.path === '[Gmail]/Spam'; + }).pop(); expect(inbox).to.exist; + expect(spam).to.exist; + + inbox.messages.sort(function(a, b) { + return a.uid - b.uid; + }); done(); }; @@ -338,16 +322,7 @@ describe('Email DAO integration tests', function() { emailDao.onIncomingMessage = function(messages) { expect(messages.length).to.equal(1); expect(messages[0].answered).to.be.false; - - emailDao.onIncomingMessage = function(messages) { - expect(messages.length).to.equal(1); - expect(messages[0].answered).to.be.true; - done(); - }; - - setTimeout(function() { - imapServer.appendMessage('INBOX', ['$My$Flag', '\\Answered'], false, 'Message-id: \r\nSubject: new message\r\n\r\nhello world!'); - }, 100); + done(); }; imapServer.appendMessage('INBOX', ['$My$Flag'], false, 'Message-id: \r\nSubject: new message\r\n\r\nhello world!'); @@ -356,9 +331,7 @@ describe('Email DAO integration tests', function() { it('should delete a message', function(done) { emailDao.deleteMessage({ folder: inbox, - message: { - uid: 600 - } + message: inbox.messages[0] }, function(err) { expect(err).to.not.exist; emailDao.openFolder({ @@ -373,10 +346,29 @@ describe('Email DAO integration tests', function() { }); }); + it('should move a message', function(done) { + emailDao.moveMessage({ + folder: inbox, + destination: spam, + message: inbox.messages[0] + }, function(err) { + expect(err).to.not.exist; + emailDao.openFolder({ + folder: { + path: '[Gmail]/Spam' + } + }, function(err, folder) { + expect(err).to.not.exist; + expect(folder.exists).to.equal(1); + done(); + }); + }); + }); + it('should get body', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[5] + message: inbox.messages[0] }, function(err, message) { expect(err).to.not.exist; expect(message.body).to.equal('World 5!'); @@ -384,32 +376,10 @@ describe('Email DAO integration tests', function() { }); }); - [7, 8].forEach(function(emailnr) { - it('should get and decrypt body #' + emailnr, function(done) { - emailDao.getBody({ - folder: inbox, - message: inbox.messages[emailnr] - }, function(err, message) { - expect(err).to.not.exist; - emailDao.decryptBody({ - message: message, - folder: inbox - }, function(err) { - expect(err).to.not.exist; - expect(message.body).to.equal('asdf'); - expect(message.encrypted).to.be.true; - expect(message.decrypted).to.be.true; - expect(message.attachments.length).to.equal(1); - done(); - }); - }); - }); - }); - it('should insert images into html mail', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[9] + message: inbox.messages[1] }, function(err, message) { expect(err).to.not.exist; expect(message.html).to.equal('asd'); @@ -418,7 +388,7 @@ describe('Email DAO integration tests', function() { }); it('should set flags', function(done) { - var message = inbox.messages[0]; + var message = inbox.messages[1]; message.unread = false; message.answered = true; @@ -436,7 +406,7 @@ describe('Email DAO integration tests', function() { it('should parse Apple Mail (attachment - PGP/MIME): Encrypted', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[10] + message: inbox.messages[2] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -457,7 +427,7 @@ describe('Email DAO integration tests', function() { it('should parse Apple Mail (attachment - PGP/MIME): Encrypted and signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[11] + message: inbox.messages[3] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -478,7 +448,7 @@ describe('Email DAO integration tests', function() { it('should parse Apple Mail (no attachment): Encrypted and signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[12] + message: inbox.messages[4] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -499,7 +469,7 @@ describe('Email DAO integration tests', function() { it('should parse Apple Mail (no attachment): Encrypted', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[13] + message: inbox.messages[5] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -520,7 +490,7 @@ describe('Email DAO integration tests', function() { it('should parse Apple Mail (attachment - PGP/MIME): Signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[14] + message: inbox.messages[6] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -541,7 +511,7 @@ describe('Email DAO integration tests', function() { it('should parse Apple Mail (no attachment): Signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[15] + message: inbox.messages[7] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -562,7 +532,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (attachment - PGP/MIME): Encrypted', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[16] + message: inbox.messages[8] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -583,7 +553,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (attachment - PGP/MIME): Encrypted and signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[17] + message: inbox.messages[9] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -604,7 +574,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (no attachment): Encrypted and signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[18] + message: inbox.messages[10] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -625,7 +595,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (no attachment): Encrypted', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[19] + message: inbox.messages[11] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -646,7 +616,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (no attachment): plaintext reply to an encrypted message', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[20] + message: inbox.messages[12] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -667,7 +637,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (attachment - PGP/MIME): Signed', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[21] + message: inbox.messages[13] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -688,7 +658,7 @@ describe('Email DAO integration tests', function() { it('should parse Thunderbird (no attachment): Signed w/ PGP/INLINE', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[22] + message: inbox.messages[14] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ @@ -709,7 +679,7 @@ describe('Email DAO integration tests', function() { it('should parse Mailvelope: encrypted (unsigned) w/PGP/INLINE', function(done) { emailDao.getBody({ folder: inbox, - message: inbox.messages[23] + message: inbox.messages[15] }, function(err, message) { expect(err).to.not.exist; emailDao.decryptBody({ diff --git a/test/unit/email-dao-test.js b/test/unit/email-dao-test.js index ed003cc..646aac6 100644 --- a/test/unit/email-dao-test.js +++ b/test/unit/email-dao-test.js @@ -132,1632 +132,1708 @@ describe('Email DAO unit tests', function() { mailreader.parse.restore(); }); - describe('public API', function() { - describe('#init', function() { - var initFoldersStub; - beforeEach(function() { - delete dao._account; - initFoldersStub = sinon.stub(dao, '_initFoldersFromDisk'); - }); + describe('#init', function() { + var initFoldersStub; - it('should initialize folders and return keypair', function(done) { - keychainStub.getUserKeyPair.withArgs(emailAddress).yieldsAsync(null, mockKeyPair); - initFoldersStub.yieldsAsync(); + beforeEach(function() { + delete dao._account; + initFoldersStub = sinon.stub(dao, '_initFoldersFromDisk'); + }); - dao.init({ - account: account - }, function(err, keypair) { - expect(err).to.not.exist; - expect(keypair).to.exist; - expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; - expect(initFoldersStub.calledOnce).to.be.true; + it('should initialize folders and return keypair', function(done) { + keychainStub.getUserKeyPair.withArgs(emailAddress).yieldsAsync(null, mockKeyPair); + initFoldersStub.yieldsAsync(); - done(); - }); - }); + dao.init({ + account: account + }, function(err, keypair) { + expect(err).to.not.exist; + expect(keypair).to.exist; + expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; + expect(initFoldersStub.calledOnce).to.be.true; - it('should fail when keychain errors', function(done) { - keychainStub.getUserKeyPair.yieldsAsync({}); - - dao.init({ - account: account - }, function(err, keypair) { - expect(err).to.exist; - expect(keypair).to.not.exist; - expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; - expect(initFoldersStub.called).to.be.false; - - done(); - }); + done(); }); }); - describe('#unlock', function() { - it('should unlock', function(done) { - pgpStub.getKeyParams.returns({ - _id: mockKeyPair.publicKey._id, - userId: emailAddress, - userIds: [{ - emailAddress: emailAddress - }] - }); + it('should fail when keychain errors', function(done) { + keychainStub.getUserKeyPair.yieldsAsync({}); - pgpStub.importKeys.withArgs({ - passphrase: passphrase, - privateKeyArmored: mockKeyPair.privateKey.encryptedKey, - publicKeyArmored: mockKeyPair.publicKey.publicKey - }).yieldsAsync(); - pgpStub._privateKey = { - foo: 'bar' - }; + dao.init({ + account: account + }, function(err, keypair) { + expect(err).to.exist; + expect(keypair).to.not.exist; + expect(keychainStub.getUserKeyPair.calledOnce).to.be.true; + expect(initFoldersStub.called).to.be.false; - dao.unlock({ - passphrase: passphrase, - keypair: mockKeyPair - }, function(err) { - expect(err).to.not.exist; + done(); + }); + }); + }); - expect(pgpStub.importKeys.calledOnce).to.be.true; - expect(dao._pgpbuilder._privateKey).to.equal(pgpStub._privateKey); - - done(); - }); + describe('#unlock', function() { + it('should unlock', function(done) { + pgpStub.getKeyParams.returns({ + _id: mockKeyPair.publicKey._id, + userId: emailAddress, + userIds: [{ + emailAddress: emailAddress + }] }); - it('should generate a keypair and unlock', function(done) { - var keypair = { - keyId: 123, - publicKeyArmored: mockKeyPair.publicKey.publicKey, - privateKeyArmored: mockKeyPair.privateKey.encryptedKey - }; + pgpStub.importKeys.withArgs({ + passphrase: passphrase, + privateKeyArmored: mockKeyPair.privateKey.encryptedKey, + publicKeyArmored: mockKeyPair.publicKey.publicKey + }).yieldsAsync(); + pgpStub._privateKey = { + foo: 'bar' + }; - pgpStub.generateKeys.withArgs({ - emailAddress: emailAddress, - keySize: asymKeySize, - passphrase: passphrase - }).yieldsAsync(null, keypair); + dao.unlock({ + passphrase: passphrase, + keypair: mockKeyPair + }, function(err) { + expect(err).to.not.exist; - pgpStub.importKeys.withArgs({ - passphrase: passphrase, - privateKeyArmored: mockKeyPair.privateKey.encryptedKey, - publicKeyArmored: mockKeyPair.publicKey.publicKey - }).yieldsAsync(); - keychainStub.putUserKeyPair.withArgs().yieldsAsync(); + expect(pgpStub.importKeys.calledOnce).to.be.true; + expect(dao._pgpbuilder._privateKey).to.equal(pgpStub._privateKey); - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.not.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - expect(pgpStub.importKeys.calledOnce).to.be.true; - expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when persisting fails', function(done) { - var keypair = { - keyId: 123, - publicKeyArmored: 'qwerty', - privateKeyArmored: 'asdfgh' - }; - pgpStub.generateKeys.yieldsAsync(null, keypair); - pgpStub.importKeys.withArgs().yieldsAsync(); - keychainStub.putUserKeyPair.yieldsAsync({}); - - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - expect(pgpStub.importKeys.calledOnce).to.be.true; - expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when import fails', function(done) { - var keypair = { - keyId: 123, - publicKeyArmored: 'qwerty', - privateKeyArmored: 'asdfgh' - }; - - pgpStub.generateKeys.withArgs().yieldsAsync(null, keypair); - pgpStub.importKeys.withArgs().yieldsAsync({}); - - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - expect(pgpStub.importKeys.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail when generation fails', function(done) { - pgpStub.generateKeys.yieldsAsync({}); - - dao.unlock({ - passphrase: passphrase - }, function(err) { - expect(err).to.exist; - - expect(pgpStub.generateKeys.calledOnce).to.be.true; - - done(); - }); + done(); }); }); - describe('#openFolder', function() { - it('should open an imap mailbox', function(done) { - imapClientStub.selectMailbox.withArgs({ - path: inboxFolder.path - }).yieldsAsync(); + it('should generate a keypair and unlock', function(done) { + var keypair = { + keyId: 123, + publicKeyArmored: mockKeyPair.publicKey.publicKey, + privateKeyArmored: mockKeyPair.privateKey.encryptedKey + }; - dao.openFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(imapClientStub.selectMailbox.calledOnce).to.be.true; - done(); - }); + pgpStub.generateKeys.withArgs({ + emailAddress: emailAddress, + keySize: asymKeySize, + passphrase: passphrase + }).yieldsAsync(null, keypair); + + pgpStub.importKeys.withArgs({ + passphrase: passphrase, + privateKeyArmored: mockKeyPair.privateKey.encryptedKey, + publicKeyArmored: mockKeyPair.publicKey.publicKey + }).yieldsAsync(); + keychainStub.putUserKeyPair.withArgs().yieldsAsync(); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.not.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + expect(pgpStub.importKeys.calledOnce).to.be.true; + expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when persisting fails', function(done) { + var keypair = { + keyId: 123, + publicKeyArmored: 'qwerty', + privateKeyArmored: 'asdfgh' + }; + pgpStub.generateKeys.yieldsAsync(null, keypair); + pgpStub.importKeys.withArgs().yieldsAsync(); + keychainStub.putUserKeyPair.yieldsAsync({}); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + expect(pgpStub.importKeys.calledOnce).to.be.true; + expect(keychainStub.putUserKeyPair.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when import fails', function(done) { + var keypair = { + keyId: 123, + publicKeyArmored: 'qwerty', + privateKeyArmored: 'asdfgh' + }; + + pgpStub.generateKeys.withArgs().yieldsAsync(null, keypair); + pgpStub.importKeys.withArgs().yieldsAsync({}); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + expect(pgpStub.importKeys.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail when generation fails', function(done) { + pgpStub.generateKeys.yieldsAsync({}); + + dao.unlock({ + passphrase: passphrase + }, function(err) { + expect(err).to.exist; + + expect(pgpStub.generateKeys.calledOnce).to.be.true; + + done(); + }); + }); + }); + + describe('#openFolder', function() { + it('should open an imap mailbox', function(done) { + imapClientStub.selectMailbox.withArgs({ + path: inboxFolder.path + }).yieldsAsync(); + + dao.openFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(imapClientStub.selectMailbox.calledOnce).to.be.true; + done(); + }); + }); + + it('should not open the virtual outbox folder in imap', function() { + dao.openFolder({ + folder: outboxFolder }); - it('should not open the virtual outbox folder in imap', function() { - dao.openFolder({ - folder: outboxFolder - }); + expect(imapClientStub.selectMailbox.called).to.be.false; + }); + it('should not do anything in offline mode', function(done) { + account.online = false; + + dao.openFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.exist; expect(imapClientStub.selectMailbox.called).to.be.false; + done(); }); - it('should not do anything in offline mode', function(done) { - account.online = false; + }); + }); - dao.openFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.exist; - expect(imapClientStub.selectMailbox.called).to.be.false; - done(); - }); + describe('#refreshFolder', function() { + var localListStub, mail; + beforeEach(function() { + localListStub = sinon.stub(dao, '_localListMessages'); + mail = { + uid: 123, + unread: true + }; + }); + + it('should add messages from disk', function(done) { + localListStub.withArgs({ + folder: inboxFolder + }).yieldsAsync(null, [mail]); + + dao.refreshFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.count).to.equal(1); + expect(inboxFolder.messages).to.contain(mail); + + done(); }); }); - describe('#refreshFolder', function() { - var localListStub, mail; + it('should not add messages from disk', function(done) { + inboxFolder.messages = [mail]; + localListStub.withArgs({ + folder: inboxFolder + }).yieldsAsync(null, [mail]); - beforeEach(function() { - localListStub = sinon.stub(dao, '_localListMessages'); - mail = { - uid: 123, - unread: true - }; - }); + dao.refreshFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.count).to.equal(1); + expect(inboxFolder.messages).to.contain(mail); - it('should add messages from disk', function(done) { - localListStub.withArgs({ - folder: inboxFolder - }).yieldsAsync(null, [mail]); - - dao.refreshFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.count).to.equal(1); - expect(inboxFolder.messages).to.contain(mail); - - done(); - }); - }); - - it('should not add messages from disk', function(done) { - inboxFolder.messages = [mail]; - localListStub.withArgs({ - folder: inboxFolder - }).yieldsAsync(null, [mail]); - - dao.refreshFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.count).to.equal(1); - expect(inboxFolder.messages).to.contain(mail); - - done(); - }); - }); - - it('should remove messages from memory', function(done) { - inboxFolder.messages = [mail]; - localListStub.withArgs({ - folder: inboxFolder - }).yieldsAsync(null, []); - - dao.refreshFolder({ - folder: inboxFolder - }, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.count).to.equal(0); - expect(inboxFolder.messages).to.be.empty; - - done(); - }); + done(); }); }); - describe('#fetchMessages', function() { - var imapListStub, imapGetStub, imapDeleteStub, localStoreStub; - var opts, message, validUuid, corruptedUuid, verificationSubject; - var notified; + it('should remove messages from memory', function(done) { + inboxFolder.messages = [mail]; + localListStub.withArgs({ + folder: inboxFolder + }).yieldsAsync(null, []); - beforeEach(function() { - imapListStub = sinon.stub(dao, '_imapListMessages'); - imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); - imapGetStub = sinon.stub(dao, '_getBodyParts'); - localStoreStub = sinon.stub(dao, '_localStoreMessages'); + dao.refreshFolder({ + folder: inboxFolder + }, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.count).to.equal(0); + expect(inboxFolder.messages).to.be.empty; - opts = { - folder: inboxFolder, - firstUid: 123, - lastUid: 123 - }; - message = { - uid: 123, - subject: 'asdasd', - unread: true, - bodyParts: [] - }; - validUuid = '9A858952-17EE-4273-9E74-D309EAFDFAFB'; - corruptedUuid = 'OMFG_FUCKING_BASTARD_UUID_FROM_HELL!'; - verificationSubject = "[whiteout] New public key uploaded"; - - notified = false; - dao.onIncomingMessage = function(newMessages) { - expect(newMessages).to.contain(message); - notified = true; - }; + done(); }); + }); + }); - it('should fetch message downstream', function(done) { - imapListStub.withArgs(opts).yieldsAsync(null, [message]); + describe('#fetchMessages', function() { + var imapListStub, imapGetStub, imapDeleteStub, localStoreStub; + var opts, message, validUuid, corruptedUuid, verificationSubject; + var notified; - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); + beforeEach(function() { + imapListStub = sinon.stub(dao, '_imapListMessages'); + imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); + imapGetStub = sinon.stub(dao, '_getBodyParts'); + localStoreStub = sinon.stub(dao, '_localStoreMessages'); - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.contain(message); - expect(notified).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - expect(imapListStub.calledOnce).to.be.true; + opts = { + folder: inboxFolder, + firstUid: 123, + lastUid: 123 + }; + message = { + uid: 123, + subject: 'asdasd', + unread: true, + bodyParts: [] + }; + validUuid = '9A858952-17EE-4273-9E74-D309EAFDFAFB'; + corruptedUuid = 'OMFG_FUCKING_BASTARD_UUID_FROM_HELL!'; + verificationSubject = "[whiteout] New public key uploaded"; - done(); - }); - }); + notified = false; + dao.onIncomingMessage = function(newMessages) { + expect(newMessages).to.contain(message); + notified = true; + }; + }); - it('should not notify for other folders', function(done) { - opts.folder = sentFolder; + it('should fetch message downstream', function(done) { + imapListStub.withArgs(opts).yieldsAsync(null, [message]); - imapListStub.withArgs(opts).yieldsAsync(null, [message]); + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); - localStoreStub.withArgs({ - folder: sentFolder, - emails: [message] - }).yieldsAsync(); + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.contain(message); + expect(notified).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + expect(imapListStub.calledOnce).to.be.true; - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(sentFolder.messages).to.contain(message); - expect(notified).to.be.false; - expect(localStoreStub.calledOnce).to.be.true; - expect(imapListStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should verify verification mails', function(done) { - message.subject = verificationSubject; - - imapListStub.withArgs(opts).yieldsAsync(null, [message]); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ - type: 'text', - content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid - }]); - - keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync(); - - imapDeleteStub.withArgs({ - folder: inboxFolder, - uid: message.uid - }).yieldsAsync(); - - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.not.contain(message); - expect(notified).to.be.false; - expect(imapListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localStoreStub.called).to.be.false; - done(); - }); - }); - - it('should not verify invalid verification mails', function(done) { - message.subject = verificationSubject; - - imapListStub.withArgs(opts).yieldsAsync(null, [message]); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ - type: 'text', - content: '' + cfg.cloudUrl + cfg.verificationUrl + corruptedUuid - }]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.contain(message); - expect(notified).to.be.true; - expect(imapListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(keychainStub.verifyPublicKey.called).to.be.false; - expect(imapDeleteStub.called).to.be.false; - expect(localStoreStub.calledOnce).to.be.true; - done(); - }); - }); - - it('should display verification mail when verification failed', function(done) { - message.subject = verificationSubject; - - imapListStub.withArgs(opts).yieldsAsync(null, [message]); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ - type: 'text', - content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid - }]); - - keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync({}); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - - dao.fetchMessages(opts, function(err) { - expect(err).to.not.exist; - expect(inboxFolder.messages).to.contain(message); - expect(notified).to.be.true; - expect(imapListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; - expect(imapDeleteStub.called).to.be.false; - expect(localStoreStub.calledOnce).to.be.true; - done(); - }); + done(); }); }); - describe('#deleteMessage', function() { - var imapDeleteStub, localDeleteStub, message; + it('should not notify for other folders', function(done) { + opts.folder = sentFolder; - beforeEach(function() { - message = { - uid: 1234 - }; - imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); - localDeleteStub = sinon.stub(dao, '_localDeleteMessage'); - inboxFolder.messages = [message]; - outboxFolder.messages = [message]; - }); + imapListStub.withArgs(opts).yieldsAsync(null, [message]); - it('should delete from imap, local, memory', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; + localStoreStub.withArgs({ + folder: sentFolder, + emails: [message] + }).yieldsAsync(); - imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); - localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(sentFolder.messages).to.contain(message); + expect(notified).to.be.false; + expect(localStoreStub.calledOnce).to.be.true; + expect(imapListStub.calledOnce).to.be.true; - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localDeleteStub.calledOnce).to.be.true; - expect(inboxFolder.messages).to.not.contain(message); - - done(); - }); - }); - - it('should delete from local, memory', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; - - localDeleteStub.withArgs(deleteOpts).yieldsAsync(); - - dao.deleteMessage({ - folder: inboxFolder, - message: message, - localOnly: true - }, function(err) { - expect(err).to.not.exist; - expect(imapDeleteStub.called).to.be.false; - expect(localDeleteStub.calledOnce).to.be.true; - expect(inboxFolder.messages).to.not.contain(message); - - done(); - }); - }); - - it('should delete from outbox from local, memory', function(done) { - var deleteOpts = { - folder: outboxFolder, - uid: message.uid - }; - - localDeleteStub.withArgs(deleteOpts).yieldsAsync(); - - dao.deleteMessage({ - folder: outboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapDeleteStub.called).to.be.false; - expect(localDeleteStub.calledOnce).to.be.true; - expect(outboxFolder.messages).to.not.contain(message); - - done(); - }); - }); - - it('should fail at delete from local', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; - - imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); - localDeleteStub.withArgs(deleteOpts).yieldsAsync({}); - - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localDeleteStub.calledOnce).to.be.true; - expect(inboxFolder.messages).to.contain(message); - - done(); - }); - }); - - it('should fail at delete from imap', function(done) { - var deleteOpts = { - folder: inboxFolder, - uid: message.uid - }; - - imapDeleteStub.withArgs(deleteOpts).yieldsAsync({}); - - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapDeleteStub.calledOnce).to.be.true; - expect(localDeleteStub.called).to.be.false; - expect(inboxFolder.messages).to.contain(message); - - done(); - }); - }); - - it('should fail at delete from imap in offline', function(done) { - account.online = false; - dao.deleteMessage({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapDeleteStub.called).to.be.false; - expect(localDeleteStub.called).to.be.false; - expect(inboxFolder.messages).to.contain(message); - - done(); - }); + done(); }); }); - describe('#setFlags', function() { - var imapMark, localListStub, localStoreStub, message; + it('should verify verification mails', function(done) { + message.subject = verificationSubject; - beforeEach(function() { - message = { - uid: 1234 - }; - imapMark = sinon.stub(dao, '_imapMark'); - localListStub = sinon.stub(dao, '_localListMessages'); - localStoreStub = sinon.stub(dao, '_localStoreMessages'); - inboxFolder.messages = [message]; - outboxFolder.messages = [message]; - }); + imapListStub.withArgs(opts).yieldsAsync(null, [message]); - it('should set flags for imap, disk, memory', function(done) { - imapMark.withArgs({ - folder: inboxFolder, - uid: message.uid, - unread: message.unread, - answered: message.answered - }).yieldsAsync(); + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid + }]); - localListStub.withArgs({ - folder: inboxFolder, - uid: message.uid - }).yieldsAsync(null, [message]); + keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync(); - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); + imapDeleteStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(); - dao.setFlags({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapMark.calledOnce).to.be.true; - expect(localListStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should set flags for outbox for disk, memory', function(done) { - localListStub.withArgs({ - folder: outboxFolder, - uid: message.uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: outboxFolder, - emails: [message] - }).yieldsAsync(); - - dao.setFlags({ - folder: outboxFolder, - message: message - }, function(err) { - expect(err).to.not.exist; - expect(imapMark.called).to.be.false; - expect(localListStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should set flags for disk, memory', function(done) { - localListStub.withArgs({ - folder: inboxFolder, - uid: message.uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - dao.setFlags({ - folder: inboxFolder, - message: message, - localOnly: true - }, function(err) { - expect(err).to.not.exist; - expect(imapMark.called).to.be.false; - expect(localListStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should fail to set flags for imap', function(done) { - imapMark.yieldsAsync({}); - localListStub.yieldsAsync(null, [message]); - localStoreStub.yieldsAsync(); - - dao.setFlags({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapMark.calledOnce).to.be.true; - expect(localListStub.called).to.be.false; - expect(localStoreStub.called).to.be.false; - - done(); - }); - }); - it('should fail to set flags for imap in offline mode', function(done) { - account.online = false; - localListStub.yieldsAsync(null, [message]); - localStoreStub.yieldsAsync(); - - dao.setFlags({ - folder: inboxFolder, - message: message - }, function(err) { - expect(err).to.exist; - expect(imapMark.called).to.be.false; - expect(localListStub.called).to.be.false; - expect(localStoreStub.called).to.be.false; - - done(); - }); + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.not.contain(message); + expect(notified).to.be.false; + expect(imapListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localStoreStub.called).to.be.false; + done(); }); }); - describe('#getBody', function() { - var localListStub, localStoreStub, imapGetStub, uid; + it('should not verify invalid verification mails', function(done) { + message.subject = verificationSubject; - beforeEach(function() { - uid = 12345, - localListStub = sinon.stub(dao, '_localListMessages'); - localStoreStub = sinon.stub(dao, '_localStoreMessages'); - imapGetStub = sinon.stub(dao, '_getBodyParts'); + imapListStub.withArgs(opts).yieldsAsync(null, [message]); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: '' + cfg.cloudUrl + cfg.verificationUrl + corruptedUuid + }]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.contain(message); + expect(notified).to.be.true; + expect(imapListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(keychainStub.verifyPublicKey.called).to.be.false; + expect(imapDeleteStub.called).to.be.false; + expect(localStoreStub.calledOnce).to.be.true; + done(); + }); + }); + + it('should display verification mail when verification failed', function(done) { + message.subject = verificationSubject; + + imapListStub.withArgs(opts).yieldsAsync(null, [message]); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: '' + cfg.cloudUrl + cfg.verificationUrl + validUuid + }]); + + keychainStub.verifyPublicKey.withArgs(validUuid).yieldsAsync({}); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + + dao.fetchMessages(opts, function(err) { + expect(err).to.not.exist; + expect(inboxFolder.messages).to.contain(message); + expect(notified).to.be.true; + expect(imapListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(keychainStub.verifyPublicKey.calledOnce).to.be.true; + expect(imapDeleteStub.called).to.be.false; + expect(localStoreStub.calledOnce).to.be.true; + done(); + }); + }); + }); + + describe('#deleteMessage', function() { + var imapDeleteStub, localDeleteStub, message; + + beforeEach(function() { + message = { + uid: 1234 + }; + imapDeleteStub = sinon.stub(dao, '_imapDeleteMessage'); + localDeleteStub = sinon.stub(dao, '_localDeleteMessage'); + inboxFolder.messages = [message]; + outboxFolder.messages = [message]; + }); + + it('should delete from imap, local, memory', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); + localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should delete from local, memory', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + + dao.deleteMessage({ + folder: inboxFolder, + message: message, + localOnly: true + }, function(err) { + expect(err).to.not.exist; + expect(imapDeleteStub.called).to.be.false; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should delete from outbox from local, memory', function(done) { + var deleteOpts = { + folder: outboxFolder, + uid: message.uid + }; + + localDeleteStub.withArgs(deleteOpts).yieldsAsync(); + + dao.deleteMessage({ + folder: outboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapDeleteStub.called).to.be.false; + expect(localDeleteStub.calledOnce).to.be.true; + expect(outboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should fail at delete from local', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + imapDeleteStub.withArgs(deleteOpts).yieldsAsync(); + localDeleteStub.withArgs(deleteOpts).yieldsAsync({}); + + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + + it('should fail at delete from imap', function(done) { + var deleteOpts = { + folder: inboxFolder, + uid: message.uid + }; + + imapDeleteStub.withArgs(deleteOpts).yieldsAsync({}); + + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapDeleteStub.calledOnce).to.be.true; + expect(localDeleteStub.called).to.be.false; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + + it('should fail at delete from imap in offline', function(done) { + account.online = false; + dao.deleteMessage({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapDeleteStub.called).to.be.false; + expect(localDeleteStub.called).to.be.false; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + }); + + describe('#setFlags', function() { + var imapMark, localListStub, localStoreStub, message; + + beforeEach(function() { + message = { + uid: 1234 + }; + imapMark = sinon.stub(dao, '_imapMark'); + localListStub = sinon.stub(dao, '_localListMessages'); + localStoreStub = sinon.stub(dao, '_localStoreMessages'); + inboxFolder.messages = [message]; + outboxFolder.messages = [message]; + }); + + it('should set flags for imap, disk, memory', function(done) { + imapMark.withArgs({ + folder: inboxFolder, + uid: message.uid, + unread: message.unread, + answered: message.answered + }).yieldsAsync(); + + localListStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapMark.calledOnce).to.be.true; + expect(localListStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should set flags for outbox for disk, memory', function(done) { + localListStub.withArgs({ + folder: outboxFolder, + uid: message.uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: outboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.setFlags({ + folder: outboxFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapMark.called).to.be.false; + expect(localListStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should set flags for disk, memory', function(done) { + localListStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message, + localOnly: true + }, function(err) { + expect(err).to.not.exist; + expect(imapMark.called).to.be.false; + expect(localListStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should fail to set flags for imap', function(done) { + imapMark.yieldsAsync({}); + localListStub.yieldsAsync(null, [message]); + localStoreStub.yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapMark.calledOnce).to.be.true; + expect(localListStub.called).to.be.false; + expect(localStoreStub.called).to.be.false; + + done(); + }); + }); + it('should fail to set flags for imap in offline mode', function(done) { + account.online = false; + localListStub.yieldsAsync(null, [message]); + localStoreStub.yieldsAsync(); + + dao.setFlags({ + folder: inboxFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapMark.called).to.be.false; + expect(localListStub.called).to.be.false; + expect(localStoreStub.called).to.be.false; + + done(); + }); + }); + }); + + describe('#moveMessage', function() { + var localDeleteStub, imapMoveStub, message; + + beforeEach(function() { + localDeleteStub = sinon.stub(dao, '_localDeleteMessage'); + imapMoveStub = sinon.stub(dao, '_imapMoveMessage'); + message = { + uid: 123 + }; + inboxFolder.messages.push(message); + }); + + it('should move a message to a destination folder', function(done) { + imapMoveStub.withArgs({ + folder: inboxFolder, + destination: sentFolder, + uid: message.uid + }).yieldsAsync(); + + localDeleteStub.withArgs({ + folder: inboxFolder, + uid: message.uid + }).yieldsAsync(); + + dao.moveMessage({ + folder: inboxFolder, + destination: sentFolder, + message: message + }, function(err) { + expect(err).to.not.exist; + expect(imapMoveStub.calledOnce).to.be.true; + expect(localDeleteStub.calledOnce).to.be.true; + expect(inboxFolder.messages).to.not.contain(message); + + done(); + }); + }); + + it('should not a message if IMAP errors', function(done) { + imapMoveStub.withArgs({ + folder: inboxFolder, + destination: sentFolder, + uid: message.uid + }).yieldsAsync(new Error()); + + dao.moveMessage({ + folder: inboxFolder, + destination: sentFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapMoveStub.calledOnce).to.be.true; + expect(localDeleteStub.called).to.be.false; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + + it('should fail at delete from imap in offline', function(done) { + account.online = false; + + dao.moveMessage({ + folder: inboxFolder, + destination: sentFolder, + message: message + }, function(err) { + expect(err).to.exist; + expect(imapMoveStub.called).to.be.false; + expect(localDeleteStub.called).to.be.false; + expect(inboxFolder.messages).to.contain(message); + + done(); + }); + }); + }); + + describe('#getBody', function() { + var localListStub, localStoreStub, imapGetStub, uid; + + beforeEach(function() { + uid = 12345, + localListStub = sinon.stub(dao, '_localListMessages'); + localStoreStub = sinon.stub(dao, '_localStoreMessages'); + imapGetStub = sinon.stub(dao, '_getBodyParts'); + }); + + it('should not do anything if the message already has content', function() { + var message = { + body: 'bender is great!' + }; + + dao.getBody({ + message: message }); - it('should not do anything if the message already has content', function() { - var message = { - body: 'bender is great!' - }; + // should do nothing + }); - dao.getBody({ - message: message - }); + it('should read an unencrypted body from the device', function(done) { + var message, body; - // should do nothing - }); + body = 'bender is great! bender is great!'; + message = { + uid: uid + }; - it('should read an unencrypted body from the device', function(done) { - var message, body; - - body = 'bender is great! bender is great!'; - message = { - uid: uid - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: body - }] - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(body); - expect(msg.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a pgp/mime from the device', function(done) { - var message, ct, pt; - - pt = 'bender is great!'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - message = { - uid: uid, - encrypted: true - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }, { - type: 'encrypted', - content: ct - }] - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(ct); - expect(msg.encrypted).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a signed pgp/mime from the device', function(done) { - var message, signed, pt, signedMimeTree, signature; - - pt = 'bender is great!'; - signed = 'omg signed text'; - signedMimeTree = 'trallalalalala'; - signature = 'ugauga'; - message = { - uid: uid, - signed: true, - from: [{ - address: 'asdasdasd' - }] - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }, { - type: 'signed', - content: [{ - type: 'text', - content: signed - }], - signedMessage: signedMimeTree, - signature: signature - }] - }]); - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(signed); - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a pgp/inline from the device', function(done) { - var message, ct, pt; - - ct = '-----BEGIN PGP MESSAGE-----\nasdasdasd\n-----END PGP MESSAGE-----'; - pt = 'bla bla yadda yadda'; - message = { - uid: uid - }; - - localListStub.yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }, { - type: 'text', - content: ct - }, { - type: 'text', - content: pt - }] - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(ct); - expect(msg.bodyParts[0].type).to.equal('encrypted'); - expect(msg.bodyParts[0].content).to.equal(ct); - expect(msg.encrypted).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should read a signed pgp/inline from the device', function(done) { - var message, pt, expected; - - expected = 'Lorem ipsum Aliquip tempor veniam proident.\n\nafguab;igab;igubalw\n\nLorem ipsum Dolor sed irure sint in non.\n\n\n'; - pt = '-----BEGIN PGP SIGNED MESSAGE-----\nHash: WTFHASH\n\n' + expected + '\n-----BEGIN PGP SIGNATURE----------END PGP SIGNATURE-----'; - message = { - uid: uid, - from: [{ - address: 'asdasdasd' - }] - }; - - localListStub.yieldsAsync(null, [{ - bodyParts: [{ - type: 'text', - content: pt - }] - }]); - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.verifyClearSignedMessage.withArgs(pt, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; - - expect(msg).to.equal(message); - expect(msg.body).to.equal(expected); - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.loadingBody).to.be.false; - - expect(localListStub.calledOnce).to.be.true; - expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; - }); - - it('should stream from imap and set plain text body', function(done) { - var message, body, uid; - - body = 'bender is great! bender is great!'; - uid = 1234; - message = { - uid: uid, - bodyParts: [{ - type: 'text' - }] - }; - - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [{ + bodyParts: [{ type: 'text', content: body - }]); + }] + }]); - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; - expect(msg).to.equal(message); - expect(msg.body).to.equal(body); - expect(msg.loadingBody).to.be.false; + expect(msg).to.equal(message); + expect(msg.body).to.equal(body); + expect(msg.loadingBody).to.be.false; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; + expect(localListStub.calledOnce).to.be.true; - done(); - }); - expect(message.loadingBody).to.be.true; + done(); }); + expect(message.loadingBody).to.be.true; + }); - it('should stream from imap and set encrypted body', function(done) { - var message, ct, pt; + it('should read a pgp/mime from the device', function(done) { + var message, ct, pt; - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - message = { - uid: uid, - encrypted: true, - bodyParts: [{ - type: 'text' - }, { - type: 'encrypted' - }] - }; + pt = 'bender is great!'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + message = { + uid: uid, + encrypted: true + }; - localListStub.withArgs({ - folder: inboxFolder, - uid: uid - }).yieldsAsync(null, [message]); - - localStoreStub.withArgs({ - folder: inboxFolder, - emails: [message] - }).yieldsAsync(); - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: message.uid, - bodyParts: message.bodyParts - }).yieldsAsync(null, [{ + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [{ + bodyParts: [{ type: 'text', content: pt }, { type: 'encrypted', content: ct - }]); + }] + }]); + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.not.exist; + expect(msg).to.equal(message); + expect(msg.body).to.equal(ct); + expect(msg.encrypted).to.be.true; + expect(message.loadingBody).to.be.false; - expect(msg).to.equal(message); - expect(msg.body).to.equal(ct); - expect(msg.encrypted).to.be.true; - expect(msg.loadingBody).to.be.false; + expect(localListStub.calledOnce).to.be.true; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - done(); - }); - expect(message.loadingBody).to.be.true; + done(); }); + expect(message.loadingBody).to.be.true; + }); - it('fail to stream from imap due to error when persisting', function(done) { - var message = { - uid: uid, - bodyParts: [{ - type: 'text' - }] - }; + it('should read a signed pgp/mime from the device', function(done) { + var message, signed, pt, signedMimeTree, signature; - localListStub.yieldsAsync(null, [message]); - localStoreStub.yieldsAsync({}); - imapGetStub.yieldsAsync(null, [{ + pt = 'bender is great!'; + signed = 'omg signed text'; + signedMimeTree = 'trallalalalala'; + signature = 'ugauga'; + message = { + uid: uid, + signed: true, + from: [{ + address: 'asdasdasd' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [{ + bodyParts: [{ type: 'text', - content: 'bender is great! bender is great!' - }]); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.exist; - expect(msg).to.not.exist; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.calledOnce).to.be.true; - - expect(message.loadingBody).to.be.false; - - done(); - }); - }); - - it('fail to stream from imap due to stream error', function(done) { - var message = { - uid: uid, - bodyParts: [{ - type: 'text' - }] - }; - - localListStub.yieldsAsync(null, [message]); - imapGetStub.yieldsAsync({}); - - dao.getBody({ - message: message, - folder: inboxFolder - }, function(err, msg) { - expect(err).to.exist; - expect(msg).to.not.exist; - expect(localListStub.calledOnce).to.be.true; - expect(imapGetStub.calledOnce).to.be.true; - expect(localStoreStub.called).to.be.false; - - expect(message.loadingBody).to.be.false; - - done(); - }); - }); - }); - - describe('#getAttachment', function() { - var imapGetStub, uid; - - beforeEach(function() { - uid = 123456; - imapGetStub = sinon.stub(dao, '_getBodyParts'); - }); - - it('should fetch an attachment from imap', function(done) { - var attmt = {}; - - imapGetStub.withArgs({ - folder: inboxFolder, - uid: uid, - bodyParts: [attmt] - }).yieldsAsync(null, [{ - content: 'CONTENT!!!' - }]); - - dao.getAttachment({ - folder: inboxFolder, - uid: uid, - attachment: attmt - }, function(err, fetchedAttmt) { - expect(err).to.not.exist; - expect(fetchedAttmt).to.equal(attmt); - expect(attmt.content).to.not.be.empty; - expect(imapGetStub.calledOnce).to.be.true; - - done(); - }); - }); - - it('should error during fetch', function(done) { - var attmt = {}; - - imapGetStub.yieldsAsync({}); - - dao.getAttachment({ - folder: inboxFolder, - uid: uid, - attachment: attmt - }, function(err, fetchedAttmt) { - expect(err).to.exist; - expect(fetchedAttmt).to.not.exist; - expect(imapGetStub.calledOnce).to.be.true; - - done(); - }); - }); - }); - - describe('#decryptBody', function() { - it('should do nothing when the message is not encrypted', function(done) { - var message = { - encrypted: false, - decrypted: true, - body: 'asd' - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('should do nothing when the message is already decrypted', function(done) { - var message = { - encrypted: true, - decrypted: true, - body: 'asd' - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('should do nothing when the message has no body', function(done) { - var message = { - encrypted: true, - decrypted: false, - body: '' - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('should do nothing when the message is decrypting', function(done) { - var message = { - encrypted: true, - decrypted: false, - body: 'asd', - decryptingBody: true - }; - - dao.decryptBody({ - message: message - }, done); - }); - - it('decrypt a pgp/mime message', function(done) { - var message, ct, pt, parsed; - - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - parsed = 'bender! bender! bender!'; - message = { - from: [{ - address: 'asdasdasd' - }], - body: ct, - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: ct - }] - }; - - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); - parseStub.withArgs({ - bodyParts: [{ - type: 'encrypted', - content: ct, - raw: pt - }] - }).yieldsAsync(null, [{ - type: 'encrypted', + content: pt + }, { + type: 'signed', content: [{ type: 'text', - content: parsed - }] - }]); - - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; - expect(msg).to.equal(message); - expect(message.decrypted).to.be.true; - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.body).to.equal(parsed); - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(parseStub.calledOnce).to.be.true; - - done(); - }); - - expect(message.decryptingBody).to.be.true; - }); - - it('decrypt a pgp/mime message with inner signature', function(done) { - var message, ct, pt, parsed, signed, signedMimeTree, signature; - - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - signedMimeTree = 'trallalalalala'; - signature = 'ugauga'; - signed = 'omg signed text'; - parsed = 'bender! bender! bender!'; - message = { - from: [{ - address: 'asdasdasd' + content: signed }], - body: ct, - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: ct - }] - }; + signedMessage: signedMimeTree, + signature: signature + }] + }]); + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, undefined); - pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; - parseStub.withArgs({ - bodyParts: [{ - type: 'encrypted', - content: ct, - raw: pt - }] - }).yieldsAsync(null, [{ + expect(msg).to.equal(message); + expect(msg.body).to.equal(signed); + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should read a pgp/inline from the device', function(done) { + var message, ct, pt; + + ct = '-----BEGIN PGP MESSAGE-----\nasdasdasd\n-----END PGP MESSAGE-----'; + pt = 'bla bla yadda yadda'; + message = { + uid: uid + }; + + localListStub.yieldsAsync(null, [{ + bodyParts: [{ + type: 'text', + content: pt + }, { + type: 'text', + content: ct + }, { + type: 'text', + content: pt + }] + }]); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(ct); + expect(msg.bodyParts[0].type).to.equal('encrypted'); + expect(msg.bodyParts[0].content).to.equal(ct); + expect(msg.encrypted).to.be.true; + expect(message.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should read a signed pgp/inline from the device', function(done) { + var message, pt, expected; + + expected = 'Lorem ipsum Aliquip tempor veniam proident.\n\nafguab;igab;igubalw\n\nLorem ipsum Dolor sed irure sint in non.\n\n\n'; + pt = '-----BEGIN PGP SIGNED MESSAGE-----\nHash: WTFHASH\n\n' + expected + '\n-----BEGIN PGP SIGNATURE----------END PGP SIGNATURE-----'; + message = { + uid: uid, + from: [{ + address: 'asdasdasd' + }] + }; + + localListStub.yieldsAsync(null, [{ + bodyParts: [{ + type: 'text', + content: pt + }] + }]); + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.verifyClearSignedMessage.withArgs(pt, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(expected); + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(pgpStub.verifyClearSignedMessage.calledOnce).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should stream from imap and set plain text body', function(done) { + var message, body, uid; + + body = 'bender is great! bender is great!'; + uid = 1234; + message = { + uid: uid, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: body + }]); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(body); + expect(msg.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('should stream from imap and set encrypted body', function(done) { + var message, ct, pt; + + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + message = { + uid: uid, + encrypted: true, + bodyParts: [{ + type: 'text' + }, { + type: 'encrypted' + }] + }; + + localListStub.withArgs({ + folder: inboxFolder, + uid: uid + }).yieldsAsync(null, [message]); + + localStoreStub.withArgs({ + folder: inboxFolder, + emails: [message] + }).yieldsAsync(); + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: message.uid, + bodyParts: message.bodyParts + }).yieldsAsync(null, [{ + type: 'text', + content: pt + }, { + type: 'encrypted', + content: ct + }]); + + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.not.exist; + + expect(msg).to.equal(message); + expect(msg.body).to.equal(ct); + expect(msg.encrypted).to.be.true; + expect(msg.loadingBody).to.be.false; + + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + done(); + }); + expect(message.loadingBody).to.be.true; + }); + + it('fail to stream from imap due to error when persisting', function(done) { + var message = { + uid: uid, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.yieldsAsync(null, [message]); + localStoreStub.yieldsAsync({}); + imapGetStub.yieldsAsync(null, [{ + type: 'text', + content: 'bender is great! bender is great!' + }]); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.exist; + expect(msg).to.not.exist; + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.calledOnce).to.be.true; + + expect(message.loadingBody).to.be.false; + + done(); + }); + }); + + it('fail to stream from imap due to stream error', function(done) { + var message = { + uid: uid, + bodyParts: [{ + type: 'text' + }] + }; + + localListStub.yieldsAsync(null, [message]); + imapGetStub.yieldsAsync({}); + + dao.getBody({ + message: message, + folder: inboxFolder + }, function(err, msg) { + expect(err).to.exist; + expect(msg).to.not.exist; + expect(localListStub.calledOnce).to.be.true; + expect(imapGetStub.calledOnce).to.be.true; + expect(localStoreStub.called).to.be.false; + + expect(message.loadingBody).to.be.false; + + done(); + }); + }); + }); + + describe('#getAttachment', function() { + var imapGetStub, uid; + + beforeEach(function() { + uid = 123456; + imapGetStub = sinon.stub(dao, '_getBodyParts'); + }); + + it('should fetch an attachment from imap', function(done) { + var attmt = {}; + + imapGetStub.withArgs({ + folder: inboxFolder, + uid: uid, + bodyParts: [attmt] + }).yieldsAsync(null, [{ + content: 'CONTENT!!!' + }]); + + dao.getAttachment({ + folder: inboxFolder, + uid: uid, + attachment: attmt + }, function(err, fetchedAttmt) { + expect(err).to.not.exist; + expect(fetchedAttmt).to.equal(attmt); + expect(attmt.content).to.not.be.empty; + expect(imapGetStub.calledOnce).to.be.true; + + done(); + }); + }); + + it('should error during fetch', function(done) { + var attmt = {}; + + imapGetStub.yieldsAsync({}); + + dao.getAttachment({ + folder: inboxFolder, + uid: uid, + attachment: attmt + }, function(err, fetchedAttmt) { + expect(err).to.exist; + expect(fetchedAttmt).to.not.exist; + expect(imapGetStub.calledOnce).to.be.true; + + done(); + }); + }); + }); + + describe('#decryptBody', function() { + it('should do nothing when the message is not encrypted', function(done) { + var message = { + encrypted: false, + decrypted: true, + body: 'asd' + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('should do nothing when the message is already decrypted', function(done) { + var message = { + encrypted: true, + decrypted: true, + body: 'asd' + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('should do nothing when the message has no body', function(done) { + var message = { + encrypted: true, + decrypted: false, + body: '' + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('should do nothing when the message is decrypting', function(done) { + var message = { + encrypted: true, + decrypted: false, + body: 'asd', + decryptingBody: true + }; + + dao.decryptBody({ + message: message + }, done); + }); + + it('decrypt a pgp/mime message', function(done) { + var message, ct, pt, parsed; + + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + parsed = 'bender! bender! bender!'; + message = { + from: [{ + address: 'asdasdasd' + }], + body: ct, + encrypted: true, + bodyParts: [{ type: 'encrypted', + content: ct + }] + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); + parseStub.withArgs({ + bodyParts: [{ + type: 'encrypted', + content: ct, + raw: pt + }] + }).yieldsAsync(null, [{ + type: 'encrypted', + content: [{ + type: 'text', + content: parsed + }] + }]); + + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; + expect(msg).to.equal(message); + expect(message.decrypted).to.be.true; + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.body).to.equal(parsed); + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(parseStub.calledOnce).to.be.true; + + done(); + }); + + expect(message.decryptingBody).to.be.true; + }); + + it('decrypt a pgp/mime message with inner signature', function(done) { + var message, ct, pt, parsed, signed, signedMimeTree, signature; + + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + signedMimeTree = 'trallalalalala'; + signature = 'ugauga'; + signed = 'omg signed text'; + parsed = 'bender! bender! bender!'; + message = { + from: [{ + address: 'asdasdasd' + }], + body: ct, + encrypted: true, + bodyParts: [{ + type: 'encrypted', + content: ct + }] + }; + + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, undefined); + pgpStub.verifySignedMessage.withArgs(signedMimeTree, signature, mockKeyPair.publicKey.publicKey).yieldsAsync(null, true); + + parseStub.withArgs({ + bodyParts: [{ + type: 'encrypted', + content: ct, + raw: pt + }] + }).yieldsAsync(null, [{ + type: 'encrypted', + content: [{ + type: 'signed', content: [{ - type: 'signed', - content: [{ - type: 'text', - content: signed - }], - signedMessage: signedMimeTree, - signature: signature - }] - }]); + type: 'text', + content: signed + }], + signedMessage: signedMimeTree, + signature: signature + }] + }]); - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; - expect(msg).to.equal(message); - expect(message.decrypted).to.be.true; - expect(message.body).to.equal(signed); - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledTwice).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; - expect(parseStub.calledOnce).to.be.true; + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; + expect(msg).to.equal(message); + expect(message.decrypted).to.be.true; + expect(message.body).to.equal(signed); + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledTwice).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(pgpStub.verifySignedMessage.calledOnce).to.be.true; + expect(parseStub.calledOnce).to.be.true; - done(); - }); - - expect(message.decryptingBody).to.be.true; + done(); }); - it('decrypt a pgp/inline message', function(done) { - var message, ct, pt; + expect(message.decryptingBody).to.be.true; + }); - pt = 'bender is great'; - ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; - message = { - from: [{ - address: 'asdasdasd' - }], - body: ct, - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: ct, - _isPgpInline: true - }] - }; + it('decrypt a pgp/inline message', function(done) { + var message, ct, pt; - keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); + pt = 'bender is great'; + ct = '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----'; + message = { + from: [{ + address: 'asdasdasd' + }], + body: ct, + encrypted: true, + bodyParts: [{ + type: 'encrypted', + content: ct, + _isPgpInline: true + }] + }; - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; + keychainStub.getReceiverPublicKey.withArgs(message.from[0].address).yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.withArgs(ct, mockKeyPair.publicKey.publicKey).yieldsAsync(null, pt, true); - expect(msg).to.equal(message); - expect(message.decrypted).to.be.true; - expect(message.body).to.equal(pt); - expect(message.decryptingBody).to.be.false; - expect(message.signed).to.be.true; - expect(message.signaturesValid).to.be.true; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(parseStub.called).to.be.false; + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; - done(); - }); + expect(msg).to.equal(message); + expect(message.decrypted).to.be.true; + expect(message.body).to.equal(pt); + expect(message.decryptingBody).to.be.false; + expect(message.signed).to.be.true; + expect(message.signaturesValid).to.be.true; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; - expect(message.decryptingBody).to.be.true; + done(); }); - it('should fail during decryption message', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - body: 'asdjafuad', - encrypted: true, - bodyParts: [{ - type: 'encrypted', - content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' - }] - }; + expect(message.decryptingBody).to.be.true; + }); - keychainStub.getReceiverPublicKey.yieldsAsync(null, mockKeyPair.publicKey); - pgpStub.decrypt.yieldsAsync(new Error('fail.')); + it('should fail during decryption message', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + body: 'asdjafuad', + encrypted: true, + bodyParts: [{ + type: 'encrypted', + content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' + }] + }; - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.not.exist; - expect(msg.body).to.equal('fail.'); - expect(msg).to.exist; - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.calledOnce).to.be.true; - expect(parseStub.called).to.be.false; + keychainStub.getReceiverPublicKey.yieldsAsync(null, mockKeyPair.publicKey); + pgpStub.decrypt.yieldsAsync(new Error('fail.')); - done(); - }); - }); + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.not.exist; + expect(msg.body).to.equal('fail.'); + expect(msg).to.exist; + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.calledOnce).to.be.true; + expect(parseStub.called).to.be.false; - it('should fail during key export', function(done) { - var message = { - from: [{ - address: 'asdasdasd' - }], - encrypted: true, - body: 'asdjafuad', - bodyParts: [{ - type: 'encrypted', - content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' - }] - }; - - keychainStub.getReceiverPublicKey.yieldsAsync({}); - - dao.decryptBody({ - message: message - }, function(error, msg) { - expect(error).to.exist; - expect(msg).to.not.exist; - expect(message.decryptingBody).to.be.false; - expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; - expect(pgpStub.decrypt.called).to.be.false; - expect(parseStub.called).to.be.false; - - done(); - }); + done(); }); }); - describe('#sendEncrypted', function() { - var publicKeys = ["PUBLIC KEY"], - dummyMail = { - publicKeysArmored: publicKeys - }, - msg = 'wow. such message. much rfc2822.'; + it('should fail during key export', function(done) { + var message = { + from: [{ + address: 'asdasdasd' + }], + encrypted: true, + body: 'asdjafuad', + bodyParts: [{ + type: 'encrypted', + content: '-----BEGIN PGP MESSAGE-----asdasdasd-----END PGP MESSAGE-----' + }] + }; - it('should send encrypted and upload to sent', function(done) { - imapClientStub.uploadMessage.withArgs({ - path: sentFolder.path, - message: msg - }).yields(); + keychainStub.getReceiverPublicKey.yieldsAsync({}); - pgpMailerStub.send.withArgs({ - encrypt: true, - mail: dummyMail, - smtpclient: undefined, - publicKeysArmored: publicKeys - }).yieldsAsync(null, msg); + dao.decryptBody({ + message: message + }, function(error, msg) { + expect(error).to.exist; + expect(msg).to.not.exist; + expect(message.decryptingBody).to.be.false; + expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true; + expect(pgpStub.decrypt.called).to.be.false; + expect(parseStub.called).to.be.false; - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - - done(); - }); + done(); }); - - it('should send encrypted and not upload to sent', function(done) { - dao.ignoreUploadOnSent = true; - - pgpMailerStub.send.withArgs({ - encrypt: true, - mail: dummyMail, - smtpclient: undefined, - publicKeysArmored: publicKeys - }).yieldsAsync(null, msg); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - - done(); - }); - }); - - it('should send encrypted and ignore error on upload', function(done) { - imapClientStub.uploadMessage.yields(new Error()); - pgpMailerStub.send.yieldsAsync(null, msg); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - - done(); - }); - }); - - it('should not send when pgpmailer fails', function(done) { - pgpMailerStub.send.yieldsAsync({}); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - - done(); - }); - }); - - it('should not send in offline mode', function(done) { - account.online = false; - - dao.sendEncrypted({}, function(err) { - expect(err).to.exist; - expect(pgpMailerStub.send.called).to.be.false; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - }); + }); - describe('#sendPlaintext', function() { - var dummyMail = {}; - var msg = 'wow. such message. much rfc2822.'; + describe('#sendEncrypted', function() { + var publicKeys = ["PUBLIC KEY"], + dummyMail = { + publicKeysArmored: publicKeys + }, + msg = 'wow. such message. much rfc2822.'; - it('should send in the plain and upload to sent', function(done) { - pgpMailerStub.send.withArgs({ - smtpclient: undefined, - mail: dummyMail - }).yieldsAsync(null, msg); + it('should send encrypted and upload to sent', function(done) { + imapClientStub.uploadMessage.withArgs({ + path: sentFolder.path, + message: msg + }).yields(); - imapClientStub.uploadMessage.withArgs({ - path: sentFolder.path, - message: msg - }).yields(); + pgpMailerStub.send.withArgs({ + encrypt: true, + mail: dummyMail, + smtpclient: undefined, + publicKeysArmored: publicKeys + }).yieldsAsync(null, msg); - dao.sendPlaintext({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - done(); - }); - }); + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; - it('should send in the plain and not upload to sent', function(done) { - dao.ignoreUploadOnSent = true; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - pgpMailerStub.send.withArgs({ - smtpclient: undefined, - mail: dummyMail - }).yieldsAsync(null, msg); - - dao.sendPlaintext({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - - it('should send and ignore error on upload', function(done) { - imapClientStub.uploadMessage.yields(new Error()); - pgpMailerStub.send.yieldsAsync(null, msg); - - dao.sendEncrypted({ - email: dummyMail - }, function(err) { - expect(err).to.not.exist; - - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.calledOnce).to.be.true; - - done(); - }); - }); - - it('should not send due to error', function(done) { - pgpMailerStub.send.yieldsAsync({}); - - dao.sendPlaintext({ - email: dummyMail - }, function(err) { - expect(err).to.exist; - expect(pgpMailerStub.send.calledOnce).to.be.true; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); - }); - - it('should not send in offline mode', function(done) { - account.online = false; - - dao.sendPlaintext({}, function(err) { - expect(err).to.exist; - expect(pgpMailerStub.send.called).to.be.false; - expect(imapClientStub.uploadMessage.called).to.be.false; - done(); - }); + done(); }); }); - describe('#encrypt', function() { - it('should encrypt', function(done) { - pgpBuilderStub.encrypt.yieldsAsync(); + it('should send encrypted and not upload to sent', function(done) { + dao.ignoreUploadOnSent = true; - dao.encrypt({}, function() { - expect(pgpBuilderStub.encrypt.calledOnce).to.be.true; - done(); - }); + pgpMailerStub.send.withArgs({ + encrypt: true, + mail: dummyMail, + smtpclient: undefined, + publicKeysArmored: publicKeys + }).yieldsAsync(null, msg); + + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + + done(); + }); + }); + + it('should send encrypted and ignore error on upload', function(done) { + imapClientStub.uploadMessage.yields(new Error()); + pgpMailerStub.send.yieldsAsync(null, msg); + + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; + + done(); + }); + }); + + it('should not send when pgpmailer fails', function(done) { + pgpMailerStub.send.yieldsAsync({}); + + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.exist; + + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + + done(); + }); + }); + + it('should not send in offline mode', function(done) { + account.online = false; + + dao.sendEncrypted({}, function(err) { + expect(err).to.exist; + expect(pgpMailerStub.send.called).to.be.false; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); + }); + }); + + }); + + describe('#sendPlaintext', function() { + var dummyMail = {}; + var msg = 'wow. such message. much rfc2822.'; + + it('should send in the plain and upload to sent', function(done) { + pgpMailerStub.send.withArgs({ + smtpclient: undefined, + mail: dummyMail + }).yieldsAsync(null, msg); + + imapClientStub.uploadMessage.withArgs({ + path: sentFolder.path, + message: msg + }).yields(); + + dao.sendPlaintext({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; + done(); + }); + }); + + it('should send in the plain and not upload to sent', function(done) { + dao.ignoreUploadOnSent = true; + + pgpMailerStub.send.withArgs({ + smtpclient: undefined, + mail: dummyMail + }).yieldsAsync(null, msg); + + dao.sendPlaintext({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); + }); + }); + + it('should send and ignore error on upload', function(done) { + imapClientStub.uploadMessage.yields(new Error()); + pgpMailerStub.send.yieldsAsync(null, msg); + + dao.sendEncrypted({ + email: dummyMail + }, function(err) { + expect(err).to.not.exist; + + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; + + done(); + }); + }); + + it('should not send due to error', function(done) { + pgpMailerStub.send.yieldsAsync({}); + + dao.sendPlaintext({ + email: dummyMail + }, function(err) { + expect(err).to.exist; + expect(pgpMailerStub.send.calledOnce).to.be.true; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); + }); + }); + + it('should not send in offline mode', function(done) { + account.online = false; + + dao.sendPlaintext({}, function(err) { + expect(err).to.exist; + expect(pgpMailerStub.send.called).to.be.false; + expect(imapClientStub.uploadMessage.called).to.be.false; + done(); + }); + }); + }); + + describe('#encrypt', function() { + it('should encrypt', function(done) { + pgpBuilderStub.encrypt.yieldsAsync(); + + dao.encrypt({}, function() { + expect(pgpBuilderStub.encrypt.calledOnce).to.be.true; + done(); }); }); }); @@ -2147,6 +2223,22 @@ describe('Email DAO unit tests', function() { }); }); + describe('#_imapMoveMessage', function() { + it('should move a message to a destination folder', function(done) { + imapClientStub.moveMessage.withArgs({ + path: inboxFolder.path, + destination: sentFolder.path, + uid: 123 + }).yieldsAsync(); + + dao._imapMoveMessage({ + folder: inboxFolder, + destination: sentFolder, + uid: 123 + }, done); + }); + }); + describe('#_imapDeleteMessage', function() { var uid = 1337;