~singpolyma/cheogram-smtp

ref: 3464bcaa8680d0122af20073fbc0072841d8edbd cheogram-smtp/incoming-email.hs -rw-r--r-- 2.4 KiB
3464bcaaStephen Paul Weber Always use line buffering, even when redirected to file 2 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
module Main (main) where

import Prelude ()
import BasicPrelude
import Data.Functor                    ((<&>))
import Control.Concurrent.STM          (atomically)
import Control.Error                   (hush)
import Network                         (PortID (PortNumber))
import System.Exit                     (exitFailure)
import qualified Data.ByteString.Lazy  as LByteString
import qualified Data.MIME             as MIME
import qualified Network.Protocol.XMPP as XMPP
import qualified Network.Protocol.XMPP.Internal as XMPP

import Email
import IQManager
import Router
import Util

runClient :: XMPP.JID -> Text -> XMPP.XMPP a -> IO (Either XMPP.Error a)
runClient jid =
	XMPP.runClient server jid jidStrNode
	where
	-- This is right unless there is an SRV record, which we don't check for
	Just jidStrNode = XMPP.strNode <$> XMPP.jidNode jid
	jidStrDomain = XMPP.strDomain $ XMPP.jidDomain jid
	Just domainJid = XMPP.parseJID jidStrDomain
	domainStr = textToString jidStrDomain
	server = XMPP.Server domainJid domainStr (PortNumber 5222)

main :: IO ()
main = do
	(rpcJidStr:rpcPassword:domain:envelopeTos) <- getArgs
	let Just rpcJid = XMPP.parseJID rpcJidStr

	let Just recipientJids = forM envelopeTos $ \envelopeTo ->
		(XMPP.parseJID =<<) $ fmap mailboxNode $ hush $ MIME.parse
			(MIME.mailbox MIME.defaultCharsets)
			(encodeUtf8 envelopeTo)

	input <- LByteString.getContents
	let Right email = MIME.parse messageOptionalMboxFrom input
	let messages = recipientJids <&> \recipientJid ->
		(emailToStanza (mailboxToJID domain) email) {
			XMPP.messageTo = Just recipientJid
		}

	let messageIQs = messages <&> \message -> (XMPP.emptyIQ XMPP.IQSet) {
			XMPP.iqTo = XMPP.parseJID domain,
			XMPP.iqID = bareTxt <$> XMPP.messageTo message,
			XMPP.iqPayload = Just $ XMPP.stanzaToElement message
		}

	result <- runClient rpcJid rpcPassword $ do
		void $ XMPP.bindJID rpcJid
		(sendIQ, iqReceived) <- iqManager
		void $ forkXMPP $ runRouted $ defaultRoutes {
				iqResultRoute = iqReceived,
				iqErrorRoute = iqReceived
			}

		resultsSTM <- mapM sendIQ messageIQs
		result <- liftIO $ atomically (sequence resultsSTM)
		liftIO $ case sequence result of
			Nothing -> do
				putStrLn $ s"4.5.0 Delivery timed out"
				exitFailure
			Just iqs | all ((==XMPP.IQResult) . XMPP.iqType) iqs ->
				return ()
			Just iqs -> do
				putStrLn $ s"5.5.0 Delivery error"
				print $ map XMPP.iqPayload iqs
				exitFailure

	case result of
		Left e -> print e >> exitFailure
		_ -> return ()