module Autoproc.Procmail where
-- One thing to keep in mind:
-- Procmail seems to "just work" by running regular expressions over the
-- email and doing something.

-- The goal of this module is to capture the abstract syntax of procmail
-- and to output to the procmail syntax.

import Data.List (sort)

data PExp = PExp [RecipeFlag] [Condition] Action

data RecipeFlag = CheckHeader | CheckBody
     | CaseSensitive | Chain
     | ElseIf | PipeAsFilter | Copy
     | Wait | IgnoreErrors | RawWrite | NeedLock Bool deriving (Eq, Ord)

data Condition = Condition ConditionFlag String
data ConditionFlag = Normal | Invert | Eval | UseExitCode
     | LessThan | GreaterThan | Var String

{-

 There are two types of actions:

 1) delivering
 2) non-delivering

 The difference is that a delivering message stops execution of rules
 a non-delivering rule feeds a carbon-copy of the message to rule and
 then continues on trying rules.

-}

data Action = Forward [String] | Pipe String | File String
     | Nest [PExp]

--This is useful when used with the list monad
--to print each element of the list xs on a line by itself use:
-- xs >>= showLn
showLn :: (Show a) => a -> String
showLn = (++ "\n") . show

instance Show PExp where
         show (PExp fs cs a) = ":0"++showFlags fs++"\n"
                               ++(cs >>= (\x -> if show x == "" then ""
                                                else showLn x))
                               ++show a++"\n"
              where
              showFlags [NeedLock b] = show (NeedLock b)
              showFlags hs         = " " ++ ((show =<<) . sort) hs

instance Show RecipeFlag where
         show CheckHeader      = "H"
         show CheckBody        = "B"
         show CaseSensitive    = "D"
         show Chain            = "A"
         show ElseIf           = "E"
         show PipeAsFilter     = "f"
         show Copy             = "c"
         show Wait             = "w"
         show IgnoreErrors     = "i"
         show RawWrite         = "r"
         show (NeedLock True)  = ":"
         show (NeedLock False) = ""

instance Show Condition where
         show (Condition _ []) = ""
         show (Condition cf s)  = "* " ++ show cf ++ s

instance Show ConditionFlag where
         show Normal      = ""
         show Invert      = "!"
         show Eval        = "$"
         show UseExitCode = "?"
         show LessThan    = "<"
         show GreaterThan = ">"
         show (Var s)     = s++" ?? "

instance Show Action where
         show (Nest es)    = "{ \n"++(es >>= showLn)++"}"
         show (File s)     = s
         show (Forward es) = "! "++(es >>= (++ " "))
         show (Pipe s)     = "| "++s


{-
Here is a test case to try:
PExp [] [(Condition Normal "^From.*peter"), (Condition Normal "^Subject:.*compilers")] (Nest [PExp [Copy] [] (Forward "william@somewhere.edu"), PExp [] [] (File "petcompil")])

It should generate output equivalent to:
:0
* ^From.*peter
* ^Subject:.*compilers
  {
    :0 c
    ! william@somewhere.edu

    :0
    petcompil
  }

-}