HaskellNet 0.3.1 → 0.4
raw patch · 8 files changed
+98/−54 lines, 8 filesdep +cryptohashdep −Cryptodep ~mime-mailPVP ok
version bump matches the API change (PVP)
Dependencies added: cryptohash
Dependencies removed: Crypto
Dependency ranges changed: mime-mail
API changes (from Hackage documentation)
+ Network.HaskellNet.Auth: hashMD5 :: [Word8] -> [Word8]
- Network.HaskellNet.Auth: hmacMD5 :: String -> String -> [Octet]
+ Network.HaskellNet.Auth: hmacMD5 :: String -> String -> [Word8]
- Network.HaskellNet.Auth: showOctet :: [Octet] -> String
+ Network.HaskellNet.Auth: showOctet :: [Word8] -> String
Files
- CHANGELOG +38/−1
- HaskellNet.cabal +4/−10
- README.md +0/−3
- src/Network/HaskellNet/Auth.hs +10/−6
- src/Network/HaskellNet/IMAP.hs +1/−1
- src/Network/HaskellNet/IMAP/Parsers.hs +5/−1
- src/Network/HaskellNet/POP3.hs +13/−8
- src/Network/HaskellNet/SMTP.hs +27/−24
CHANGELOG view
@@ -1,4 +1,41 @@ +0.3 -> 0.4+----------++ - Merge pull request #22 from dpwright/parse-fix:+ Fix parser error when passing parameters to FETCH+ (See http://stackoverflow.com/questions/26183675/error-when-fetching-subject-from-email-using-haskellnets-imap)+ - Merge pull request #20 from vincenthz/master:+ Replace Crypto by the much faster cryptohash+ - Merge pull request #19 from fegu/patch-1+ remove closeSMTP at end of sendMimeMail+ (sendMail and sendMimeMail should have the same behaviour towards the+ connection given to the function. In addition, Office365 causes the+ closeSMTP of sendMimeMail to raise an exception of already closed. Thus,+ removed.)+ - Merge pull request #18 from michaelbeaumont/issue17+ Stopped the POP3 module from removing whitespace before response lines+ except for the initial line with the POP3 status. Retrieved messages can now+ be correctly parsed.+ - Merge pull request #16 from fegu/master+ Fix store command to enable Office365 support (Adding a space between UID+ and flags in STORE command. This should have been there all the time, but+ while some IMAP servers (notably Gmail) accepts that it is missing, others+ (notably Office365) requires it.)+ - Merge pull request #10 from ppetr/master+ Improve `tryCommand` so that it includes the failed server response.+ - Improve a bad piece of code in `sendMail`.+ It used pattern matching and then catching the exception using `handle`,+ which is very non-idiomatic and error prone. Also the code seemed to catch+ the failure only to rethrow it.+ - Merge pull request #8 from ppetr/master+ Upgrade to mime-mail >= 0.4.+ - Merge pull request #5 from sordina/master+ Adding show constraint to show6 in Network/HaskellNet/IMAP.hs for+ compatibility with GHC 7.4.1+ - Merge pull request #4 from nh2/ghc-7.2+ Fix compilation with GHC 7.0 and 7.2 (fixes Char and List imports)+ 0.2.5 -> 0.3 ------------ @@ -38,4 +75,4 @@ Network.HaskellNet.Connection (POP connection functions) * IMAP.Parsers: - removed unused Either handling functions- - constraind exports (originally exported everything)+ - constraind exports (originally exported everything)commit 682edece1bf5fb5923ea5bd04309819c630ff33d
HaskellNet.cabal view
@@ -4,10 +4,10 @@ SMTP, and IMAP protocols. NOTE: this package will be split into smaller, protocol-specific packages in the future.-Version: 0.3.1+Version: 0.4 Copyright: (c) 2006 Jun Mukai Author: Jun Mukai-Maintainer: Jonathan Daugherty <drcygnus@gmail.com>+Maintainer: Jonathan Daugherty <cygnus@foobox.com> License: BSD3 License-file: LICENSE Category: Network@@ -24,12 +24,6 @@ type: git location: git://github.com/jtdaugherty/HaskellNet.git -Source-Repository this- type: git- location: git://github.com/shapr/HaskellNet.git- tag: nonmaintainerupload-- Library Hs-Source-Dirs: src GHC-Options: -Wall -fno-warn-unused-do-bind@@ -58,8 +52,8 @@ bytestring, pretty, array,- Crypto > 4.2.1,+ cryptohash, base64-string, old-time,- mime-mail >= 0.4,+ mime-mail >= 0.4.0 && < 0.5, text
README.md view
@@ -17,6 +17,3 @@ :set -fbreak-on-exception :trace main---(The source for the 0.3.1 non-maintainer upload can be found at https://github.com/shapr/HaskellNet)
src/Network/HaskellNet/Auth.hs view
@@ -1,13 +1,14 @@ module Network.HaskellNet.Auth where -import Data.Digest.MD5-import Codec.Utils+import Crypto.Hash.MD5 import qualified Codec.Binary.Base64.String as B64 (encode, decode) +import Data.Word import Data.List import Data.Bits import Data.Array+import qualified Data.ByteString as B type UserName = String type Password = String@@ -30,16 +31,19 @@ b64Decode :: String -> String b64Decode = map (toEnum.fromEnum) . B64.decode . map (toEnum.fromEnum) -showOctet :: [Octet] -> String+showOctet :: [Word8] -> String showOctet = concat . map hexChars where hexChars c = [arr ! (c `div` 16), arr ! (c `mod` 16)] arr = listArray (0, 15) "0123456789abcdef" -hmacMD5 :: String -> String -> [Octet]-hmacMD5 text key = hash $ okey ++ hash (ikey ++ map (toEnum.fromEnum) text)+hashMD5 :: [Word8] -> [Word8]+hashMD5 = B.unpack . hash . B.pack++hmacMD5 :: String -> String -> [Word8]+hmacMD5 text key = hashMD5 $ okey ++ hashMD5 (ikey ++ map (toEnum.fromEnum) text) where koc = map (toEnum.fromEnum) key key' = if length koc > 64- then hash koc ++ replicate 48 0+ then hashMD5 $ koc ++ replicate 48 0 else koc ++ replicate (64-length koc) 0 ipad = replicate 64 0x36 opad = replicate 64 0x5c
src/Network/HaskellNet/IMAP.hs view
@@ -398,7 +398,7 @@ storeFull :: IMAPConnection -> String -> FlagsQuery -> Bool -> IO [(UID, [Flag])] storeFull conn uidstr query isSilent =- fetchCommand conn ("UID STORE " ++ uidstr ++ flgs query) procStore+ fetchCommand conn ("UID STORE " ++ uidstr ++ " " ++ flgs query) procStore where fstrs fs = "(" ++ (concat $ intersperse " " $ map show fs) ++ ")" toFStr s fstrs' = s ++ (if isSilent then ".SILENT" else "") ++ " " ++ fstrs'
src/Network/HaskellNet/IMAP/Parsers.hs view
@@ -321,7 +321,11 @@ char ')' crlfP return $ Right $ (read num, pairs)- where pPair = do key <- anyChar `manyTill` space+ where pPair = do key <- (do k <- anyChar `manyTill` char '['+ ps <- anyChar `manyTill` char ']'+ space+ return (k++"["++ps++"]"))+ <|> anyChar `manyTill` space value <- (do char '(' v <- pParen `sepBy` space char ')'
src/Network/HaskellNet/POP3.hs view
@@ -33,8 +33,9 @@ import qualified Network.HaskellNet.Auth as A import Data.ByteString (ByteString)+import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BS-import Data.Digest.MD5+import Crypto.Hash.MD5 import Numeric (showHex) import Control.Applicative ((<$>))@@ -52,16 +53,20 @@ import Network.HaskellNet.POP3.Connection hexDigest :: [Char] -> [Char]-hexDigest = concatMap (flip showHex "") . hash . map (toEnum.fromEnum)+hexDigest = concatMap (flip showHex "") . B.unpack . hash . B.pack . map (toEnum.fromEnum) +blank :: Char -> Bool+blank a = isSpace a || isControl a++trimR :: ByteString -> ByteString+trimR s = let rs = BS.reverse s in+ BS.dropWhile blank rs+ strip :: ByteString -> ByteString strip = trimR . trimR- where- trimR s = let rs = BS.reverse s in- BS.dropWhile blank rs -blank :: Char -> Bool-blank a = isSpace a || isControl a+stripEnd :: ByteString -> ByteString+stripEnd = BS.reverse . trimR -- | connecting to the pop3 server specified by the hostname and port -- number@@ -101,7 +106,7 @@ return (Ok, BS.unlines (BS.drop 4 reply : rest)) else return (Err, BS.drop 5 reply) where st = stream conn- getRest = do l <- strip <$> bsGetLine st+ getRest = do l <- stripEnd <$> bsGetLine st if l == BS.singleton '.' then return [] else (l:) <$> getRest
src/Network/HaskellNet/SMTP.hs view
@@ -45,7 +45,9 @@ import Prelude hiding (catch) -data SMTPConnection = SMTPC !BSStream ![ByteString]+-- The response field seems to be unused. It's saved at one place, but never+-- retrieved.+data SMTPConnection = SMTPC { bsstream :: !BSStream, _response :: ![ByteString] } data Command = HELO String | EHLO String@@ -100,17 +102,19 @@ -> IO SMTPConnection connectSMTP = flip connectSMTPPort 25 -tryCommand :: BSStream -> Command -> Int -> ReplyCode+tryCommand :: SMTPConnection -> Command -> Int -> ReplyCode -> IO ByteString-tryCommand st cmd tries expectedReply | tries <= 0 = do- bsClose st- fail $ "cannot execute command " ++ show cmd ++- ", expected reply code " ++ show expectedReply-tryCommand st cmd tries expectedReply = do- (code, msg) <- sendCommand (SMTPC st []) cmd- if code == expectedReply then- return msg else- tryCommand st cmd (tries - 1) expectedReply+tryCommand conn cmd tries expectedReply = do+ (code, msg) <- sendCommand conn cmd+ case () of+ _ | code == expectedReply -> return msg+ _ | tries > 1 ->+ tryCommand conn cmd (tries - 1) expectedReply+ _ | otherwise -> do+ bsClose (bsstream conn)+ fail $ "cannot execute command " ++ show cmd +++ ", expected reply code " ++ show expectedReply +++ ", but received " ++ show code ++ " " ++ BS.unpack msg -- | create SMTPConnection from already connected Stream connectStream :: BSStream -> IO SMTPConnection@@ -120,7 +124,7 @@ do bsClose st fail "cannot connect to the server" senderHost <- getHostName- msg <- tryCommand st (EHLO senderHost) 3 250+ msg <- tryCommand (SMTPC st []) (EHLO senderHost) 3 250 return (SMTPC st (tail $ BS.lines msg)) parseResponse :: BSStream -> IO (ReplyCode, ByteString)@@ -207,15 +211,14 @@ -> ByteString -- ^ data -> SMTPConnection -> IO ()-sendMail sender receivers dat conn =- catcher `handle` mainProc- where mainProc =- do (250, _) <- sendCommand conn (MAIL sender)- vals <- mapM (sendCommand conn . RCPT) receivers- unless (all ((==250) . fst) vals) $ fail "sendMail error"- (250, _) <- sendCommand conn (DATA dat)+sendMail sender receivers dat conn = do+ sendAndCheck (MAIL sender)+ mapM_ (sendAndCheck . RCPT) receivers+ sendAndCheck (DATA dat) return ()- catcher e@(PatternMatchFail _) = throwIO e+ where+ -- Try the command once and @fail@ if the response isn't 250.+ sendAndCheck cmd = tryCommand conn cmd 1 250 -- | doSMTPPort open a connection, and do an IO action with the -- connection, and then close it.@@ -236,12 +239,12 @@ sendMimeMail :: String -> String -> String -> LT.Text -> LT.Text -> [(T.Text, FilePath)] -> SMTPConnection -> IO () sendMimeMail to from subject plainBody htmlBody attachments con = do- myMail <- simpleMail (Address Nothing $ T.pack to) (Address Nothing- $ T.pack from)- (T.pack subject) plainBody htmlBody attachments+ myMail <- simpleMail (address to) (address from) (T.pack subject)+ plainBody htmlBody attachments renderedMail <- renderMail' myMail sendMail from [to] (lazyToStrict renderedMail) con- closeSMTP con+ where+ address = Address Nothing . T.pack -- haskellNet uses strict bytestrings -- TODO: look at making haskellnet lazy