HaskellNet 0.5.1 → 0.5.2
raw patch · 10 files changed
+140/−26 lines, 10 filesdep +faildep +network-bsddep ~basedep ~bytestringdep ~mime-mailPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: fail, network-bsd
Dependency ranges changed: base, bytestring, mime-mail, network
API changes (from Hackage documentation)
+ Network.HaskellNet.IMAP: UNSEEN :: MailboxStatus
+ Network.HaskellNet.IMAP.Types: UNSEEN :: MailboxStatus
- Network.HaskellNet.IMAP.Types: BAD :: (Maybe StatusCode) -> String -> ServerResponse
+ Network.HaskellNet.IMAP.Types: BAD :: Maybe StatusCode -> String -> ServerResponse
- Network.HaskellNet.IMAP.Types: NO :: (Maybe StatusCode) -> String -> ServerResponse
+ Network.HaskellNet.IMAP.Types: NO :: Maybe StatusCode -> String -> ServerResponse
- Network.HaskellNet.IMAP.Types: OK :: (Maybe StatusCode) -> String -> ServerResponse
+ Network.HaskellNet.IMAP.Types: OK :: Maybe StatusCode -> String -> ServerResponse
- Network.HaskellNet.IMAP.Types: PREAUTH :: (Maybe StatusCode) -> String -> ServerResponse
+ Network.HaskellNet.IMAP.Types: PREAUTH :: Maybe StatusCode -> String -> ServerResponse
- Network.HaskellNet.POP3.Types: LIST :: (Maybe Int) -> Command
+ Network.HaskellNet.POP3.Types: LIST :: Maybe Int -> Command
- Network.HaskellNet.POP3.Types: UIDL :: (Maybe Int) -> Command
+ Network.HaskellNet.POP3.Types: UIDL :: Maybe Int -> Command
Files
- CHANGELOG +16/−0
- HaskellNet.cabal +34/−7
- README.md +2/−0
- src/Network/Compat.hs +53/−0
- src/Network/HaskellNet/IMAP.hs +14/−11
- src/Network/HaskellNet/IMAP/Parsers.hs +1/−0
- src/Network/HaskellNet/IMAP/Types.hs +1/−0
- src/Network/HaskellNet/POP3.hs +3/−2
- src/Network/HaskellNet/SMTP.hs +7/−6
- src/Text/Packrat/Parse.hs +9/−0
CHANGELOG view
@@ -1,3 +1,19 @@+0.5.2 (2020-03-19)+------------------++ - Improved Monad failure messages from sendCommmand (thanks Scott+ Fleischman)+ - Fixed IMAP append (thanks Keijo Kapp)+ - Added support for GHC 8.8.1 (thanks Oleg Grenrus)+ - Added support for network-3 (thanks Oleg Grenrus)+ - Increased upper bound on mime-mail to include 0.5 (thanks Marek+ Suchánek)+ - Improved failure message for AUTH failures (thanks Tom McLaughlin)+ - Avoided unsafe use of unsafe bytestring length functions in+ getResponse (thanks Javran Cheng)+ - Added support for UNSEEN in STATUS commands (thanks Dominik Xaver+ Hörl)+ 0.5.1 (2016-05-05) ------------------
HaskellNet.cabal view
@@ -4,7 +4,7 @@ SMTP, and IMAP protocols. NOTE: this package will be split into smaller, protocol-specific packages in the future.-Version: 0.5.1+Version: 0.5.2 Copyright: (c) 2006 Jun Mukai Author: Jun Mukai Maintainer: Jonathan Daugherty <cygnus@foobox.com>,@@ -13,8 +13,20 @@ License-file: LICENSE Category: Network Homepage: https://github.com/jtdaugherty/HaskellNet-Cabal-version: >=1.6+Cabal-version: >=1.8 Build-type: Simple+Tested-with:+ GHC ==7.0.4+ || ==7.2.2+ || ==7.4.2+ || ==7.6.3+ || ==7.8.4+ || ==7.10.3+ || ==8.0.2+ || ==8.2.2+ || ==8.4.4+ || ==8.6.5+ || ==8.8.1 Extra-Source-Files: CHANGELOG@@ -25,6 +37,11 @@ type: git location: git://github.com/jtdaugherty/HaskellNet.git +Flag network-bsd+ description: Use network-bsd+ manual: False+ default: True+ Library Hs-Source-Dirs: src GHC-Options: -Wall -fno-warn-unused-do-bind@@ -43,18 +60,28 @@ Network.HaskellNet.Debug Other-modules:+ Network.Compat Text.Packrat.Pos Text.Packrat.Parse Build-Depends:- base >= 4 && < 5,- network,+ base >= 4.3 && < 4.14,+ network >= 2.6.3.1 && < 3.2, mtl,- bytestring,+ bytestring >=0.10.2, pretty, array,- cryptohash,+ cryptohash >=0.6, base64-string, old-time,- mime-mail >= 0.4.7 && < 0.5,+ mime-mail >= 0.4.7 && < 0.6, text++ if !impl(ghc >= 8.0)+ Build-depends: fail >= 4.9.0.0 && <4.10++ if flag(network-bsd)+ Build-Depends: network-bsd >=2.7 && <2.9,+ network >=2.7+ else+ Build-Depends: network <2.7
README.md view
@@ -3,6 +3,8 @@ [](https://travis-ci.org/lemol/HaskellNet) +**NOTE: I am seeking a maintainer for this package. If you are interested, let me know!**+ This package provides client support for the E-mail protocols POP3, SMTP, and IMAP.
+ src/Network/Compat.hs view
@@ -0,0 +1,53 @@+module Network.Compat where++import Network.Socket+import Network.BSD (getProtocolNumber)+import System.IO (Handle, IOMode (..))++import qualified Control.Exception as Exception++connectTo :: String -- Hostname+ -> PortNumber -- Port Identifier+ -> IO Handle -- Connected Socket+connectTo host port = do+ proto <- getProtocolNumber "tcp"+ let hints = defaultHints { addrFlags = [AI_ADDRCONFIG]+ , addrProtocol = proto+ , addrSocketType = Stream }+ addrs <- getAddrInfo (Just hints) (Just host) (Just serv)+ firstSuccessful "connectTo" $ map tryToConnect addrs+ where+ serv = show port++ tryToConnect addr =+ Exception.bracketOnError+ (socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr))+ close -- only done if there's an error+ (\sock -> do+ connect sock (addrAddress addr)+ socketToHandle sock ReadWriteMode+ )++-- Returns the first action from a list which does not throw an exception.+-- If all the actions throw exceptions (and the list of actions is not empty),+-- the last exception is thrown.+-- The operations are run outside of the catchIO cleanup handler because+-- catchIO masks asynchronous exceptions in the cleanup handler.+-- In the case of complete failure, the last exception is actually thrown.+firstSuccessful :: String -> [IO a] -> IO a+firstSuccessful caller = go Nothing+ where+ -- Attempt the next operation, remember exception on failure+ go _ (p:ps) =+ do r <- tryIO p+ case r of+ Right x -> return x+ Left e -> go (Just e) ps++ -- All operations failed, throw error if one exists+ go Nothing [] = ioError $ userError $ caller ++ ": firstSuccessful: empty list"+ go (Just e) [] = Exception.throwIO e++-- Version of try implemented in terms of the locally defined catchIO+tryIO :: IO a -> IO (Either Exception.IOException a)+tryIO m = Exception.catch (fmap Right m) (return . Left)
src/Network/HaskellNet/IMAP.hs view
@@ -23,7 +23,8 @@ ) where -import Network+import Network.Socket (PortNumber)+import Network.Compat import Network.HaskellNet.BSStream import Network.HaskellNet.IMAP.Connection import Network.HaskellNet.IMAP.Types@@ -33,7 +34,7 @@ import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BS -import Control.Applicative ((<$>))+import Control.Applicative ((<$>), (<*>)) import Control.Monad import System.Time@@ -116,7 +117,7 @@ connectIMAPPort :: String -> PortNumber -> IO IMAPConnection connectIMAPPort hostname port =- handleToStream <$> connectTo hostname (PortNumber port)+ handleToStream <$> connectTo hostname port >>= connectStream connectIMAP :: String -> IO IMAPConnection@@ -165,7 +166,8 @@ getLs = do l <- strip <$> bsGetLine s case () of- _ | isLiteral l -> do l' <- getLiteral l (getLitLen l)+ _ | BS.null l -> return [l]+ | isLiteral l -> do l' <- getLiteral l (getLitLen l) ls <- getLs return (l' : ls) | isTagged l -> (l:) <$> getLs@@ -313,17 +315,18 @@ in sendCommand conn cmd pStatus append :: IMAPConnection -> MailboxName -> ByteString -> IO ()-append conn mbox mailData = appendFull conn mbox mailData [] Nothing+append conn mbox mailData = appendFull conn mbox mailData Nothing Nothing appendFull :: IMAPConnection -> MailboxName -> ByteString- -> [Flag] -> Maybe CalendarTime -> IO ()+ -> Maybe [Flag] -> Maybe CalendarTime -> IO () appendFull conn mbox mailData flags' time = do (buf, num) <- sendCommand' conn- (unwords ["APPEND", mbox- , fstr, tstr, "{" ++ show len ++ "}"])- unless (BS.null buf || (BS.head buf /= '+')) $+ (concat ["APPEND ", mbox+ , fstr, tstr, " {" ++ show len ++ "}"])+ when (BS.null buf || (BS.head buf /= '+')) $ fail "illegal server response" mapM_ (bsPutCrLf $ stream conn) mailLines+ bsPutCrLf (stream conn) BS.empty buf2 <- getResponse $ stream conn let (resp, mboxUp, ()) = eval pNone (show6 num) buf2 case resp of@@ -333,8 +336,8 @@ PREAUTH _ msg -> fail ("PREAUTH: "++msg) where mailLines = BS.lines mailData len = sum $ map ((2+) . BS.length) mailLines- tstr = maybe "" show time- fstr = unwords $ map show flags'+ tstr = maybe "" ((" "++) . show) time+ fstr = maybe "" ((" ("++) . (++")") . unwords . map show) flags' check :: IMAPConnection -> IO () check conn = sendCommand conn "CHECK" pNone
src/Network/HaskellNet/IMAP/Parsers.hs view
@@ -268,6 +268,7 @@ , string "RECENT" >>= return . read , string "UIDNEXT" >>= return . read , string "UIDVALIDITY" >>= return . read+ , string "UNSEEN" >>= return . read ] space num <- many1 digit >>= return . read
src/Network/HaskellNet/IMAP/Types.hs view
@@ -97,6 +97,7 @@ | RECENT -- ^ the number of messages with the \Recent flag set | UIDNEXT -- ^ the next unique identifier value of the mailbox | UIDVALIDITY -- ^ the unique identifier validity value of the mailbox+ | UNSEEN -- ^ the number of messages with the \Unseen flag set deriving (Show, Read, Eq)
src/Network/HaskellNet/POP3.hs view
@@ -31,7 +31,8 @@ where import Network.HaskellNet.BSStream-import Network+import Network.Socket+import Network.Compat import qualified Network.HaskellNet.Auth as A import Data.ByteString (ByteString)@@ -74,7 +75,7 @@ -- number connectPop3Port :: String -> PortNumber -> IO POP3Connection connectPop3Port hostname port =- handleToStream <$> (connectTo hostname (PortNumber port))+ handleToStream <$> (connectTo hostname port) >>= connectStream -- | connecting to the pop3 server specified by the hostname. 110 is
src/Network/HaskellNet/SMTP.hs view
@@ -74,7 +74,8 @@ import Data.ByteString (ByteString) import qualified Data.ByteString.Char8 as BS import Network.BSD (getHostName)-import Network+import Network.Socket+import Network.Compat import Control.Applicative ((<$>)) import Control.Exception@@ -140,7 +141,7 @@ -> PortNumber -- ^ port number -> IO SMTPConnection connectSMTPPort hostname port =- (handleToStream <$> connectTo hostname (PortNumber port))+ (handleToStream <$> connectTo hostname port) >>= connectStream -- | connecting SMTP server with the specified name and port 25.@@ -190,8 +191,8 @@ sendCommand :: SMTPConnection -> Command -> IO (ReplyCode, ByteString) sendCommand (SMTPC conn _) (DATA dat) = do bsPutCrLf conn $ BS.pack "DATA"- (code, _) <- parseResponse conn- unless (code == 354) $ fail "this server cannot accept any data."+ (code, msg) <- parseResponse conn+ unless (code == 354) $ fail $ "this server cannot accept any data. code: " ++ show code ++ ", msg: " ++ BS.unpack msg mapM_ (sendLine . stripCR) $ BS.lines dat ++ [BS.pack "."] parseResponse conn where sendLine = bsPutCrLf conn@@ -210,7 +211,7 @@ sendCommand (SMTPC conn _) (AUTH at username password) = do bsPutCrLf conn command (code, msg) <- parseResponse conn- unless (code == 334) $ fail "authentication failed."+ unless (code == 334) $ fail $ "authentication failed. code: " ++ show code ++ ", msg: " ++ BS.unpack msg bsPutCrLf conn $ BS.pack $ auth at (BS.unpack msg) username password parseResponse conn where command = BS.pack $ unwords ["AUTH", show at]@@ -359,7 +360,7 @@ -- haskellNet uses strict bytestrings -- TODO: look at making haskellnet lazy lazyToStrict :: B.ByteString -> S.ByteString-lazyToStrict = S.concat . B.toChunks+lazyToStrict = B.toStrict crlf :: BS.ByteString crlf = BS.pack "\r\n"
src/Text/Packrat/Parse.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} -- | Packrat parsing: Simple, Powerful, Lazy, Linear time by Bryan -- Ford. This module achieves monadic parsing library similar to -- Parsec.@@ -14,6 +15,8 @@ import Control.Applicative (Applicative(..)) import qualified Control.Applicative as A +import qualified Control.Monad.Fail as Fail+ -- Data types data Message = Expected String@@ -62,6 +65,12 @@ second err1 (NoParse err) = NoParse (joinErrors err1 err) return = pure++#if !(MIN_VERSION_base(4,13,0))+ fail = Fail.fail+#endif++instance Derivs d => Fail.MonadFail (Parser d) where fail msg = Parser (\dvs -> NoParse (msgError (dvPos dvs) msg)) instance Derivs d => A.Alternative (Parser d) where