{-# LINE 1 "src/Network/Telnet/LibTelnet/Ffi.hsc" #-}
module Network.Telnet.LibTelnet.Ffi where
import           Network.Telnet.LibTelnet.Iac (Iac(..), iacNull)
import           Network.Telnet.LibTelnet.Options (Option(..))
import qualified Network.Telnet.LibTelnet.Types as T
import           Control.Exception (throwIO)
import           Control.Monad (when)
import           Data.ByteString (ByteString)
import qualified Data.ByteString as B
import           Data.List (genericLength)
import           Foreign hiding (newForeignPtr)
import           Foreign.C (CSize(..), CString, CUChar(..))
import           Foreign.Concurrent (newForeignPtr)
telnetInit
  :: [T.TelnetTeloptT]
  -> TelnetEventHandlerT
  -> [T.Flag]
  -> IO (ForeignPtr T.TelnetT)
telnetInit options handler flags = do
  optionsA <- newArray0 (T.TelnetTeloptT (-1) iacNull iacNull) options
  handlerP <- wrapEventHandler handler
  let flagsC = foldr ((.|.) . T.unFlag) 0 flags
  telnet <- cTelnetInit optionsA handlerP flagsC nullPtr
  when (telnet == nullPtr) $ throwIO T.NullTelnetPtr
  newForeignPtr telnet $ do
    cTelnetFree telnet
    freeHaskellFunPtr handlerP
    free optionsA
foreign import ccall "libtelnet.h telnet_init"
  cTelnetInit
    :: Ptr T.TelnetTeloptT 
    -> FunPtr TelnetEventHandlerT 
    -> CUChar 
    -> Ptr () 
    -> IO (Ptr T.TelnetT)
foreign import ccall "libtelnet.h telnet_free"
  cTelnetFree :: Ptr T.TelnetT -> IO ()
type TelnetEventHandlerT = Ptr T.TelnetT -> Ptr T.EventT -> Ptr () -> IO ()
foreign import ccall "wrapper"
  wrapEventHandler :: TelnetEventHandlerT -> IO (FunPtr TelnetEventHandlerT)
telnetRecv :: Ptr T.TelnetT -> ByteString -> IO ()
telnetRecv telnetP bs = B.useAsCStringLen bs $
    \(buffer, size) -> cTelnetRecv telnetP buffer $ fromIntegral size
foreign import ccall "libtelnet.h telnet_recv"
  cTelnetRecv
    :: Ptr T.TelnetT 
    -> CString 
    -> CSize 
    -> IO ()
foreign import ccall "libtelnet.h telnet_iac"
  cTelnetIac
    :: Ptr T.TelnetT 
    -> Iac 
    -> IO ()
foreign import ccall "libtelnet.h telnet_negotiate"
  cTelnetNegotiate
    :: Ptr T.TelnetT 
    -> Iac 
    -> Option 
    -> IO ()
telnetSend :: Ptr T.TelnetT -> ByteString -> IO ()
telnetSend telnetP bs = B.useAsCStringLen bs $
    \(buffer, size) -> cTelnetSend telnetP buffer $ fromIntegral size
foreign import ccall "libtelnet.h telnet_send"
  cTelnetSend
    :: Ptr T.TelnetT 
    -> CString 
    -> CSize 
    -> IO ()
telnetSubnegotiation :: Ptr T.TelnetT -> Option -> ByteString -> IO ()
telnetSubnegotiation telnetP opt bs = B.useAsCStringLen bs $
    \(buffer, size) ->
      cTelnetSubnegotiation telnetP opt buffer $ fromIntegral size
foreign import ccall "libtelnet.h telnet_subnegotiation"
  cTelnetSubnegotiation
    :: Ptr T.TelnetT 
    -> Option 
    -> CString 
    -> CSize 
    -> IO ()
foreign import ccall "libtelnet.h telnet_begin_compress2"
  cTelnetBeginCompress2
    :: Ptr T.TelnetT 
    -> IO ()
foreign import ccall "libtelnet.h telnet_begin_newenviron"
  cTelnetBeginNewEnviron
    :: Ptr T.TelnetT 
    -> T.ECmd 
    -> IO ()
foreign import ccall "libtelnet.h telnet_newenviron_value"
  cTelnetNewEnvironValue
    :: Ptr T.TelnetT 
    -> T.EVar 
    -> CString 
    -> IO ()
foreign import ccall "libtelnet.h telnet_ttype_send"
  cTelnetTTypeSend
    :: Ptr T.TelnetT 
    -> IO ()
foreign import ccall "libtelnet.h telnet_ttype_is"
  cTelnetTTypeIs
    :: Ptr T.TelnetT 
    -> CString 
    -> IO ()
telnetSendZmp :: Ptr T.TelnetT -> [ByteString] -> IO ()
telnetSendZmp telnetP cmd = useAsCStrings cmd $
    \cCmd -> cTelnetSendZmp telnetP (genericLength cmd) cCmd
foreign import ccall "libtelnet.h telnet_send_zmp"
  cTelnetSendZmp
    :: Ptr T.TelnetT 
    -> CSize 
    -> Ptr CString 
    -> IO ()
useAsCStrings :: [ByteString] -> (Ptr CString -> IO a) -> IO a
useAsCStrings list f = go list [] where
  go [] css = withArray (reverse css) f
  go (bs:bss) css = B.useAsCString bs $ \cs -> go bss (cs:css)