module EmailTest where import Prelude () import BasicPrelude import Test.Tasty.HUnit import Test.QuickCheck.Instances () import Control.Error (hush) import Control.Lens (view, set) import qualified Data.Time.Format as Time import qualified Data.MIME as MIME import qualified Data.XML.Types as XML import qualified Network.Protocol.XMPP as XMPP import Util import Email import TestInstances () mailboxFromLocal :: Text -> MIME.Mailbox mailboxFromLocal local = MIME.Mailbox Nothing $ MIME.AddrSpec (encodeUtf8 local) (MIME.DomainLiteral mempty) prop_jidToMailboxRoundtrip :: XMPP.JID -> MIME.Domain -> Bool prop_jidToMailboxRoundtrip jid domain = mailboxNode mailbox == bareTxt jid where mailbox = jidToMailbox jid domain unit_mailboxNodeUnescapes :: IO () unit_mailboxNodeUnescapes = mailboxNode (mailboxFromLocal $ s"boop=40example.com") @?= s"boop@example.com" unit_mailboxToJID :: IO () unit_mailboxToJID = mailboxToJID (s"gateway.example.com") mailbox @?= XMPP.parseJID (s"boop\\40example.com@gateway.example.com") where Right mailbox = MIME.parse (MIME.mailbox MIME.defaultCharsets) (encodeUtf8 $ s"\"Joe\" ") unit_emailToStanzaSimple :: IO () unit_emailToStanzaSimple = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"subject" ], XML.Element (s"{http://jabber.org/protocol/nick}nick") [] [ XML.NodeContent $ XML.ContentText $ s"Human" ], XML.Element (s"{urn:xmpp:sid:0}origin-id") [( s"id", [XML.ContentText $ s"boop-id@ids.example.com"] )] [], XML.Element (s"{jabber:component:accept}thread") [] [ XML.NodeContent $ XML.ContentText $ s"References: " ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: Human \n\ \Subject: subject\n\ \Message-ID: \n\ \\n\ \Hello\n" unit_emailToStanzaChat :: IO () unit_emailToStanzaChat = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageChat) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"subject" ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: subject\n\ \Chat-Version: 1.0\n\ \\n\ \Hello\n" unit_emailToStanzaChatFakeSubject :: IO () unit_emailToStanzaChatFakeSubject = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageChat) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: Chat: Hello\n\ \Chat-Version: 1.0\n\ \\n\ \Hello\n" unit_emailToStanzaChatReFakeSubject :: IO () unit_emailToStanzaChatReFakeSubject = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageChat) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: Re: Chat: Hello\n\ \Chat-Version: 1.0\n\ \\n\ \Hello\n" unit_emailToStanzUTF8Subject :: IO () unit_emailToStanzUTF8Subject = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [XML.NodeContent $ XML.ContentText $s"Hello\n"], XML.Element (s"{jabber:component:accept}subject") [] [XML.NodeContent $ XML.ContentText $ s"世界"] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: =?utf-8?B?5LiW55WM?=\n\ \\n\ \Hello\n" unit_emailToStanzaReply :: IO () unit_emailToStanzaReply = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"subject" ], XML.Element (s"{urn:xmpp:sid:0}origin-id") [( s"id", [XML.ContentText $ s"abc@example.com"] )] [], XML.Element (s"{jabber:component:accept}thread") [( s"parent", [XML.ContentText $ s"athread"] )] [ XML.NodeContent $ XML.ContentText $ s"References: \ \<123.456.athread@gateway.example.com> \ \" ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: subject\n\ \Message-ID: \n\ \References: <123.456.athread@gateway.example.com>\n\ \\n\ \Hello\n" unit_emailToStanzaReplyNulThread :: IO () unit_emailToStanzaReplyNulThread = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"subject" ], XML.Element (s"{urn:xmpp:sid:0}origin-id") [( s"id", [XML.ContentText $ s"abc@example.com"] )] [], XML.Element (s"{jabber:component:accept}thread") [] [ XML.NodeContent $ XML.ContentText $ s"References: \ \<123.456.=00@gateway.example.com> \ \" ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: subject\n\ \Message-ID: \n\ \References: <123.456.=00@gateway.example.com>\n\ \\n\ \Hello\n" unit_emailToStanzaDeepReply:: IO () unit_emailToStanzaDeepReply = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"subject" ], XML.Element (s"{urn:xmpp:sid:0}origin-id") [( s"id", [XML.ContentText $ s"abc@example.com"] )] [], XML.Element (s"{jabber:component:accept}thread") [( s"parent", [XML.ContentText $ s"References: <1583335391.\ \7d84bbbf-4dd8-42f7-81cc-d7f4ffa06609.\ \exBUAYVLbCAwUgAUpONVhfirfwVfAUZf\ \@gateway.example.com>\ \ <20200304152333.GA4768@example.com>" ] )] [ XML.NodeContent $ XML.ContentText $ s"References: <1583335391.7d84bbbf-4dd8-42f7-\ \81cc-d7f4ffa06609.exBUAYVLbCAwUgAUpON\ \VhfirfwVfAUZf@gateway.example.com>\ \ <20200304152333.GA4768@example.com>\ \ <1583335474.cdc32108-582b-4256-a5b0-\ \09c4d17af3f8.References=3A=20=3C15833\ \35391=2E7d84bbbf-4dd8-42f7-81cc-d7f4f\ \fa06609=2EexBUAYVLbCAwUgAUpONVhfirfwV\ \fAUZf=40gateway=2Eexample=2Ecom\ \=3E=20=3C20200304152333=2EGA4768=40\ \example=2Ecom=3E@gateway.example.com>\ \ " ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: subject\n\ \Message-ID: \n\ \References: <1583335391.7d84bbbf-4dd8-42f7-81cc-d7f4ffa06609\ \.exBUAYVLbCAwUgAUpONVhfirfwVfAUZf@gateway.example.com>\n\ \ <20200304152333.GA4768@example.com>\n\ \ <1583335474.cdc32108-582b-4256-a5b0-09c4d17af3f8.References\ \=3A=20=3C1583335391=2E7d84bbbf-4dd8-42f7-81cc-d7f4ffa06609\ \=2EexBUAYVLbCAwUgAUpONVhfirfwVfAUZf=40gateway=2Eexample=2Ecom\ \=3E=20=3C20200304152333=2EGA4768=40example=2Ecom=3E\ \@gateway.example.com>\n\ \\n\ \Hello\n" unit_emailToStanzaDeepInReplyTo:: IO () unit_emailToStanzaDeepInReplyTo = show (emailToStanza (s"gateway.example.com") message) @?= show (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageFrom = XMPP.parseJID $ s"f\\40example.com@gateway.example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"Hello\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"subject" ], XML.Element (s"{urn:xmpp:sid:0}origin-id") [( s"id", [XML.ContentText $ s"abc@example.com"] )] [], XML.Element (s"{jabber:component:accept}thread") [( s"parent", [XML.ContentText $ s"References: <1583335391.\ \7d84bbbf-4dd8-42f7-81cc-d7f4ffa06609.\ \exBUAYVLbCAwUgAUpONVhfirfwVfAUZf\ \@gateway.example.com>\ \ <20200304152333.GA4768@example.com>" ] )] [ XML.NodeContent $ XML.ContentText $ s"References: <1583335391.7d84bbbf-4dd8-42f7-\ \81cc-d7f4ffa06609.exBUAYVLbCAwUgAUpON\ \VhfirfwVfAUZf@gateway.example.com>\ \ <20200304152333.GA4768@example.com>\ \ <1583335474.cdc32108-582b-4256-a5b0-\ \09c4d17af3f8.References=3A=20=3C15833\ \35391=2E7d84bbbf-4dd8-42f7-81cc-d7f4f\ \fa06609=2EexBUAYVLbCAwUgAUpONVhfirfwV\ \fAUZf=40gateway=2Eexample=2Ecom\ \=3E=20=3C20200304152333=2EGA4768=40\ \example=2Ecom=3E@gateway.example.com>\ \ " ] ] } where Right message = MIME.parse (MIME.message MIME.mime) email email = encodeUtf8 $ s"To: to@example.com\n\ \From: f@example.com\n\ \Subject: subject\n\ \Message-ID: \n\ \In-Reply-To: <1583335474.cdc32108-582b-4256-a5b0-09c4d17af3f8.\ \References=3A=20=3C1583335391=2E7d84bbbf-4dd8-42f7-81cc-\ \d7f4ffa06609=2EexBUAYVLbCAwUgAUpONVhfirfwVfAUZf\ \=40gateway=2Eexample=2Ecom=3E=20=3C20200304152333\ \=2EGA4768=40example=2Ecom=3E@gateway.example.com>\n\ \\n\ \Hello\n" unit_messageToEmailChat :: IO () unit_messageToEmailChat = hush (fmap (MIME.renderMessage . emailMessage) ( messageToEmail (MIME.DomainLiteral $ encodeUtf8 $ s"gateway.example.com") date message )) @?= Just email where Just date = parseXMPPTime (s"1990-01-01T00:00:00Z") timestamp = Time.formatTime Time.defaultTimeLocale "%s" date email = s$"MIME-Version: 1.0\r\n\ \Message-ID: <" ++ timestamp ++ ".=00.=00@gateway.example.com>\r\n\ \Chat-Version: 1.0\r\n\ \To: t@example.com\r\n\ \From: =?utf-8?B?5LiW?=\ \ <=E4=B8=96=40example=2Ecom@gateway.example.com>\r\n\ \Jabber-ID: =?utf-8?B?5LiWQGV4YW1wbGUuY29t?=\r\n\ \Subject: Chat: =?utf-8?B?5LiW55WMCi4K?=\r\n\ \Date: Mon, 01 Jan 1990 00:00:00 +0000\r\n\ \Content-Transfer-Encoding: base64\r\n\ \Content-Disposition: inline\r\n\ \Content-Type: text/plain; charset=utf-8\r\n\ \\r\n\ \5LiW55WMCi4K\r\n" message = (XMPP.emptyMessage XMPP.MessageChat) { XMPP.messageTo = XMPP.parseJID $ s"t\\40example.com@gateway.example.com", XMPP.messageFrom = XMPP.parseJID $ s"世@example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"世界\n.\n" ] ] } unit_messageToEmailWithSubject :: IO () unit_messageToEmailWithSubject = hush (fmap (MIME.renderMessage . emailMessage) ( messageToEmail (MIME.DomainLiteral $ encodeUtf8 $ s"gateway.example.com") date message )) @?= Just email where Just date = parseXMPPTime (s"1990-01-01T00:00:00Z") timestamp = Time.formatTime Time.defaultTimeLocale "%s" date email = s$"MIME-Version: 1.0\r\n\ \Message-ID: <" ++ timestamp ++ ".123.=00@gateway.example.com>\r\n\ \To: t@example.com\r\n\ \From: f \r\n\ \Jabber-ID: f@example.com\r\n\ \Subject: =?utf-8?B?5LiW55WM?=\r\n\ \Date: Mon, 01 Jan 1990 00:00:00 +0000\r\n\ \Content-Transfer-Encoding: base64\r\n\ \Content-Disposition: inline\r\n\ \Content-Type: text/plain; charset=utf-8\r\n\ \\r\n\ \5LiW55WMCi4K\r\n" message = (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageID = Just $ s"123", XMPP.messageTo = XMPP.parseJID $ s"t\\40example.com@gateway.example.com", XMPP.messageFrom = XMPP.parseJID $ s"f@example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [ XML.NodeContent $ XML.ContentText $ s"世界\n.\n" ], XML.Element (s"{jabber:component:accept}subject") [] [ XML.NodeContent $ XML.ContentText $ s"世界" ] ] } unit_messageToEmailWithDelay :: IO () unit_messageToEmailWithDelay = hush (fmap (MIME.renderMessage . emailMessage) ( messageToEmail (MIME.DomainLiteral $ encodeUtf8 $ s"gateway.example.com") date message )) @?= Just email where Just date = parseXMPPTime (s"1990-01-01T00:00:00Z") timestamp = Time.formatTime Time.defaultTimeLocale "%s" date email = s$"MIME-Version: 1.0\r\n\ \Message-ID: <" ++ timestamp ++ ".=00.=00@gateway.example.com>\r\n\ \To: t@example.com\r\n\ \From: f \r\n\ \Jabber-ID: f@example.com\r\n\ \Date: Sun, 22 Feb 2009 00:10:00 +0000\r\n\ \Content-Transfer-Encoding: base64\r\n\ \Content-Disposition: inline\r\n\ \Content-Type: text/plain; charset=utf-8\r\n\ \\r\n\ \5LiW55WMCi4K\r\n" message = (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageTo = XMPP.parseJID $ s"t\\40example.com@gateway.example.com", XMPP.messageFrom = XMPP.parseJID $ s"f@example.com", XMPP.messagePayloads = [ XML.Element (s"{urn:xmpp:delay}delay") [( s"stamp", [XML.ContentText $ s"2009-02-22T00:10:00Z"] )] [], XML.Element (s"{jabber:component:accept}body") [] [XML.NodeContent $ XML.ContentText $ s"世界\n.\n"] ] } unit_messageToEmailWithThread :: IO () unit_messageToEmailWithThread = hush (fmap (MIME.renderMessage . emailMessage) ( messageToEmail (MIME.DomainLiteral $ encodeUtf8 $ s"gateway.example.com") date message )) @?= Just email where Just date = parseXMPPTime (s"1990-01-01T00:00:00Z") timestamp = Time.formatTime Time.defaultTimeLocale "%s" date email = s$"MIME-Version: 1.0\r\n\ \Message-ID: <" ++ timestamp ++ ".=00.athread@gateway.example.com>\r\n\ \To: t@example.com\r\n\ \From: f \r\n\ \Jabber-ID: f@example.com\r\n\ \Date: Mon, 01 Jan 1990 00:00:00 +0000\r\n\ \Content-Transfer-Encoding: base64\r\n\ \Content-Disposition: inline\r\n\ \Content-Type: text/plain; charset=utf-8\r\n\ \\r\n\ \5LiW55WMCi4K\r\n" message = (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageTo = XMPP.parseJID $ s"t\\40example.com@gateway.example.com", XMPP.messageFrom = XMPP.parseJID $ s"f@example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [XML.NodeContent $ XML.ContentText $ s"世界\n.\n"], XML.Element (s"{jabber:component:accept}thread") [] [XML.NodeContent $ XML.ContentText $ s"athread"] ] } unit_messageToEmailWithCheoThread :: IO () unit_messageToEmailWithCheoThread = hush (fmap (MIME.renderMessage . emailMessage) ( messageToEmail (MIME.DomainLiteral $ encodeUtf8 $ s"gateway.example.com") date message )) @?= Just email where Just date = parseXMPPTime (s"1990-01-01T00:00:00Z") timestamp = Time.formatTime Time.defaultTimeLocale "%s" date email = s$"MIME-Version: 1.0\r\n\ \Message-ID: <" ++ timestamp ++ ".=00.References=3A=20=3Cthing\ \=40foo=2Etld=3E@gateway.example.com>\r\n\ \References: \r\n\ \To: t@example.com\r\n\ \From: f \r\n\ \Jabber-ID: f@example.com\r\n\ \Date: Mon, 01 Jan 1990 00:00:00 +0000\r\n\ \Content-Transfer-Encoding: base64\r\n\ \Content-Disposition: inline\r\n\ \Content-Type: text/plain; charset=utf-8\r\n\ \\r\n\ \5LiW55WMCi4K\r\n" message = (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageTo = XMPP.parseJID $ s"t\\40example.com@gateway.example.com", XMPP.messageFrom = XMPP.parseJID $ s"f@example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [XML.NodeContent $ XML.ContentText $ s"世界\n.\n"], XML.Element (s"{jabber:component:accept}thread") [] [ XML.NodeContent $ XML.ContentText $ s"References: " ] ] } unit_messageToEmailWithDeepCheoThread :: IO () unit_messageToEmailWithDeepCheoThread = hush (fmap (MIME.renderMessage . emailMessage) ( messageToEmail (MIME.DomainLiteral $ encodeUtf8 $ s"gateway.example.com") date message )) @?= Just email where Just date = parseXMPPTime (s"1990-01-01T00:00:00Z") timestamp = Time.formatTime Time.defaultTimeLocale "%s" date email = s$"MIME-Version: 1.0\r\n\ \Message-ID: <" ++ timestamp ++ ".=00.References=3A=20=3C1=40t=2Et=3E=\ \20=3C2=40t=2Et=3E=20=3C3=40t=2Et=3E=20=3C4=40t=2Et=3E=20=3C5=\ \40t=2Et=3E=20=3C6=40t=2Et=3E@gateway.example.com>\r\n\ \References: <1@t.t> <3@t.t> <4@t.t> <5@t.t> <6@t.t>\r\n\ \To: t@example.com\r\n\ \From: f \r\n\ \Jabber-ID: f@example.com\r\n\ \Date: Mon, 01 Jan 1990 00:00:00 +0000\r\n\ \Content-Transfer-Encoding: base64\r\n\ \Content-Disposition: inline\r\n\ \Content-Type: text/plain; charset=utf-8\r\n\ \\r\n\ \5LiW55WMCi4K\r\n" message = (XMPP.emptyMessage XMPP.MessageNormal) { XMPP.messageTo = XMPP.parseJID $ s"t\\40example.com@gateway.example.com", XMPP.messageFrom = XMPP.parseJID $ s"f@example.com", XMPP.messagePayloads = [ XML.Element (s"{jabber:component:accept}body") [] [XML.NodeContent $ XML.ContentText $ s"世界\n.\n"], XML.Element (s"{jabber:component:accept}thread") [] [ XML.NodeContent $ XML.ContentText $ s"References: <1@t.t> <2@t.t> <3@t.t> <4@t.t>\ \ <5@t.t> <6@t.t>" ] ] } unit_emailMessage' :: IO () unit_emailMessage' = view emailMessage' envelope @?= email where envelope = EmailWithEnvelope email undefined undefined Right email = MIME.parse (MIME.message MIME.mime) $ encodeUtf8 $ s"To: to@example.com\n\ \From: Human \n\ \Subject: subject\n\ \Message-ID: \n\ \\n\ \Hello\n" unit_emailMessage'Set :: IO () unit_emailMessage'Set = view emailMessage' (set emailMessage' email envelope) @?= email where envelope = EmailWithEnvelope undefined undefined undefined Right email = MIME.parse (MIME.message MIME.mime) $ encodeUtf8 $ s"To: to@example.com\n\ \From: Human \n\ \Subject: subject\n\ \Message-ID: \n\ \\n\ \Hello\n"