-- |
-- Module:     Network.Smtp.Connect
-- Copyright:  (c) 2011 Ertugrul Soeylemez
-- License:    BSD3
-- Maintainer: Ertugrul Soeylemez <es@ertes.de>
--
-- High level interfaces for networking.

{-# LANGUAGE ScopedTypeVariables, TypeFamilies #-}

module Network.Smtp.Connect
    ( -- * Connection
      withMxConn,
      withSmtpConn,

      -- * Initialization
      withIsmtp
    )
    where

import Control.ContStuff
import Control.Monad.IO.Peel
import Control.Exception.Peel as Ex
import Network
import Network.DnsCache
import Network.Smtp.Simple
import Network.Smtp.Types
import System.IO


-- | Perform some useful (but not necessarily needed) initialization
-- like disabling SIGPIPE and initializing sockets, run the given
-- computation and then clean up.

withIsmtp :: IO a -> IO a
withIsmtp = withSocketsDo


-- | Interface to 'withSmtpConn', which connects to the first mail
-- exchanger (MX) of the given domain on port 25.  The 'Bool' parameter
-- specifies whether to fall back to the given domain itself, if no MX
-- records can be found.

withMxConn ::
    (Applicative m, DnsMonad m, MonadPeelIO m) =>
    Domain -> Bool -> MailT a m a -> m a
withMxConn domain fallback c = do
    mMx <- resolveMX domain
    hostname <-
        case mMx of
          Just (mx:_)   -> return mx
          _ | fallback  -> return domain
            | otherwise -> throwIO $ userError "No MX records for domain"
    withSmtpConn hostname (PortNumber 25) c


-- | Connect to the specified SMTP server and run the given computation.
-- Note that there is also 'withMxConn', which resolves the MX server of
-- the given domain.

withSmtpConn ::
    forall a m. (Applicative m, MonadPeelIO m) =>
    HostName -> PortID -> MailT a m a -> m a
withSmtpConn host port c =
    Ex.bracket connect (liftIO . hClose) $ \h -> do
        sendMail_ (defSendMail h h) c

    where
    connect :: m Handle
    connect =
        liftIO $ do
            h <- connectTo host port
            hSetBuffering h NoBuffering
            hSetBinaryMode h True
            return h