imap 0.1.0.3 → 0.2.0.0
raw patch · 5 files changed
+81/−57 lines, 5 filesdep +data-defaultdep ~HUnitdep ~QuickCheckdep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: data-default
Dependency ranges changed: HUnit, QuickCheck, bytestring, derive, either, exceptions, hslogger, list-t, monadIO, mtl, stm, stm-delay, tasty, tasty-hunit, tasty-quickcheck, transformers, word8
API changes (from Hackage documentation)
+ Network.IMAP.Types: IMAPSettings :: Int -> Int -> IMAPSettings
+ Network.IMAP.Types: [imapSettings] :: IMAPState -> IMAPSettings
+ Network.IMAP.Types: [imapTimeout] :: IMAPSettings -> Int
+ Network.IMAP.Types: [untaggedQueueLength] :: IMAPSettings -> Int
+ Network.IMAP.Types: data IMAPSettings
+ Network.IMAP.Types: instance Data.Default.Class.Default Network.IMAP.Types.IMAPSettings
- Network.IMAP: connectServer :: ConnectionParams -> IO IMAPConnection
+ Network.IMAP: connectServer :: ConnectionParams -> Maybe IMAPSettings -> IO IMAPConnection
- Network.IMAP.Types: IMAPState :: !Connection -> ConnectionContext -> TQueue ResponseRequest -> TVar (Maybe ThreadId) -> TVar [ResponseRequest] -> IMAPState
+ Network.IMAP.Types: IMAPState :: !Connection -> ConnectionContext -> TQueue ResponseRequest -> TVar (Maybe ThreadId) -> TVar [ResponseRequest] -> IMAPSettings -> IMAPState
- Network.IMAP.Utils: readResults :: (MonadPlus m, MonadIO m, Universe m) => TQueue CommandResult -> m CommandResult
+ Network.IMAP.Utils: readResults :: (MonadPlus m, MonadIO m, Universe m) => IMAPState -> ResponseRequest -> m CommandResult
Files
- imap.cabal +42/−40
- src/Network/IMAP.hs +8/−5
- src/Network/IMAP/RequestWatcher.hs +0/−1
- src/Network/IMAP/Types.hs +14/−1
- src/Network/IMAP/Utils.hs +17/−10
imap.cabal view
@@ -2,7 +2,7 @@ -- see http://haskell.org/cabal/users-guide/ name: imap-version: 0.1.0.3+version: 0.2.0.0 synopsis: An efficient IMAP client library, with SSL and streaming license: BSD3 license-file: LICENSE@@ -37,9 +37,9 @@ . > let tls = TLSSettingsSimple False False False > let params = ConnectionParams "imap.gmail.com" 993 (Just tls) Nothing- > conn <- connectServer params+ > conn <- connectServer params Nothing .- From now on you can run commands on this connection. We will use the `simpleFormat` helper function to convert from `ListT` to `IO`. Let's log in:+ From now on you can run commands on this connection. The second parameter to `connectServer` is `Maybe IMAPSettings`. If settings are not provided, sane defaults will be used. We will use the `simpleFormat` helper function to convert from `ListT` to `IO`. Let's log in: . > simpleFormat $ login conn "mylogin" "mypass" > Right [Capabilities [CIMAP4,CUnselect,CIdle,CNamespace,CQuota,CId,CExperimental "XLIST",CChildren,CExperimental "X-GM-EXT-1",CUIDPlus,CCompress "DEFLATE",CEnable,CMove,CCondstore,CEsearch,CUtf8 "ACCEPT",CListExtended,CListStatus,CAppendLimit 35882577]]@@ -87,7 +87,7 @@ . /Streaming/ .- There's an excellent article <http://www.haskellforall.com/2014/11/how-to-build-library-agnostic-streaming.html an excellent article> by Gabriel Gonzalez you should read :)+ There's <http://www.haskellforall.com/2014/11/how-to-build-library-agnostic-streaming.html an excellent article> by Gabriel Gonzalez you should read :) source-repository head type: git location: https://github.com/mkawalec/imap@@ -103,22 +103,23 @@ -- other-modules: -- other-extensions: build-depends: base >=4.8 && <4.9,- attoparsec >= 0.13 && <0.14,- text >= 1.2 && <1.3,- connection >= 0.2 && <0.3,- bytestring >= 0.10.6.0 && <0.11,- random >= 1.1 && <1.2,- word8 >= 0.1.2 && <0.2,+ attoparsec == 0.13.*,+ text == 1.2.*,+ connection == 0.2.*,+ bytestring == 0.10.*,+ random == 1.1.*,+ word8 == 0.1.* && <0.2, rolling-queue == 0.1,- stm >= 2.4.4.1 && <2.5,- either >= 4.4.1 && <4.5,- hslogger >= 1.2.9 && < 1.3,- transformers >= 0.4.2.0 && <0.5,- list-t >= 0.4.5.1 && <0.5,- monadIO >= 0.10.1.4 && <0.11,- derive >= 2.5.23 && <2.6,- stm-delay >= 0.1.1.1 && <0.2,- exceptions >= 0.8.2.1 && <0.9+ stm == 2.4.* && <2.5,+ either == 4.4.*,+ hslogger == 1.2.*,+ transformers == 0.4.*,+ list-t == 0.4.*,+ monadIO == 0.10.*,+ derive == 2.5.*,+ stm-delay == 0.1.*,+ exceptions == 0.8.*,+ data-default == 0.5.* hs-source-dirs: src default-language: Haskell2010 default-extensions: OverloadedStrings,@@ -137,29 +138,30 @@ main-is: main.hs hs-source-dirs: test, src build-depends: base >=4.8 && <4.9,- attoparsec >= 0.13 && <0.14,- text >= 1.2 && <1.3,- connection >= 0.2 && <0.3,- bytestring >= 0.10.6.0 && <0.11,- random >= 1.1 && <1.2,- word8 >= 0.1.2 && <0.2,+ attoparsec == 0.13.*,+ text == 1.2.*,+ connection == 0.2.*,+ bytestring == 0.10.*,+ random == 1.1.*,+ word8 == 0.1.* && <0.2, rolling-queue == 0.1,- stm >= 2.4.4.1 && <2.5,- either >= 4.4.1 && <4.5,- hslogger >= 1.2.9 && < 1.3,- transformers >= 0.4.2.0 && <0.5,- list-t >= 0.4.5.1 && <0.5,- monadIO >= 0.10.1.4 && <0.11,- derive >= 2.5.23 && <2.6,- stm-delay >= 0.1.1.1 && <0.2,- exceptions >= 0.8.2.1 && <0.9,+ stm == 2.4.* && <2.5,+ either == 4.4.*,+ hslogger == 1.2.*,+ transformers == 0.4.*,+ list-t == 0.4.*,+ monadIO == 0.10.*,+ derive == 2.5.*,+ stm-delay == 0.1.*,+ exceptions == 0.8.*,+ data-default == 0.5.*, - tasty >= 0.11.0.2 && <0.12,- HUnit >= 1.3.1.1 && <1.4,- QuickCheck >= 2.8.2 && <2.9,- tasty-hunit >= 0.9.2 && <0.10,- tasty-quickcheck >= 0.8.4 && <0.9,- mtl >= 2.2.1+ tasty == 0.11.*,+ HUnit == 1.3.*,+ QuickCheck == 2.8.*,+ tasty-hunit == 0.9.*,+ tasty-quickcheck == 0.8.*,+ mtl == 2.2.* default-language: Haskell2010 default-extensions: OverloadedStrings, GeneralizedNewtypeDeriving,
src/Network/IMAP.hs view
@@ -76,16 +76,18 @@ import ListT (toList, ListT) import qualified Data.List as L import qualified Debug.Trace as DT+import Data.Default (def) -- |Connects to the server and gives you a connection object -- that needs to be passed to any other command. You should only call it once -- for every connection you wish to create-connectServer :: ConnectionParams -> IO IMAPConnection-connectServer connParams = do+connectServer :: ConnectionParams -> Maybe IMAPSettings -> IO IMAPConnection+connectServer connParams wrappedSettings = do context <- initConnectionContext connection <- connectTo context connParams+ let settings = if isJust wrappedSettings then fromJust wrappedSettings else def - untaggedRespsQueue <- RQ.newIO 20+ untaggedRespsQueue <- RQ.newIO $ untaggedQueueLength settings responseRequestsQueue <- newTQueueIO connState <- newTVarIO UndefinedState watcherId <- newTVarIO Nothing@@ -96,7 +98,8 @@ connectionContext = context, responseRequests = responseRequestsQueue, serverWatcherThread = watcherId,- outstandingReqs = requests+ outstandingReqs = requests,+ imapSettings = settings } let conn = IMAPConnection {@@ -127,7 +130,7 @@ liftIO . atomically $ writeTQueue (responseRequests state) responseRequest connectionPut' (rawConnection state) commandLine- readResults responseQ+ readResults state responseRequest -- | -- = Connected state commands
src/Network/IMAP/RequestWatcher.hs view
@@ -53,7 +53,6 @@ Untagged u -> dispatchUntagged conn requests u liftIO . atomically $ writeTVar (outstandingReqs state) pendingReqs- shouldIDie conn updateConnState :: (MonadIO m, Universe m) => IMAPConnection -> CommandResult -> m ()
src/Network/IMAP/Types.hs view
@@ -12,6 +12,7 @@ connectionPut, connectionGetChunk') import ListT (ListT) import Control.Monad.IO.Class (liftIO)+import Data.Default (Default, def) -- |A type alias used for an error message type ErrorMessage = T.Text@@ -46,7 +47,9 @@ -- |Id of the thread the watcher executes on serverWatcherThread :: TVar (Maybe ThreadId), -- |All the unfulfilled requests the watcher thread knows about- outstandingReqs :: TVar [ResponseRequest]+ outstandingReqs :: TVar [ResponseRequest],+ -- |Configuration settings+ imapSettings :: IMAPSettings } data ResponseRequest = ResponseRequest {@@ -57,6 +60,13 @@ respRequestId :: CommandId } deriving (Eq) +data IMAPSettings = IMAPSettings {+ -- Number of seconds after which request timeouts+ imapTimeout :: Int,+ -- Length of a queue containing messages we weren't expecting+ untaggedQueueLength :: Int+}+ data EmailAddress = EmailAddress { emailLabel :: Maybe T.Text, emailAddress :: T.Text@@ -195,6 +205,9 @@ instance Universe (ListT IO) where connectionPut' c d = liftIO $ connectionPut c d connectionGetChunk'' c cont = liftIO $ connectionGetChunk' c cont++instance Default IMAPSettings where+ def = IMAPSettings 30 10 $(derive makeIs ''Flag) $(derive makeIs ''UntaggedResult)
src/Network/IMAP/Utils.hs view
@@ -20,25 +20,32 @@ return $ BSC.pack . Prelude.take 9 $ randomRs ('a', 'z') randomGen readResults :: (MonadPlus m, MonadIO m, Universe m) =>- TQueue CommandResult ->- m CommandResult-readResults resultsQueue = do- delay <- liftIO . newDelay $ 10 * 1000000+ IMAPState -> ResponseRequest -> m CommandResult+readResults state req@(ResponseRequest resultsQueue requestId) = do+ let timeout = imapTimeout . imapSettings $ state+ let reqs = outstandingReqs state+ + delay <- liftIO . newDelay $ timeout * 1000000 let d_wait = do didComplete <- tryWaitDelay delay if didComplete- then return . Tagged $ TaggedResult {- commandId="noid",- resultState=BAD,- resultRest="Connection timeout"- }+ then do+ -- Remove current request from the list of outstanding ones+ allReqs <- readTVar reqs+ writeTVar reqs $ filter (/=req) allReqs++ return . Tagged $ TaggedResult {+ commandId=requestId,+ resultState=BAD,+ resultRest="Connection timeout"+ } else retry readResult = readTQueue resultsQueue nextResult <- liftIO . atomically $ d_wait `orElse` readResult case nextResult of Tagged _ -> return nextResult- Untagged _ -> return nextResult `mplus` readResults resultsQueue+ Untagged _ -> return nextResult `mplus` readResults state req escapeText :: T.Text -> T.Text escapeText t = T.replace "{" "\\{" $