dist-install\build\System\Win32\SimpleMAPI.hs

    {-# LINE 1 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

    {-# LINE 2 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    {-# LANGUAGE Safe #-}

    {-# LINE 6 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  System.Win32.SimpleMAPI
    -- Copyright   :  (c) Esa Ilari Vuokko, 2006
    -- License     :  BSD-style (see the file LICENSE)
    --
    -- Maintainer  :  Esa Ilari Vuokko <ei@vuokko.info>
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- FFI-bindings to interact with SimpleMAPI
    --
    -----------------------------------------------------------------------------
    module System.Win32.SimpleMAPI
    where

    -- I am not sure why exactly, but with mingw64 mapi.h does not define
    -- some of the values we use, e.g. MAPI_LOGOFF_SHARED.
    -- mapix.h does define MAPI_LOGOFF_SHARED, but the various flags
    -- clash with each other.

    import Control.Exception    ( bracket, handle, finally, onException
                                , IOException )
    import Control.Monad        ( liftM5 )
    import Foreign              ( FunPtr, newForeignPtr, pokeByteOff, maybeWith
                                , Ptr, castPtr, castPtrToFunPtr, nullPtr
                                , touchForeignPtr, alloca, peek, allocaBytes
                                , minusPtr, plusPtr, copyBytes, ForeignPtr )
    import Foreign.C            ( withCAString, withCAStringLen )
      -- Apparently, simple MAPI does not support unicode and probably never will,
      -- so this module will just mangle any Unicode in your strings
    import Graphics.Win32.GDI.Types     ( HWND)
    import System.Win32.DLL     ( loadLibrary, c_GetProcAddress, freeLibrary
                                , c_FreeLibraryFinaliser )
    import System.Win32.Types   ( DWORD, LPSTR, HMODULE, failIfNull )

    #include "windows_cconv.h"

    {-# LINE 45 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

    {-# LINE 46 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

    type ULONG = DWORD
    type LHANDLE = ULONG
    newtype MapiRecipDesc = MapiRecipDesc ()
    type MapiFlag = ULONG
    mAPI_LOGON_UI          :: MapiFlag
    mAPI_LOGON_UI          =  1
    mAPI_NEW_SESSION       :: MapiFlag
    mAPI_NEW_SESSION       =  2
    mAPI_FORCE_DOWNLOAD    :: MapiFlag
    mAPI_FORCE_DOWNLOAD    =  4096
    mAPI_DIALOG            :: MapiFlag
    mAPI_DIALOG            =  8
    mAPI_UNREAD_ONLY       :: MapiFlag
    mAPI_UNREAD_ONLY       =  32
    mAPI_LONG_MSGID        :: MapiFlag
    mAPI_LONG_MSGID        =  16384
    mAPI_GUARANTEE_FIFO    :: MapiFlag
    mAPI_GUARANTEE_FIFO    =  256
    mAPI_ENVELOPE_ONLY     :: MapiFlag
    mAPI_ENVELOPE_ONLY     =  64
    mAPI_PEEK              :: MapiFlag
    mAPI_PEEK              =  128
    mAPI_BODY_AS_FILE      :: MapiFlag
    mAPI_BODY_AS_FILE      =  512
    mAPI_SUPPRESS_ATTACH   :: MapiFlag
    mAPI_SUPPRESS_ATTACH   =  2048
    mAPI_AB_NOMODIFY       :: MapiFlag
    mAPI_AB_NOMODIFY       =  1024
    mAPI_OLE               :: MapiFlag
    mAPI_OLE               =  1
    mAPI_OLE_STATIC        :: MapiFlag
    mAPI_OLE_STATIC        =  2
    mAPI_UNREAD            :: MapiFlag
    mAPI_UNREAD            =  1
    mAPI_RECEIPT_REQUESTED  :: MapiFlag
    mAPI_RECEIPT_REQUESTED  =  2
    mAPI_SENT              :: MapiFlag
    mAPI_SENT              =  4

    {-# LINE 77 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

    mapiErrors :: [(ULONG,String)]
    mapiErrors =
        [ ((0)         , "Success")
    {-# LINE 81 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((2)          , "Generic error or multiple errors")
    {-# LINE 82 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((1)       , "User aborted")
    {-# LINE 83 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((3)    , "Logoff failed")
    {-# LINE 84 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((3)    , "Logon failed")
    {-# LINE 85 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((4)        , "Disk full")
    {-# LINE 86 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((5)      , "Not enough memory")
    {-# LINE 87 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((6)    , "Access denied")
    {-# LINE 88 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

    {-# LINE 91 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((8), "Too many open sessions")
    {-# LINE 92 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((9)   , "Too many open files")
    {-# LINE 93 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((10)      , "Too many recipients")
    {-# LINE 94 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((11)     , "Attachemnt not found")
    {-# LINE 95 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((12)  , "Couldn't open attachment")
    {-# LINE 96 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((13) , "Couldn't write attachment")
    {-# LINE 97 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((14)        , "Unknown recipient")
    {-# LINE 98 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((15)            , "Bad recipient type")
    {-# LINE 99 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((16)              , "No messages")
    {-# LINE 100 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((17)          , "Invalid message")
    {-# LINE 101 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((18)           , "Text too large")
    {-# LINE 102 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((19)          , "Invalid session")
    {-# LINE 103 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((20)       , "Type not supported")
    {-# LINE 104 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((21)      , "Ambigious recipient")
    {-# LINE 105 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

    {-# LINE 108 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((22)           , "Message in use")
    {-# LINE 109 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((23)          , "Network failure")
    {-# LINE 110 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((24)       , "Invalid editfields")
    {-# LINE 111 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((25)           , "Invalid recipient(s)")
    {-# LINE 112 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        , ((26)            , "Not supported")
    {-# LINE 113 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ]

    mapiErrorString :: ULONG -> String
    mapiErrorString c = case lookup c mapiErrors of
        Nothing -> "Unkown error (" ++ show c ++ ")"
        Just x  -> x

    mapiFail :: String -> IO ULONG -> IO ULONG
    mapiFail name act = act >>= \err -> if err==(0)
    {-# LINE 122 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        then return err
        else fail $ name ++ ": " ++ mapiErrorString err

    mapiFail_ :: String -> IO ULONG -> IO ()
    mapiFail_ n a = mapiFail n a >> return ()

    type MapiLogonType = ULONG -> LPSTR -> LPSTR -> MapiFlag -> ULONG -> Ptr LHANDLE -> IO ULONG
    foreign import WINDOWS_CCONV "dynamic" mkMapiLogon :: FunPtr MapiLogonType -> MapiLogonType

    type MapiLogoffType = LHANDLE -> ULONG -> MapiFlag -> ULONG -> IO ULONG
    foreign import WINDOWS_CCONV "dynamic" mkMapiLogoff :: FunPtr MapiLogoffType -> MapiLogoffType

    type MapiResolveNameType =
        LHANDLE -> ULONG -> LPSTR -> MapiFlag -> ULONG
        -> Ptr (Ptr MapiRecipDesc) -> IO ULONG
    foreign import WINDOWS_CCONV "dynamic" mkMapiResolveName :: FunPtr MapiResolveNameType -> MapiResolveNameType

    type MapiFreeBufferType = Ptr () -> IO ULONG
    foreign import WINDOWS_CCONV "dynamic" mkMapiFreeBuffer :: FunPtr MapiFreeBufferType -> MapiFreeBufferType

    type MapiSendMailType = LHANDLE -> ULONG -> Ptr Message -> MapiFlag -> ULONG -> IO ULONG
    foreign import WINDOWS_CCONV "dynamic" mkMapiSendMail :: FunPtr MapiSendMailType -> MapiSendMailType

    data MapiFuncs = MapiFuncs
        { mapifLogon    :: MapiLogonType
        , mapifLogoff   :: MapiLogoffType
        , mapifResolveName  :: MapiResolveNameType
        , mapifFreeBuffer   :: MapiFreeBufferType
        , mapifSendMail :: MapiSendMailType
        }

    type MapiLoaded = (MapiFuncs, ForeignPtr ())

    -- |
    loadMapiFuncs :: String -> HMODULE -> IO MapiFuncs
    loadMapiFuncs dllname dll =  liftM5 MapiFuncs
        (loadProc "MAPILogon"       dll mkMapiLogon)
        (loadProc "MAPILogoff"      dll mkMapiLogoff)
        (loadProc "MAPIResolveName" dll mkMapiResolveName)
        (loadProc "MAPIFreeBuffer"  dll mkMapiFreeBuffer)
        (loadProc "MAPISendMail"    dll mkMapiSendMail)
        where
           loadProc :: String -> HMODULE -> (FunPtr a -> a) -> IO a
           loadProc name dll' conv = withCAString name $ \name' -> do
                proc <- failIfNull ("loadMapiDll: " ++ dllname ++ ": " ++ name)
                            $ c_GetProcAddress dll' name'
                return $ conv $ castPtrToFunPtr proc
    -- |
    loadMapiDll :: String -> IO (MapiFuncs, HMODULE)
    loadMapiDll dllname = do
        dll <- loadLibrary dllname
        do funcs <- loadMapiFuncs dllname dll
           return (funcs, dll)
         `onException` freeLibrary dll

    -- |
    withMapiFuncs :: [String] -> (MapiFuncs -> IO a) -> IO a
    withMapiFuncs dlls act = bracket load free (act . fst)
        where
            loadOne l = case l of
                []  -> fail $ "withMapiFuncs: Failed to load DLLs: " ++ show dlls
                x:y -> handleIOException (const $ loadOne y) (loadMapiDll x)
            load = loadOne dlls
            free = freeLibrary . snd

    -- |
    loadMapi :: [String] -> IO MapiLoaded
    loadMapi dlls = do
        (f,m) <- loadOne dlls
        m' <- newForeignPtr c_FreeLibraryFinaliser m
        return (f,m')
        where
            loadOne l = case l of
                []  -> fail $ "loadMapi: Failed to load any of DLLs: " ++ show dlls
                x:y -> handleIOException (const $ loadOne y) (loadMapiDll x)

    -- |
    withMapiLoaded :: MapiLoaded -> (MapiFuncs -> IO a) -> IO a
    withMapiLoaded (f,m) act = finally (act f) (touchForeignPtr m)

    maybeHWND :: Maybe HWND -> ULONG
    maybeHWND = maybe 0 (fromIntegral . flip minusPtr nullPtr)

    -- | Create Simple MAPI-session by logon
    mapiLogon
        :: MapiFuncs    -- ^ Functions loaded from MAPI DLL
        -> Maybe HWND   -- ^ Parent window, used for modal logon dialog
        -> Maybe String -- ^ Session
        -> Maybe String -- ^ Password
        -> MapiFlag     -- ^ None, one or many flags: FORCE_DOWNLOAD, NEW_SESSION, LOGON_UI, PASSWORD_UI
        -> IO LHANDLE
    mapiLogon f hwnd ses pw flags =
        maybeWith withCAString ses  $ \c_ses ->
        maybeWith withCAString pw   $ \c_pw  ->
        alloca                      $ \out   -> do
            mapiFail_ "MAPILogon: " $ mapifLogon
                f (maybeHWND hwnd)
                c_ses c_pw flags 0 out
            peek out

    -- | End Simple MAPI-session
    mapiLogoff
        :: MapiFuncs
        -> LHANDLE
        -> Maybe HWND
        -> IO ()
    mapiLogoff f ses hwnd
        = mapiFail_ "MAPILogoff"
            $ mapifLogoff f ses (maybeHWND hwnd) 0 0

    data RecipientClass = RcOriginal | RcTo | RcCc | RcBcc
        deriving (Show, Eq, Ord, Enum)

    rcToULONG :: RecipientClass -> ULONG
    rcToULONG = fromIntegral . fromEnum

    uLONGToRc :: ULONG -> RecipientClass
    uLONGToRc = toEnum . fromIntegral

    data Recipient
        = RecipResolve (Maybe HWND) MapiFlag String (Maybe Recipient)
        | Recip String String
        deriving (Show)
    type Recipients = [(RecipientClass, Recipient)]

    simpleRecip :: String -> Recipient
    simpleRecip s = RecipResolve Nothing 0 s $ Just $ Recip s s

    withRecipient
        :: MapiFuncs
        -> LHANDLE
        -> RecipientClass
        -> Recipient
        -> (Ptr MapiRecipDesc -> IO a)
        -> IO a
    withRecipient f ses rcls rec act = resolve "" rec
        where
            a buf = do
                ((\hsc_ptr -> pokeByteOff hsc_ptr 4)) buf (rcToULONG rcls)
    {-# LINE 265 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                act buf
            resolve err rc = case rc of
                Recip name addr ->
                    withCAString name $ \c_name ->
                    withCAString addr $ \c_addr ->
                    allocaBytes ((40)) $ \buf -> do
    {-# LINE 271 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                        ((\hsc_ptr -> pokeByteOff hsc_ptr 0))   buf (0::ULONG)
    {-# LINE 272 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                        ((\hsc_ptr -> pokeByteOff hsc_ptr 8))     buf c_name
    {-# LINE 273 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                        ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  buf c_addr
    {-# LINE 274 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                        ((\hsc_ptr -> pokeByteOff hsc_ptr 24))    buf (0::ULONG)
    {-# LINE 275 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                        ((\hsc_ptr -> pokeByteOff hsc_ptr 32))    buf nullPtr
    {-# LINE 276 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                        a buf
                RecipResolve hwnd flag name fallback -> do
                    res <-  alloca          $ \res ->
                            withCAString name $ \name' -> do
                                errn <- mapifResolveName
                                        f ses (maybeHWND hwnd) name' flag 0 res
                                if errn==(0)
    {-# LINE 283 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                                    then do
                                        buf <- peek res
                                        v <- a buf
                                        _ <- mapifFreeBuffer f $ castPtr buf
                                        return $ Right v
                                    else return $ Left
                                        $ err ++ ", "
                                        ++ name ++ ":" ++ mapiErrorString errn
                    case res of
                        Left e -> case fallback of
                            Nothing -> fail $ "Failed to resolve any of the recipients: " ++ e
                            Just x  -> resolve e x
                        Right x -> return x

    withRecipients
        :: MapiFuncs
        -> LHANDLE
        -> Recipients
        -> (Int -> Ptr MapiRecipDesc -> IO a)
        -> IO a
    withRecipients f ses rec act = w [] rec
        where
            w res [] = allocaBytes (length res*rs) $ \buf -> do
                mapM_ (write buf) $ zip [0..] $ reverse res
                act (length res) buf
            w res ((c,r):y) = withRecipient f ses c r $ \x -> w (x:res) y
            rs = ((40))
    {-# LINE 310 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            write buf (off,src) = do
                let buf' = plusPtr buf (off*rs)
                copyBytes buf' src rs

    data FileTag = FileTag
        { ftTag         :: Maybe String -- ^ mime
        , ftEncoding    :: Maybe String
        } deriving (Show)

    defFileTag :: FileTag
    defFileTag = FileTag Nothing Nothing

    withFileTag :: FileTag -> (Ptr FileTag -> IO a) -> IO a
    withFileTag ft act =
        allocaBytes ((32))  $ \buf ->
    {-# LINE 325 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        w (ftTag ft)                        $ \(tbuf,tsiz) ->
        w (ftEncoding ft)                   $ \(ebuf,esiz) -> do
            ((\hsc_ptr -> pokeByteOff hsc_ptr 0))  buf (0::ULONG)
    {-# LINE 328 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 4))       buf tsiz
    {-# LINE 329 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 8))       buf tbuf
    {-# LINE 330 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  buf esiz
    {-# LINE 331 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 24))  buf ebuf
    {-# LINE 332 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            act buf
        where
            w v a = case v of
                Nothing -> a (nullPtr, 0)
                Just x  -> withCAStringLen x a

    data Attachment = Attachment
        { attFlag       :: MapiFlag
        , attPosition   :: Maybe ULONG
        , attPath       :: String
        , attName       :: Maybe String
        , attTag        :: Maybe FileTag
        } deriving (Show)
    defAttachment :: Attachment
    defAttachment = Attachment 0 Nothing "" Nothing Nothing
    type Attachments = [Attachment]

    withAttachments :: Attachments -> (Int -> Ptr Attachment -> IO a) -> IO a
    withAttachments att act = allocaBytes (len*as) $ \buf -> write (act len buf) buf att
        where
            as = ((40))
    {-# LINE 353 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            len = length att
            write act' _ [] = act'
            write act' buf (att':y) =
                withCAString (attPath att') $ \path ->
                maybeWith withFileTag (attTag att') $ \tag ->
                withCAString (maybe (attPath att') id (attName att')) $ \name -> do
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 0))    buf (0::ULONG)
    {-# LINE 360 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 4))       buf (attFlag att')
    {-# LINE 361 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 8))     buf (maybe 0xffffffff id $ attPosition att')
    {-# LINE 362 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  buf path
    {-# LINE 363 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 24))  buf name
    {-# LINE 364 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 32))    buf tag
    {-# LINE 365 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    write act' (plusPtr buf as) y

    data Message = Message
        { msgSubject    :: String
        , msgBody       :: String
        , msgType       :: Maybe String
        , msgDate       :: Maybe String
        , msgConversationId :: Maybe String
        , msgFlags      :: MapiFlag
        , msgFrom       :: Maybe Recipient
        , msgRecips     :: Recipients
        , msgAttachments :: Attachments
        } deriving (Show)

    defMessage :: Message
    defMessage = Message "" "" Nothing Nothing Nothing 0 Nothing [] []

    withMessage
        :: MapiFuncs
        -> LHANDLE
        -> Message
        -> (Ptr Message -> IO a)
        -> IO a
    withMessage f ses m act =
        withCAString (msgSubject m)             $ \subject ->
        withCAString (msgBody m)                $ \body ->
        maybeWith withCAString (msgType m)      $ \message_type ->
        maybeWith withCAString (msgDate m)      $ \date ->
        maybeWith withCAString (msgConversationId m) $ \conv_id ->
        withRecipients f ses (msgRecips m)          $ \rlen rbuf ->
        withAttachments (msgAttachments m)      $ \alen abuf ->
        maybeWith (withRecipient f ses RcOriginal) (msgFrom m) $ \from ->
        allocaBytes ((96))             $ \buf -> do
    {-# LINE 398 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 0))     buf (0::ULONG)
    {-# LINE 399 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 8))    buf subject
    {-# LINE 400 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 16))   buf body
    {-# LINE 401 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) buf message_type
    {-# LINE 402 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) buf date
    {-# LINE 403 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) buf conv_id
    {-# LINE 404 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 48))        buf (msgFlags m)
    {-# LINE 405 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 56))   buf from
    {-# LINE 406 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 64))    buf (fromIntegral rlen :: ULONG)
    {-# LINE 407 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 72))       buf rbuf
    {-# LINE 408 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 80))     buf alen
    {-# LINE 409 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            ((\hsc_ptr -> pokeByteOff hsc_ptr 88))        buf abuf
    {-# LINE 410 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
            act buf

    mapiSendMail :: MapiFuncs -> LHANDLE -> Maybe HWND -> Message -> MapiFlag -> IO ()
    mapiSendMail f ses hwnd msg flag = withMessage f ses msg $ \c_msg ->
        mapiFail_ "MAPISendMail" $ mapifSendMail f ses (maybeHWND hwnd) c_msg flag 0

    handleIOException :: (IOException -> IO a) -> IO a -> IO a
    handleIOException = handle