]> git.rkrishnan.org Git - functorrent.git/blob - src/FuncTorrent/Metainfo.hs
4cc6ed126c2685528427f0145db03f9dbc5ae6a6
[functorrent.git] / src / FuncTorrent / Metainfo.hs
1 {-
2  - Copyright (C) 2015-2016 Ramakrishnan Muthukrishnan <ram@rkrishnan.org>
3  -
4  - This file is part of FuncTorrent.
5  -
6  - FuncTorrent is free software; you can redistribute it and/or modify
7  - it under the terms of the GNU General Public License as published by
8  - the Free Software Foundation; either version 3 of the License, or
9  - (at your option) any later version.
10  -
11  - FuncTorrent is distributed in the hope that it will be useful,
12  - but WITHOUT ANY WARRANTY; without even the implied warranty of
13  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  - GNU General Public License for more details.
15  -
16  - You should have received a copy of the GNU General Public License
17  - along with FuncTorrent; if not,  see <http://www.gnu.org/licenses/>
18  -}
19
20 {-# LANGUAGE OverloadedStrings #-}
21 module FuncTorrent.Metainfo
22     (Info(..),
23      Metainfo(..),
24      torrentToMetainfo
25     ) where
26
27 import Prelude hiding (lookup)
28 import Data.ByteString.Char8 (ByteString, unpack)
29 import Data.Map as M ((!), lookup)
30 import Crypto.Hash.SHA1 (hash)
31 import Data.Maybe (maybeToList)
32
33 import FuncTorrent.Bencode (BVal(..), encode, decode, bstrToString, bValToInteger)
34
35 -- only single file mode supported for the time being.
36 data Info = Info { pieceLength :: !Integer
37                  , pieces :: !ByteString
38                  , private :: !(Maybe Integer)
39                  , name :: !String
40                  , lengthInBytes :: !Integer
41                  , md5sum :: !(Maybe String)
42                  } deriving (Eq, Show)
43
44 data Metainfo = Metainfo { info :: !(Maybe Info)
45                          , announceList :: ![String]
46                          , creationDate :: !(Maybe Integer)
47                          , comment :: !(Maybe String)
48                          , createdBy :: !(Maybe String)
49                          , encoding :: !(Maybe String)
50                          , infoHash :: !ByteString
51                          } deriving (Eq, Show)
52
53 bvalToInfo :: BVal -> Maybe Info
54 bvalToInfo (Bdict m) = let (Bint pieceLength') = m ! "piece length"
55                            (Bstr pieces') = m ! "pieces"
56                            private' = Nothing
57                            (Bstr name') = m ! "name"
58                            (Bint length') = m ! "length"
59                            md5sum' = Nothing
60                        in Just Info { pieceLength = pieceLength'
61                                     , pieces = pieces'
62                                     , private = private'
63                                     , name = unpack name'
64                                     , lengthInBytes = length'
65                                     , md5sum = md5sum'}
66 bvalToInfo _ = Nothing
67
68 mkMetaInfo :: BVal   -> Either String Metainfo
69 mkMetaInfo (Bdict m)  =
70     let info'         = bvalToInfo $ m ! "info"
71         announce'     = lookup "announce" m
72         announceList' = lookup "announce-list" m
73         creationDate' = lookup "creation date" m
74         comment'      = lookup "comment" m
75         createdBy'    = lookup "created by" m
76         encoding'     = lookup "encoding" m
77     in Right Metainfo {
78                info         = info'
79              , announceList = maybeToList (announce' >>= bstrToString)
80                               ++ getAnnounceList announceList'
81              , creationDate = bValToInteger =<< creationDate'
82              , comment      = bstrToString  =<< comment'
83              , createdBy    = bstrToString  =<< createdBy'
84              , encoding     = bstrToString  =<< encoding'
85              , infoHash     = hash . encode $ (m ! "info")
86              }
87 mkMetaInfo _ = Left "mkMetaInfo: expect an input dict"
88
89 getAnnounceList :: Maybe BVal -> [String]
90 getAnnounceList Nothing = []
91 getAnnounceList (Just (Bint _)) = []
92 getAnnounceList (Just (Bstr _)) = []
93 getAnnounceList (Just (Blist l)) = map (\s -> case s of
94                                                (Bstr s') ->  unpack s'
95                                                (Blist s') -> case s' of
96                                                               [Bstr s''] -> unpack s''
97                                                               _ -> ""
98                                                _ -> "") l
99 getAnnounceList (Just (Bdict _)) = []
100
101 torrentToMetainfo :: ByteString -> Either String Metainfo
102 torrentToMetainfo s =
103   case decode s of
104    Right d -> mkMetaInfo d
105    Left e -> Left $ show e