~singpolyma/cheogram-smtp

cheogram-smtp/incoming-email.hs -rw-r--r-- 2.4 KiB
7021b245Stephen Paul Weber jabber:iq:gateway working against my local Gajim 5 months 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
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 domain email) {
			XMPP.messageTo = Just recipientJid
		}

	let messageIQs = messages <&> \message -> (XMPP.emptyIQ XMPP.IQSet) {
			XMPP.iqTo = XMPP.parseJID domain,
			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 ()