{-# 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"





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 71 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
-- Have to define enum values outside previous declaration due to
-- hsc2hs bug in --cross-compile mode:
--    https://ghc.haskell.org/trac/ghc/ticket/13620

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

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

mapiErrors :: [(ULONG,String)]
mapiErrors =
    [ ((0)         , "Success")
{-# LINE 88 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((2)          , "Generic error or multiple errors")
{-# LINE 89 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((1)       , "User aborted")
{-# LINE 90 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((3)    , "Logoff failed")
{-# LINE 91 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((3)    , "Logon failed")
{-# LINE 92 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((4)        , "Disk full")
{-# LINE 93 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((5)      , "Not enough memory")
{-# LINE 94 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((6)    , "Access denied")
{-# LINE 95 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}

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

{-# LINE 115 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((22)           , "Message in use")
{-# LINE 116 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((23)          , "Network failure")
{-# LINE 117 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((24)       , "Invalid editfields")
{-# LINE 118 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((25)           , "Invalid recipient(s)")
{-# LINE 119 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
    , ((26)            , "Not supported")
{-# LINE 120 "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 129 "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 272 "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 278 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 0))   buf (0::ULONG)
{-# LINE 279 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 8))     buf c_name
{-# LINE 280 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  buf c_addr
{-# LINE 281 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 24))    buf (0::ULONG)
{-# LINE 282 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                    ((\hsc_ptr -> pokeByteOff hsc_ptr 32))    buf nullPtr
{-# LINE 283 "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 290 "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 317 "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 332 "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 335 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 4))       buf tsiz
{-# LINE 336 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 8))       buf tbuf
{-# LINE 337 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  buf esiz
{-# LINE 338 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 24))  buf ebuf
{-# LINE 339 "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 360 "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 367 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                ((\hsc_ptr -> pokeByteOff hsc_ptr 4))       buf (attFlag att')
{-# LINE 368 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                ((\hsc_ptr -> pokeByteOff hsc_ptr 8))     buf (maybe 0xffffffff id $ attPosition att')
{-# LINE 369 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                ((\hsc_ptr -> pokeByteOff hsc_ptr 16))  buf path
{-# LINE 370 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                ((\hsc_ptr -> pokeByteOff hsc_ptr 24))  buf name
{-# LINE 371 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
                ((\hsc_ptr -> pokeByteOff hsc_ptr 32))    buf tag
{-# LINE 372 "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 405 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 0))     buf (0::ULONG)
{-# LINE 406 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 8))    buf subject
{-# LINE 407 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 16))   buf body
{-# LINE 408 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 24)) buf message_type
{-# LINE 409 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 32)) buf date
{-# LINE 410 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 40)) buf conv_id
{-# LINE 411 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 48))        buf (msgFlags m)
{-# LINE 412 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 56))   buf from
{-# LINE 413 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 64))    buf (fromIntegral rlen :: ULONG)
{-# LINE 414 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 72))       buf rbuf
{-# LINE 415 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 80))     buf alen
{-# LINE 416 "libraries\\Win32\\System\\Win32\\SimpleMAPI.hsc" #-}
        ((\hsc_ptr -> pokeByteOff hsc_ptr 88))        buf abuf
{-# LINE 417 "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