torrent-10000.0.0/0000755000000000000000000000000012445101431011666 5ustar0000000000000000torrent-10000.0.0/LICENSE0000644000000000000000000000302112445101431012667 0ustar0000000000000000Copyright (c) 2005-2007, David Himmelstrup All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of David Himmelstrup nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. torrent-10000.0.0/torrent.cabal0000644000000000000000000000114512445101431014350 0ustar0000000000000000Name: torrent Version: 10000.0.0 Cabal-Version: >= 1.6 Maintainer: Joey Hess Author: Lemmih Copyright: 2005-2007, Lemmih License-File: LICENSE License: BSD3 Build-Type: Simple Category: Network Extra-Source-Files: CHANGELOG Synopsis: BitTorrent file parser and generater Library GHC-Options: -Wall Hs-Source-Dirs: src Exposed-Modules: Data.Torrent Data.Torrent.Scrape Build-Depends: base >= 4.5, base < 5, binary, bencode >=0.2, filepath, containers, bytestring, syb source-repository head type: git location: git://git.kitenet.net/haskell-torrent.git torrent-10000.0.0/CHANGELOG0000644000000000000000000000070512445101431013102 0ustar0000000000000000haskell-torrent (10000.0.0) unstable; urgency=medium * Taking over upstream maintenance of this package. * Updated to build with the current haskell ecosystem. * Removed SHA1 implementation for simplicity, and removed iInfoHash from Torrent. * Use the PVP rather than date-based version. * Some data type changes, including using Integer rather than Int for file sizes. -- Joey Hess Thu, 18 Dec 2014 13:15:42 -0400 torrent-10000.0.0/Setup.hs0000644000000000000000000000005712445101431013324 0ustar0000000000000000import Distribution.Simple main = defaultMain torrent-10000.0.0/src/0000755000000000000000000000000012445101431012455 5ustar0000000000000000torrent-10000.0.0/src/Data/0000755000000000000000000000000012445101431013326 5ustar0000000000000000torrent-10000.0.0/src/Data/Torrent.hs0000644000000000000000000000610212445101431015316 0ustar0000000000000000{-# LANGUAGE DeriveDataTypeable #-} module Data.Torrent ( Torrent(..) , TorrentInfo(..) , TorrentFile(..) , readTorrent , serializeTorrent , torrentSize ) where import Data.BEncode import Data.BEncode.Parser import Data.Binary import Data.Generics import qualified Data.ByteString.Lazy as BS import Data.ByteString.Lazy (ByteString) import qualified Data.Map as Map data Torrent = Torrent { tAnnounce :: ByteString , tAnnounceList :: [ByteString] , tComment :: ByteString , tCreatedBy :: Maybe ByteString , tInfo :: TorrentInfo } deriving (Show, Read, Typeable, Data) data TorrentInfo = SingleFile { tLength :: Integer , tName :: ByteString , tPieceLength :: Integer , tPieces :: ByteString } | MultiFile { tFiles :: [TorrentFile] , tName :: ByteString , tPieceLength :: Integer , tPieces :: ByteString } deriving (Show, Read, Typeable, Data) data TorrentFile = TorrentFile { fileLength :: Integer , filePath :: [ByteString] } deriving (Show, Read, Typeable, Data) instance Binary Torrent where put = put . serializeTorrent get = do e <- get case readTorrent e of Left err -> fail $ "Failed to parse torrent: " ++ err Right t -> return t -- | Size of the files in the torrent. torrentSize :: Torrent -> Integer torrentSize torrent = case tInfo torrent of s@SingleFile{} -> tLength s MultiFile{tFiles=files} -> sum (map fileLength files) readTorrent :: ByteString -> Either String Torrent readTorrent inp = case bRead inp of Nothing -> Left "Not BEncoded" Just be -> runParser parseTorrent be parseTorrent :: BParser Torrent parseTorrent = do announce <- bbytestring $ dict "announce" creator <- optional $ bbytestring $ dict "created by" info <- dict "info" setInput info name <- bbytestring $ dict "name" pLen <- bint $ dict "piece length" pieces <- bbytestring $ dict "pieces" torrentInfo <- parseTorrentInfo name pLen pieces return $ Torrent announce [] BS.empty creator torrentInfo parseTorrentInfo :: ByteString -> Integer -> ByteString -> BParser TorrentInfo parseTorrentInfo name pLen pieces = single <|> multi where single = do len <- bint $ dict "length" return $ SingleFile len name pLen pieces multi = do files <- list "files" $ do len <- bint $ dict "length" filePaths <- list "path" $ bbytestring token return $ TorrentFile len filePaths return $ MultiFile files name pLen pieces serializeTorrent :: Torrent -> BEncode serializeTorrent torrent = BDict $ Map.fromList [ ("announce", BString $ tAnnounce torrent) , ("comment", BString $ tComment torrent) , ("info", info) ] where info = BDict $ Map.fromList $ [ ("name", BString $ tName (tInfo torrent)) , ("pieces", BString $ tPieces (tInfo torrent)) , ("piece length", BInt $ tPieceLength (tInfo torrent)) ] ++ case tInfo torrent of SingleFile len _ _ _ -> [ ("length", BInt len) ] MultiFile files _ _ _ -> [ ("files", BList $ map serfile files) ] serfile file = BDict $ Map.fromList [ ("length", BInt (fileLength file)) , ("path", BList (map BString $ filePath file)) ] torrent-10000.0.0/src/Data/Torrent/0000755000000000000000000000000012445101431014763 5ustar0000000000000000torrent-10000.0.0/src/Data/Torrent/Scrape.hs0000644000000000000000000000453212445101431016540 0ustar0000000000000000----------------------------------------------------------------------------- -- | -- Module : Data.Torrent.Scrape -- Copyright : (c) Lemmih 2005 -- License : BSD-like -- -- Maintainer : lemmih@gmail.com -- Stability : experimental -- Portability : portable -- -- ----------------------------------------------------------------------------- {-# LANGUAGE PatternGuards #-} module Data.Torrent.Scrape ( ScrapeInfo(..) , parseScrapeInfo , scrapeUrl ) where import Data.Char import Data.BEncode import qualified Data.ByteString.Lazy.Char8 as BS import Data.ByteString.Lazy (ByteString) import System.FilePath import qualified Data.Map as Map data ScrapeInfo = ScrapeInfo { scrapeSeeds :: Integer , scrapeLeechers :: Integer } deriving (Read,Show) parseScrapeInfo :: ByteString -> Maybe ScrapeInfo parseScrapeInfo bs = case bRead bs of Just (BDict dict) -> do BDict files <- Map.lookup "files" dict [BDict dict'] <- return (Map.elems files) BInt seeders <- Map.lookup "complete" dict' BInt peers <- Map.lookup "incomplete" dict' return $ ScrapeInfo { scrapeSeeds = seeders , scrapeLeechers = peers } _ -> Nothing scrapeUrl :: ByteString -> [String] -> Maybe String scrapeUrl _hash [] = Nothing scrapeUrl hash (announce:rs) = case splitFileName announce of (path,file_) | (file,ext) <- splitExtension file_ , ("announce",rest) <- break (=='?') file -> let info_hash = urlEncode (BS.unpack hash) file' = "scrape" ++ if null rest then "?info_hash="++info_hash else "&info_hash="++info_hash in Just (path file' <.> ext) _ -> scrapeUrl hash rs urlEncode :: String -> String urlEncode [] = [] urlEncode s = foldr worker [] s where worker c cs = if isReservedChar c then let (a, b) = ord c `divMod` 16 in '%' : intToDigit a : intToDigit b : cs else c : cs isReservedChar x = x < '0' || x > '9' && x < 'A' || x > 'Z' && x < 'a' || x > 'z'