Browse Source

Pushed entire backend interface from walrus here, changed the ParserTools into its own lib

Marcos Dumay de Medeiros 8 years ago
parent
commit
337393c378
4 changed files with 126 additions and 4 deletions
  1. 107 0
      src/Walrus/Backend.hs
  2. 3 3
      src/Walrus/Backend/Metadata.hs
  3. 9 0
      src/Walrus/Backend/Request.hs
  4. 7 1
      walrus-backend.cabal

+ 107 - 0
src/Walrus/Backend.hs

@@ -0,0 +1,107 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Walrus.Backend (
+  parseBackend,
+  runBackend
+  ) where
+
+import qualified Data.Attoparsec.ByteString.Char8 as A
+import qualified Data.Attoparsec.ByteString.Lazy as LA
+import Data.Attoparsec.ByteString.Char8.Extras
+import qualified Data.ByteString.Lazy as LBS
+import qualified Data.Char as C
+import Encoding
+
+import Walrus.Backend.Metadata
+import Walrus.Backend.Request
+
+import Control.Applicative
+
+import Network
+import System.IO
+import qualified System.Process as P
+
+data Backend = TCPBackend String Int | UnixSocketBackend String | ExecBackend String [String]
+
+parseBackend :: A.Parser Backend
+parseBackend = do
+  A.choice [
+    do
+      tp "tcp"
+      h <- tillSpace
+      p <- A.decimal
+      return $ TCPBackend h p,
+    do
+      tp "unix"
+      tp "socket"
+      p <- qStr
+      return $ UnixSocketBackend p,
+    do
+      tp "exec"
+      f <- qStr
+      pp <- parseParameters
+      return $ ExecBackend f pp
+    ]
+  where
+    tp t = do
+      skipHorizontalSpace
+      A.stringCI t
+      skipHorizontalSpace
+    tillSpace :: A.Parser String
+    tillSpace = bsutf8 <$> A.takeTill C.isSpace
+    qStr :: A.Parser String
+    qStr = bsutf8 <$> quotedString '\\' " " ""
+    parseParameters = A.many' $ do
+      p <- qStr
+      skipHorizontalSpace
+      return p
+
+runBackend :: Backend -> (Request, Metadata, LBS.ByteString) -> IO (Either String (Metadata, LBS.ByteString))
+runBackend b (req, m, qdt) = case renderMetadata m of
+  Nothing -> return $ Left "Metadata error"
+  Just rm -> do
+    edt' <- intBk b $ LBS.concat [
+      LBS.fromStrict . utf8bs . show $ req,
+      LBS.fromStrict rm,
+      "\r\n",
+      qdt]
+    case LA.parse repParse edt' of
+      LA.Fail _ _ e -> return $ Left e
+      LA.Done edt m' -> return $ Right (m', edt)
+  where
+    intBk :: Backend -> LBS.ByteString -> IO LBS.ByteString
+    intBk (TCPBackend h p) = runTcp h p
+    intBk (UnixSocketBackend f) = runUnix f
+    intBk (ExecBackend f aa) = runExec f aa
+    repParse = do
+      m' <- parseMetadata
+      A.endOfLine
+      return m'
+
+runTcp :: String -> Int -> LBS.ByteString -> IO LBS.ByteString
+runTcp host port dt = do
+  h <- connectTo host (PortNumber . fromIntegral $ port)
+  bkgTrans h dt
+
+runUnix :: String -> LBS.ByteString -> IO LBS.ByteString
+runUnix path dt = do
+  h <- connectTo "localhost" (UnixSocket path)
+  bkgTrans h dt
+
+bkgTrans :: Handle -> LBS.ByteString -> IO LBS.ByteString
+bkgTrans h dt = do
+  hSetNewlineMode h noNewlineTranslation
+  LBS.hPut h dt
+  hFlush h
+  LBS.hGetContents h
+
+runExec :: String -> [String] -> LBS.ByteString -> IO LBS.ByteString
+runExec f args dt = do
+  (Just i, Just o, _, _) <- P.createProcess (
+    (P.proc f args){P.std_in=P.CreatePipe}{
+     P.std_out=P.CreatePipe}{P.std_err=P.Inherit}
+    )
+  mapM (\h -> hSetNewlineMode h noNewlineTranslation) [i, o]
+  LBS.hPut i dt
+  hFlush i
+  LBS.hGetContents o

+ 3 - 3
src/Walrus/Backend/Metadata.hs

@@ -24,7 +24,7 @@ import Data.Maybe (isJust)
 
 import Data.Attoparsec.ByteString.Char8 (Parser)
 import qualified Data.Attoparsec.ByteString.Char8 as A
-import SMTP.Parser.ParserTools
+import Data.Attoparsec.ByteString.Char8.Extras
 import qualified Data.ByteString as BS
 import qualified Data.List as List
 
@@ -34,7 +34,7 @@ data Metadata = Metadata {_clientId :: Maybe ClientIdentity, _clientName :: Mayb
                           _mailFrom :: Maybe Account, _rcptTo :: [Address], _rcptFailed :: [(Address, Response)],
                           _auth :: Maybe ByteString, _recvDate :: Maybe UTCTime, _bodyEnc :: Mime.BodyEncoding,
                           _smtpUtf8 :: Bool, _unrecognized :: [ByteString]
-                         } deriving (Read, Show, Ord, Eq)
+                         } deriving (Show, Ord, Eq)
 
 makeLenses ''ClientIdentity
 makeLenses ''Metadata
@@ -82,7 +82,7 @@ isMetadataComplete = isJust . renderMetadata
 
 parseMetadata :: A.Parser Metadata
 parseMetadata = do
-  (m', h', p') <- parseFold parseField (def, Nothing, Nothing)
+  (m', h', p') <- parserFold parseField (def, Nothing, Nothing)
   let i = do
         h <- h'
         p <- p'

+ 9 - 0
src/Walrus/Backend/Request.hs

@@ -0,0 +1,9 @@
+module Walrus.Backend.Request where
+
+import Data.Attoparsec.ByteString
+import Data.Attoparsec.ByteString.Char8.Extras
+
+data Request = DATA deriving (Show, Read, Eq, Ord, Bounded, Enum)
+
+parseRequest :: Parser Request
+parseRequest = parseEnumCI

+ 7 - 1
walrus-backend.cabal

@@ -16,7 +16,10 @@ build-type:          Simple
 cabal-version:       >=1.10
 
 library
-  exposed-modules:     Walrus.Backend.Metadata
+  exposed-modules:
+    Walrus.Backend
+    Walrus.Backend.Metadata
+    Walrus.Backend.Request
   -- other-modules:       
   other-extensions:    OverloadedStrings, TemplateHaskell
   build-depends:
@@ -29,8 +32,11 @@ library
     iproute >=1.7,
     data-default-class,
     attoparsec >=0.11,
+    network >= 2.6,
+    process >= 1.2,
     lens,
     iso8601-time,
+    tools-for-attoparsec,
     hssealtools
   hs-source-dirs:      src
   default-language:    Haskell2010