module BibAttach where

import Control.Applicative hiding ((<|>),many)
import Control.Monad
import Control.Monad.Trans
import qualified Data.ByteString.Lazy as BS
import Data.Char
import Data.List
import Data.List.Split
import Data.Maybe
import Data.Tree
import System.Directory
import System.FilePath
import System.Process
import Data.Function
import System.FilePath

import TypedBibData
import Config

--------------------------------------
-- Attachment manipulation

sanitize :: [Char] -> [Char]
sanitize = (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
filter (\Char
c -> Char
cChar -> [Char] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [Char]
";:{}/\\" Bool -> Bool -> Bool
&& Char -> Int
ord Char
c Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
128) 
-- there seems to be a problem with big chars in filenames at the moment.
-- see http://hackage.haskell.org/trac/ghc/ticket/3307

-- save a (binary) file, safely
saveFile :: [Char] -> ByteString -> IO [Char]
saveFile [Char]
name ByteString
contents = do
  [Char] -> IO ()
putStrLn ([Char] -> IO ()) -> [Char] -> IO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Creating directory for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
name
  Bool -> [Char] -> IO ()
createDirectoryIfMissing Bool
True ([Char] -> [Char]
dropFileName [Char]
name)
  [Char] -> IO ()
putStrLn ([Char] -> IO ()) -> [Char] -> IO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Writing..."
  [Char] -> ByteString -> IO ()
BS.writeFile [Char]
name ByteString
contents
  [Char] -> IO [Char]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
name


findAttachName :: InitFile -> Entry -> [Char] -> [Char]
findAttachName InitFile
cfg Entry
entry [Char]
ext = InitFile -> [Char]
attachmentsRoot InitFile
cfg [Char] -> [Char] -> [Char]
</> ([Char] -> [Char]
sanitize ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ Entry -> [Char]
findTitle Entry
entry [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"-" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Entry -> [Char]
findYear Entry
entry [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"." [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
ext)


guessTypeByName :: [Char] -> [Char]
guessTypeByName [Char]
fname = Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
1 ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
takeExtension [Char]
fname


guessType :: FilePath -> BS.ByteString -> String
guessType :: [Char] -> ByteString -> [Char]
guessType [Char]
fname ByteString
contents 
    | HasCallStack => ByteString -> Word8
ByteString -> Word8
BS.head ByteString
contents Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Char -> Word8
ord' Char
'@' = [Char]
"bib"
    | ByteString
magic ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
pdfMagic = [Char]
"pdf"
    | ByteString
magic ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
psMagic = [Char]
"ps"
    | Bool
otherwise = [Char] -> [Char]
guessTypeByName [Char]
fname
   where magic :: ByteString
magic = Int64 -> ByteString -> ByteString
BS.take Int64
4 ByteString
contents
         pdfMagic :: ByteString
pdfMagic = [Word8] -> ByteString
BS.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ (Char -> Word8) -> [Char] -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
ord' [Char]
"%PDF"
         psMagic :: ByteString
psMagic  = [Word8] -> ByteString
BS.pack ([Word8] -> ByteString) -> [Word8] -> ByteString
forall a b. (a -> b) -> a -> b
$ (Char -> Word8) -> [Char] -> [Word8]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Word8
ord' [Char]
"%!PS"
         ord' :: Char -> Word8
ord' = Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word8) -> (Char -> Int) -> Char -> Word8
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord