0.3.4.1 -> 0.4.0.2
This commit is contained in:
parent
6fe62d91af
commit
1d346b07fb
16
CHANGELOG.md
Normal file
16
CHANGELOG.md
Normal file
@ -0,0 +1,16 @@
|
||||
# Revision history for HaskellNet-SSL
|
||||
|
||||
## 0.4.0.0 -- 2025-01-07
|
||||
|
||||
- drop support for connection in favour of crypton-connection
|
||||
- compatibility with GHCs up to ghc 9.8 (bump base and bytestring)
|
||||
- fix example
|
||||
- add tested-with stanza
|
||||
|
||||
## 0.4.0.1 -- 2025-01-17
|
||||
|
||||
- Ignore 502 error on helo - fixes communication with some servers
|
||||
|
||||
## 0.4.0.1 -- 2025-02-15
|
||||
|
||||
- bump data-default and network
|
||||
@ -1,23 +1,24 @@
|
||||
name: HaskellNet-SSL
|
||||
synopsis: Helpers to connect to SSL/TLS mail servers with HaskellNet
|
||||
version: 0.3.4.1
|
||||
version: 0.4.0.2
|
||||
description: This package ties together the HaskellNet and connection
|
||||
packages to make it easy to open IMAP and SMTP connections
|
||||
over SSL.
|
||||
homepage: https://github.com/dpwright/HaskellNet-SSL
|
||||
tested-with: GHC ==9.4.8 || ==9.6.5 || ==9.8.2
|
||||
license: BSD3
|
||||
license-file: LICENSE
|
||||
author: Daniel P. Wright
|
||||
maintainer: Leza M. Lutonda <lemol-c@outlook.com>, dani@dpwright.com
|
||||
maintainer: Leza M. Lutonda <lemol-c@outlook.com>, dani@dpwright.com, contact@mangoiv.com
|
||||
copyright: (c) 2013 Daniel P. Wright
|
||||
category: Network
|
||||
build-type: Simple
|
||||
cabal-version: >=1.8
|
||||
data-files: README.md
|
||||
cabal-version: 1.18
|
||||
extra-doc-files: README.md, CHANGELOG.md
|
||||
|
||||
Flag NoUpperBounds
|
||||
Description: Removes upper bounds from all packages
|
||||
Default: False
|
||||
flag network-bsd
|
||||
description: Get Network.BSD from the network-bsd package
|
||||
default: True
|
||||
|
||||
source-repository head
|
||||
type: git
|
||||
@ -26,24 +27,30 @@ source-repository head
|
||||
library
|
||||
hs-source-dirs: src
|
||||
ghc-options: -Wall
|
||||
default-language: Haskell2010
|
||||
exposed-modules: Network.HaskellNet.IMAP.SSL
|
||||
Network.HaskellNet.POP3.SSL
|
||||
Network.HaskellNet.SMTP.SSL
|
||||
Network.HaskellNet.SSL
|
||||
other-modules: Network.HaskellNet.SSL.Internal
|
||||
if flag(NoUpperBounds)
|
||||
build-depends: base >= 4,
|
||||
HaskellNet >= 0.3,
|
||||
tls >= 1.2,
|
||||
connection >= 0.2.7,
|
||||
network >= 2.4,
|
||||
bytestring,
|
||||
data-default
|
||||
build-depends: base >= 4 && < 5,
|
||||
HaskellNet >= 0.3 && < 0.7,
|
||||
crypton-connection >= 0.3.1 && < 0.5,
|
||||
bytestring >= 0.9 && < 0.13,
|
||||
data-default >= 0.2 && < 0.9
|
||||
if flag(network-bsd)
|
||||
build-depends: network >= 3.0 && < 3.3,
|
||||
network-bsd >= 2.7 && < 2.9
|
||||
else
|
||||
build-depends: base >= 4 && < 5,
|
||||
HaskellNet >= 0.3 && < 0.6,
|
||||
tls >= 1.2 && < 1.5,
|
||||
connection >= 0.2.7 && < 0.3,
|
||||
network >= 2.4 && < 2.9,
|
||||
bytestring,
|
||||
data-default
|
||||
build-depends: network >= 2.4 && < 3.3
|
||||
|
||||
executable HaskellNet-SSL-example
|
||||
hs-source-dirs: examples
|
||||
main-is: gmail.hs
|
||||
other-modules:
|
||||
build-depends: base,
|
||||
HaskellNet-SSL,
|
||||
HaskellNet,
|
||||
bytestring
|
||||
|
||||
default-language: Haskell2010
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
HaskellNet-SSL
|
||||
--------------
|
||||
# HaskellNet-SSL
|
||||
|
||||
[](https://travis-ci.org/dpwright/HaskellNet-SSL)
|
||||
[](https://github.com/dpwright/HaskellNet-SSL/actions/workflows/haskell.yml)
|
||||
|
||||
This package ties together the excellent [HaskellNet][HaskellNet] and
|
||||
[connection][connection] packages to make it easy to open IMAP and SMTP
|
||||
[crypton-connection][crypton-connection] packages to make it easy to open IMAP and SMTP
|
||||
connections over SSL. This is a simple "glue" library; all credit for a)
|
||||
connecting to IMAP/SMTP servers and b) making an SSL connection goes to the
|
||||
aforementioned libraries.
|
||||
|
||||
[HaskellNet]: https://github.com/jtdaugherty/HaskellNet
|
||||
[connection]: https://github.com/vincenthz/hs-connection
|
||||
[crypton-connection]: https://github.com/kazu-yamamoto/crypton-connection
|
||||
|
||||
6
cabal.project
Normal file
6
cabal.project
Normal file
@ -0,0 +1,6 @@
|
||||
packages: .
|
||||
|
||||
allow-newer:
|
||||
, HaskellNet:base
|
||||
, HaskellNet:network
|
||||
, HaskellNet:data-default
|
||||
@ -3,34 +3,52 @@
|
||||
import Network.HaskellNet.IMAP.SSL
|
||||
import Network.HaskellNet.SMTP.SSL as SMTP
|
||||
|
||||
import Network.HaskellNet.Auth (AuthType(LOGIN))
|
||||
import Network.HaskellNet.Auth (AuthType(LOGIN), Password)
|
||||
import Network.Mail.Mime
|
||||
|
||||
import qualified Data.ByteString.Char8 as B
|
||||
import Data.String
|
||||
|
||||
username :: IsString s => s
|
||||
username = "username@gmail.com"
|
||||
|
||||
password :: Password
|
||||
password = "password"
|
||||
|
||||
recipient :: Address
|
||||
recipient = "someone@somewhere.com"
|
||||
|
||||
imapTest :: IO ()
|
||||
imapTest = do
|
||||
c <- connectIMAPSSLWithSettings "imap.gmail.com" cfg
|
||||
login c username password
|
||||
mboxes <- list c
|
||||
mapM_ print mboxes
|
||||
select c "INBOX"
|
||||
msgs <- search c [ALLs]
|
||||
let firstMsg = head msgs
|
||||
msgs@(firstMsg : _) <- search c [ALLs]
|
||||
msgContent <- fetch c firstMsg
|
||||
B.putStrLn msgContent
|
||||
logout c
|
||||
where cfg = defaultSettingsIMAPSSL { sslMaxLineLength = 100000 }
|
||||
|
||||
smtpTest :: IO ()
|
||||
smtpTest = doSMTPSTARTTLS "smtp.gmail.com" $ \c -> do
|
||||
authSucceed <- SMTP.authenticate LOGIN username password c
|
||||
if authSucceed
|
||||
then sendPlainTextMail recipient username subject body c
|
||||
then do
|
||||
mail <- simpleMail
|
||||
recipient
|
||||
username
|
||||
subject
|
||||
body
|
||||
mempty
|
||||
mempty
|
||||
sendMail mail c -- recipient username subject body
|
||||
else print "Authentication error."
|
||||
where subject = "Test message"
|
||||
body = "This is a test message"
|
||||
|
||||
main :: IO ()
|
||||
main = smtpTest >> imapTest >> return ()
|
||||
main = do
|
||||
smtpTest
|
||||
imapTest
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
-- | IMAP SSL Connections
|
||||
module Network.HaskellNet.IMAP.SSL
|
||||
( -- * Establishing connection
|
||||
connectIMAPSSL
|
||||
@ -15,11 +16,14 @@ import Network.HaskellNet.SSL
|
||||
|
||||
import Network.HaskellNet.SSL.Internal
|
||||
|
||||
-- | Create IMAP connection with default settings
|
||||
connectIMAPSSL :: String -> IO IMAPConnection
|
||||
connectIMAPSSL hostname = connectIMAPSSLWithSettings hostname defaultSettingsIMAPSSL
|
||||
|
||||
-- | Create IMAP connection with given settings
|
||||
connectIMAPSSLWithSettings :: String -> Settings -> IO IMAPConnection
|
||||
connectIMAPSSLWithSettings hostname cfg = connectSSL hostname cfg >>= connectStream
|
||||
|
||||
-- | Default IMAP SSL settings, port 993
|
||||
defaultSettingsIMAPSSL :: Settings
|
||||
defaultSettingsIMAPSSL = defaultSettingsWithPort 993
|
||||
|
||||
@ -48,10 +48,12 @@ connectSTARTTLS hostname cfg = do
|
||||
(bs, startTLS) <- connectPlain hostname cfg
|
||||
|
||||
greeting <- bsGetLine bs
|
||||
failIfNot bs 220 $ parseResponse greeting
|
||||
failIfNot bs 220 $ parse $ B.unpack greeting
|
||||
|
||||
hn <- getHostName
|
||||
bsPut bs $ B.pack ("HELO " ++ hn ++ "\r\n")
|
||||
getResponse bs >>= failIfNotEx bs (`elem` [250, 502])
|
||||
bsPut bs $ B.pack ("EHLO " ++ hn ++ "\r\n")
|
||||
getResponse bs >>= failIfNot bs 250
|
||||
bsPut bs $ B.pack "STARTTLS\r\n"
|
||||
getResponse bs >>= failIfNot bs 220
|
||||
@ -60,15 +62,22 @@ connectSTARTTLS hostname cfg = do
|
||||
|
||||
prefixRef <- newIORef [greeting]
|
||||
return $ bs {bsGetLine = prefixedGetLine prefixRef (bsGetLine bs)}
|
||||
where parseResponse = parse . B.unpack
|
||||
parse s = (getCode s, s)
|
||||
where getFinalResponse bs = do
|
||||
line <- fmap B.unpack $ bsGetLine bs
|
||||
if (line !! 3) == '-' then getFinalResponse bs else return line
|
||||
parse s = (getCode s, s)
|
||||
getCode = read . head . words
|
||||
getResponse bs = liftM parseResponse $ bsGetLine bs
|
||||
getResponse bs = liftM parse $ getFinalResponse bs
|
||||
|
||||
failIfNot :: BSStream -> Integer -> (Integer, String) -> IO ()
|
||||
failIfNot bs code (rc, rs) = when (code /= rc) closeAndFail
|
||||
where closeAndFail = bsClose bs >> fail ("cannot connect to server: " ++ rs)
|
||||
|
||||
-- | Extended version of fail if, can support multiple statuses
|
||||
failIfNotEx :: BSStream -> (Integer -> Bool) -> (Integer, String) -> IO ()
|
||||
failIfNotEx bs f (rc, rs) = unless (f rc) closeAndFail
|
||||
where closeAndFail = bsClose bs >> fail ("cannot connect to server: " ++ rs)
|
||||
|
||||
-- This is a bit of a nasty hack. Network.HaskellNet.SMTP.connectStream
|
||||
-- expects to receive a status 220 from the server as soon as it connects,
|
||||
-- but we've intercepted it in order to establish a STARTTLS connection.
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
{-# LANGUAGE CPP #-}
|
||||
module Network.HaskellNet.SSL
|
||||
( Settings (..)
|
||||
, defaultSettingsWithPort
|
||||
) where
|
||||
|
||||
#if MIN_VERSION_network(3,0,0)
|
||||
import Network.Socket (PortNumber)
|
||||
#else
|
||||
import Network.Socket.Internal (PortNumber)
|
||||
#endif
|
||||
|
||||
-- | Settings for configuring HaskellNet connections
|
||||
data Settings = Settings
|
||||
{ sslPort :: PortNumber
|
||||
, sslMaxLineLength :: Int
|
||||
, sslLogToConsole :: Bool
|
||||
, sslDisableCertificateValidation :: Bool
|
||||
{ sslPort :: PortNumber -- ^ Port number to connect to
|
||||
, sslMaxLineLength :: Int -- ^ Max line lengths
|
||||
, sslLogToConsole :: Bool -- ^ Log info to console
|
||||
, sslDisableCertificateValidation :: Bool -- ^ Disable certificate validation
|
||||
} deriving(Eq, Ord, Show)
|
||||
|
||||
-- | Construct default settings for a port
|
||||
defaultSettingsWithPort :: PortNumber -> Settings
|
||||
defaultSettingsWithPort p = Settings
|
||||
{ sslPort = p
|
||||
|
||||
Loading…
Reference in New Issue
Block a user