module Main(main) where
import CarbonCopy.StorageInit
import CarbonCopy.MailHeaders
import CarbonCopy.HeadersStorage
import CarbonCopy.ThreadBuilder
import CarbonCopy.Configuration
import System
import System.Exit
import System.IO.HVFS
import System.FilePath.Posix
import Data.ByteString.Char8 as BStr
import Data.Maybe
import Control.Monad.IfElse
import Control.Monad
import Prelude as P
emptyStr = BStr.pack ""
data CCState = Ok | NotFound | NoChain deriving ( Enum )
data Opts = Opts { email, storageFileName :: String, storage :: Storage StrHeader }
main = do
opts <- prepareConfig
getArgs >>= processArgs opts
processArgs :: Opts -> [String] -> IO ()
processArgs opts args =
case args of
("init":folders) -> initPassedFolders folders
[] -> handlePassedEmail
_ -> usage
where
email' = email opts
storage' = storage opts
storageFileName' = storageFileName opts
initPassedFolders folders = do
let foldersLength = P.length folders
unlessM (fileExists storageFileName' ) $ BStr.writeFile storageFileName' emptyStr
mapM_ (initMailFolder storage' email' foldersLength ) $ P.zip folders [1..]
handlePassedEmail = BStr.getContents >>= handleEmail storage' email' >>= processCCState
prepareConfig :: IO Opts
prepareConfig = do
home <- getEnv "HOME"
let configFileName = home </> ".ccrc"
unlessM ( fileExists configFileName) $ error $ "Configuration file " ++ configFileName ++ " not found"
configuration <- fmap loadConfiguration $ BStr.readFile configFileName
let storageFileName = home </> ( fromJust . getPath $ configuration )
storage = fileStorage storageFileName
email = fromJust . getEmail $ configuration
return ( Opts email storageFileName storage )
usage :: IO ()
usage = do
progName <- getProgName
P.putStrLn $ "Usage " ++ progName ++ " [init maildir1 maildir2 maildir3 ...] [ < content ]"
P.putStrLn "\twhere 'init' will initialize header index with messages from given maildirs"
P.putStrLn "\twith no arguments it will read message from stdin and attempt to recognize headers within it"
P.putStrLn "\n\nExit codes:"
P.putStrLn "\t0\t- reply to known thread was found, header was added to the storage"
P.putStrLn "\t1\t- current email does not contain either e-mail address from configuration and is not a reply to a known thread"
P.putStrLn "\t2\t- no message headers were recognized"
processCCState :: CCState -> IO ()
processCCState state | stateCode == 0 = System.exitWith ExitSuccess
| otherwise = System.exitWith $ ExitFailure stateCode
where
stateCode = fromEnum state
fileExists :: FilePath -> IO Bool
fileExists = vDoesFileExist SystemFS
initMailFolder :: Storage StrHeader -> String -> Int -> (FilePath , Int) -> IO ()
initMailFolder storage email count (mailStorage, idx) = do
P.putStrLn $ "Processing storage " ++ show idx ++ " of " ++ show count ++ " at " ++ mailStorage
storageInit email mailStorage storage
handleEmail :: Storage StrHeader -> String -> ByteString -> IO CCState
handleEmail storage email content = handleEmail' chain
where ( chain, ownerEmail ) = matchFromHeader content email
handleEmail' (Just chain) = handleEmail'' ownerEmail
where
handleEmail'' True = do hdrAdd storage . current $ chain
System.exitWith ExitSuccess
handleEmail'' _ = do existsInStorage <- saveMatchingChain storage chain
if existsInStorage
then return Ok
else return NotFound
handleEmail' _ = return NoChain