]> git.rkrishnan.org Git - functorrent.git/blob - src/FuncTorrent/Metainfo.hs
2c5a7254a5ba0a0c31b8a90a8ab583e52d6359c9
[functorrent.git] / src / FuncTorrent / Metainfo.hs
1 module FuncTorrent.Metainfo
2     (Info(..),
3      Metainfo(..),
4      mkInfo,
5      torrentToMetainfo
6     ) where
7
8 import Prelude hiding (lookup)
9 import Data.ByteString.Char8 (ByteString, unpack)
10 import Data.Map as M ((!), lookup)
11 import Crypto.Hash.SHA1 (hash)
12 import Data.Maybe (maybeToList)
13
14 import FuncTorrent.Bencode (BVal(..), encode, decode, bstrToString, bValToInteger)
15
16 -- only single file mode supported for the time being.
17 data Info = Info { pieceLength :: !Integer
18                  , pieces :: !ByteString
19                  , private :: !(Maybe Integer)
20                  , name :: !String
21                  , lengthInBytes :: !Integer
22                  , md5sum :: !(Maybe String)
23                  } deriving (Eq, Show)
24
25 data Metainfo = Metainfo { info :: !Info
26                          , announceList :: ![String]
27                          , creationDate :: !(Maybe Integer)
28                          , comment :: !(Maybe String)
29                          , createdBy :: !(Maybe String)
30                          , encoding :: !(Maybe String)
31                          , infoHash :: !ByteString
32                          } deriving (Eq, Show)
33
34 mkInfo :: BVal -> Maybe Info
35 mkInfo (Bdict m) = let (Bint pieceLength') = m ! "piece length"
36                        (Bstr pieces') = m ! "pieces"
37                        private' = Nothing
38                        (Bstr name') = m ! "name"
39                        (Bint length') = m ! "length"
40                        md5sum' = Nothing
41                    in Just Info { pieceLength = pieceLength'
42                                 , pieces = pieces'
43                                 , private = private'
44                                 , name = unpack name'
45                                 , lengthInBytes = length'
46                                 , md5sum = md5sum'}
47 mkInfo _ = Nothing
48
49 mkMetaInfo :: BVal   -> Either String Metainfo
50 mkMetaInfo (Bdict m)  =
51     let (Just info')  = mkInfo $ m ! "info"
52         announce'     = lookup "announce" m
53         announceList' = lookup "announce-list" m
54         creationDate' = lookup "creation date" m
55         comment'      = lookup "comment" m
56         createdBy'    = lookup "created by" m
57         encoding'     = lookup "encoding" m
58     in Right Metainfo {
59                info         = info'
60              , announceList = maybeToList (announce' >>= bstrToString)
61                               ++ getAnnounceList announceList'
62              , creationDate = bValToInteger =<< creationDate'
63              , comment      = bstrToString  =<< comment'
64              , createdBy    = bstrToString  =<< createdBy'
65              , encoding     = bstrToString  =<< encoding'
66              , infoHash     = hash . encode $ (m ! "info")
67              }
68 mkMetaInfo _ = Left "mkMetaInfo: expect an input dict"
69
70 getAnnounceList :: Maybe BVal -> [String]
71 getAnnounceList Nothing = []
72 getAnnounceList (Just (Bint _)) = []
73 getAnnounceList (Just (Bstr _)) = []
74 getAnnounceList (Just (Blist l)) = map (\s -> case s of
75                                                (Bstr s') ->  unpack s'
76                                                (Blist s') -> case s' of
77                                                               [Bstr s''] -> unpack s''
78                                                               _ -> ""
79                                                _ -> "") l
80 getAnnounceList (Just (Bdict _)) = []
81
82 torrentToMetainfo :: ByteString -> Either String Metainfo
83 torrentToMetainfo s =
84   case decode s of
85    Right d -> mkMetaInfo d
86    Left e -> Left $ show e