-- Types.hs: OpenPGP (RFC4880) data types
-- Copyright Ⓒ 2012  Clint Adams
-- This software is released under the terms of the Expat (MIT) license.
-- (See the LICENSE file).

module Codec.Encryption.OpenPGP.Types (
   SigSubPacket(..)
 , CompressionAlgorithm(..)
 , HashAlgorithm(..)
 , PubKeyAlgorithm(..)
 , SymmetricAlgorithm(..)
 , MPI(MPI)
 , Packet(..)
 , S2K(..)
 , SignaturePayload(..)
 , UserAttrSubPacket(..)
 , SigType(..)
 , ImageHeader(..)
 , ImageFormat(..)
 , PKPayload(..)
 , SKAddendum(..)
 , EightOctetKeyId
 , SessionKey
 , FutureFlag
 , FutureVal
 , fromFVal
 , fromFFlag
 , toFVal
 , toFFlag
) where

import Data.ByteString (ByteString)
import Data.Set (Set)
import Data.Word (Word8, Word16, Word32)

type TimeStamp = Word32
type Exportability = Bool
type TrustLevel = Word8
type TrustAmount = Word8
type AlmostPublicDomainRegex = ByteString
type Revocability = Bool
type RevocationReason = ByteString
type TwentyOctetFingerprint = ByteString
type EightOctetKeyId = ByteString
type KeyServer = ByteString
type URL = ByteString
type NotationName = ByteString
type NotationValue = ByteString
type UserId = ByteString
type SignaturePacketBody = ByteString
type SignatureHash = ByteString
type PacketVersion = Word8
type SessionKey = ByteString
type Salt = ByteString
type Count = Int
type V3Expiration = Word16
type CompressedDataPayload = ByteString
type FileName = ByteString
type ImageData = ByteString
type NestedFlag = Bool
type IV = ByteString

data SymmetricAlgorithm = Plaintext
                        | IDEA
                        | TripleDES
                        | CAST5
                        | Blowfish
                        | ReservedSAFER
                        | ReservedDES
                        | AES128
                        | AES192
                        | AES256
                        | Twofish
                        | OtherSA Word8
     deriving (Show)

instance Eq SymmetricAlgorithm where
    (==) a b = fromFVal a == fromFVal b

instance Ord SymmetricAlgorithm where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal SymmetricAlgorithm where
    fromFVal Plaintext = 0
    fromFVal IDEA = 1
    fromFVal TripleDES = 2
    fromFVal CAST5 = 3
    fromFVal Blowfish = 4
    fromFVal AES128 = 7
    fromFVal AES192 = 8
    fromFVal AES256 = 9
    fromFVal Twofish = 10
    fromFVal (OtherSA o) = o
    toFVal 0 = Plaintext
    toFVal 1 = IDEA
    toFVal 2 = TripleDES
    toFVal 3 = CAST5
    toFVal 4 = Blowfish
    toFVal 7 = AES128
    toFVal 8 = AES192
    toFVal 9 = AES256
    toFVal 10 = Twofish
    toFVal o = OtherSA o

data NotationFlag = HumanReadable
                  | OtherNF Int
     deriving (Show)

instance Eq NotationFlag where
    (==) a b = fromFFlag a == fromFFlag b

instance Ord NotationFlag where
    compare a b = fromFFlag a `compare` fromFFlag b

instance FutureFlag NotationFlag where
    fromFFlag HumanReadable = 0
    fromFFlag (OtherNF o) = fromIntegral o

    toFFlag 0 = HumanReadable
    toFFlag o = OtherNF (fromIntegral o)

data SigSubPacket = SigCreationTime Bool TimeStamp
                  | SigExpirationTime Bool TimeStamp
                  | ExportableCertification Bool Exportability
                  | TrustSignature Bool TrustLevel TrustAmount
                  | RegularExpression Bool AlmostPublicDomainRegex
                  | Revocable Bool Revocability
                  | KeyExpirationTime Bool TimeStamp
                  | PreferredSymmetricAlgorithms Bool [SymmetricAlgorithm]
                  | RevocationKey Bool (Set RevocationClass) PubKeyAlgorithm TwentyOctetFingerprint
                  | Issuer Bool EightOctetKeyId
                  | NotationData Bool (Set NotationFlag) NotationName NotationValue
                  | PreferredHashAlgorithms Bool [HashAlgorithm]
                  | PreferredCompressionAlgorithms Bool [CompressionAlgorithm]
                  | KeyServerPreferences Bool (Set KSPFlag)
                  | PreferredKeyServer Bool KeyServer
                  | PrimaryUserId Bool Bool
                  | PolicyURL Bool URL
                  | KeyFlags Bool (Set KeyFlag)
                  | SignersUserId Bool UserId
                  | ReasonForRevocation Bool RevocationCode RevocationReason
                  | Features Bool (Set FeatureFlag)
                  | SignatureTarget Bool PubKeyAlgorithm HashAlgorithm SignatureHash
                  | EmbeddedSignature Bool SignaturePacketBody
                  | UserDefinedSigSub Bool Word8 ByteString
                  | OtherSigSub Bool Word8 ByteString
    deriving (Show, Eq) -- FIXME

data HashAlgorithm = DeprecatedMD5
                   | SHA1
                   | RIPEMD160
                   | SHA256
                   | SHA384
                   | SHA512
                   | SHA224
                   | OtherHA Word8
    deriving (Show)

instance Eq HashAlgorithm where
    (==) a b = fromFVal a == fromFVal b

instance Ord HashAlgorithm where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal HashAlgorithm where
    fromFVal DeprecatedMD5 = 1
    fromFVal SHA1 = 2
    fromFVal RIPEMD160 = 3
    fromFVal SHA256 = 8
    fromFVal SHA384 = 9
    fromFVal SHA512 = 10
    fromFVal SHA224 = 11
    fromFVal (OtherHA o) = o
    toFVal 1 = DeprecatedMD5
    toFVal 2 = SHA1
    toFVal 3 = RIPEMD160
    toFVal 8 = SHA256
    toFVal 9 = SHA384
    toFVal 10 = SHA512
    toFVal 11 = SHA224
    toFVal o = OtherHA o

data CompressionAlgorithm = Uncompressed
                          | ZIP
                          | ZLIB
                          | BZip2
                          | OtherCA Word8
    deriving (Show)

instance Eq CompressionAlgorithm where
    (==) a b = fromFVal a == fromFVal b

instance Ord CompressionAlgorithm where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal CompressionAlgorithm where
    fromFVal Uncompressed = 0
    fromFVal ZIP = 1
    fromFVal ZLIB = 2
    fromFVal BZip2 = 3
    fromFVal (OtherCA o) = o
    toFVal 0 = Uncompressed
    toFVal 1 = ZIP
    toFVal 2 = ZLIB
    toFVal 3 = BZip2
    toFVal o = OtherCA o

class (Eq a, Ord a) => FutureVal a where
   fromFVal :: a -> Word8
   toFVal :: Word8 -> a

data PubKeyAlgorithm = RSA
                     | RSAEncryptOnly
                     | RSASignOnly
                     | ElgamalEncryptOnly
                     | DSA
                     | EC
                     | ECDSA
                     | Elgamal
                     | DH
                     | OtherPKA Word8
    deriving (Show)

instance Eq PubKeyAlgorithm where
    (==) a b = fromFVal a == fromFVal b

instance Ord PubKeyAlgorithm where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal PubKeyAlgorithm where
    fromFVal RSA = 1
    fromFVal RSAEncryptOnly = 2
    fromFVal RSASignOnly = 3
    fromFVal ElgamalEncryptOnly = 16
    fromFVal DSA = 17
    fromFVal EC = 18
    fromFVal ECDSA = 19
    fromFVal Elgamal = 20
    fromFVal DH = 21
    fromFVal (OtherPKA o) = o
    toFVal 1 = RSA
    toFVal 2 = RSAEncryptOnly
    toFVal 3 = RSASignOnly
    toFVal 16 = ElgamalEncryptOnly
    toFVal 17 = DSA
    toFVal 18 = EC
    toFVal 19 = ECDSA
    toFVal 20 = Elgamal
    toFVal 21 = DH
    toFVal o = OtherPKA o

class (Eq a, Ord a) => FutureFlag a where
    fromFFlag :: Integral b => a -> b
    toFFlag :: Integral b => b-> a

data KSPFlag = NoModify
             | KSPOther Int
    deriving (Show)

instance Eq KSPFlag where
    (==) a b = fromFFlag a == fromFFlag b

instance Ord KSPFlag where
    compare a b = fromFFlag a `compare` fromFFlag b

instance FutureFlag KSPFlag where
    fromFFlag NoModify = 0
    fromFFlag (KSPOther i) = fromIntegral i

    toFFlag 0 = NoModify
    toFFlag i = KSPOther (fromIntegral i)

data KeyFlag = GroupKey
             | AuthKey
             | SplitKey
             | EncryptStorageKey
             | EncryptCommunicationsKey
             | SignDataKey
             | CertifyKeysKey
             | KFOther Int
    deriving (Show)

instance Eq KeyFlag where
    (==) a b = fromFFlag a == fromFFlag b

instance Ord KeyFlag where
    compare a b = fromFFlag a `compare` fromFFlag b

instance FutureFlag KeyFlag where
    fromFFlag GroupKey = 0
    fromFFlag AuthKey = 2
    fromFFlag SplitKey = 3
    fromFFlag EncryptStorageKey = 4
    fromFFlag EncryptCommunicationsKey = 5
    fromFFlag SignDataKey = 6
    fromFFlag CertifyKeysKey = 7
    fromFFlag (KFOther i) = fromIntegral i

    toFFlag 0 = GroupKey
    toFFlag 2 = AuthKey
    toFFlag 3 = SplitKey
    toFFlag 4 = EncryptStorageKey
    toFFlag 5 = EncryptCommunicationsKey
    toFFlag 6 = SignDataKey
    toFFlag 7 = CertifyKeysKey
    toFFlag i = KFOther (fromIntegral i)

data RevocationClass = SensitiveRK
                     | RClOther Int
    deriving (Show)

instance Eq RevocationClass where
    (==) a b = fromFFlag a == fromFFlag b

instance Ord RevocationClass where
    compare a b = fromFFlag a `compare` fromFFlag b

instance FutureFlag RevocationClass where
    fromFFlag SensitiveRK = 1
    fromFFlag (RClOther i) = fromIntegral i

    toFFlag 1 = SensitiveRK
    toFFlag i = RClOther (fromIntegral i)

data RevocationCode = NoReason
                    | KeySuperseded
                    | KeyMaterialCompromised
                    | KeyRetiredAndNoLongerUsed
                    | UserIdInfoNoLongerValid
                    | RCoOther Word8
    deriving (Show)

instance Eq RevocationCode where
    (==) a b = fromFVal a == fromFVal b

instance Ord RevocationCode where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal RevocationCode where
    fromFVal NoReason = 0
    fromFVal KeySuperseded = 1
    fromFVal KeyMaterialCompromised = 2
    fromFVal KeyRetiredAndNoLongerUsed = 3
    fromFVal UserIdInfoNoLongerValid = 32
    fromFVal (RCoOther o) = o
    toFVal 0 = NoReason
    toFVal 1 = KeySuperseded
    toFVal 2 = KeyMaterialCompromised
    toFVal 3 = KeyRetiredAndNoLongerUsed
    toFVal 32 = UserIdInfoNoLongerValid
    toFVal o = RCoOther o

data FeatureFlag = ModificationDetection
                 | FeatureOther Int
    deriving (Show)

instance Eq FeatureFlag where
    (==) a b = fromFFlag a == fromFFlag b

instance Ord FeatureFlag where
    compare a b = fromFFlag a `compare` fromFFlag b

instance FutureFlag FeatureFlag where
    fromFFlag ModificationDetection = 7
    fromFFlag (FeatureOther i) = fromIntegral i

    toFFlag 7 = ModificationDetection
    toFFlag i = FeatureOther (fromIntegral i)

data MPI = MPI ByteString
    deriving (Show, Eq)

data SignaturePayload = SigV3 SigType Word32 EightOctetKeyId PubKeyAlgorithm HashAlgorithm Word16 [MPI]
                      | SigV4 SigType PubKeyAlgorithm HashAlgorithm [SigSubPacket] [SigSubPacket] Word16 [MPI]
                      | SigVOther Word8 ByteString
    deriving (Show, Eq) -- FIXME

data PKPayload = PubV3 TimeStamp V3Expiration PubKeyAlgorithm [MPI]
               | PubV4 TimeStamp PubKeyAlgorithm [MPI]
    deriving (Show, Eq)

data SKAddendum = SUS16bit SymmetricAlgorithm S2K IV ByteString
                | SUSSHA1 SymmetricAlgorithm S2K IV ByteString
                | SUSym SymmetricAlgorithm IV ByteString
                | SUUnencrypted [MPI] Word16
    deriving (Show, Eq)

data DataType = BinaryData
              | TextData
              | UTF8Data
              | OtherData Word8
    deriving (Show)

instance Eq DataType where
    (==) a b = fromFVal a == fromFVal b

instance Ord DataType where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal DataType where
    fromFVal BinaryData = fromIntegral . fromEnum $ 'b'
    fromFVal TextData = fromIntegral . fromEnum $ 't'
    fromFVal UTF8Data = fromIntegral . fromEnum $ 'u'
    fromFVal (OtherData o) = o

    toFVal 0x62 = BinaryData
    toFVal 0x74 = TextData
    toFVal 0x75 = UTF8Data
    toFVal o = OtherData o

data Packet = PKESK PacketVersion EightOctetKeyId PubKeyAlgorithm SessionKey
            | Signature SignaturePayload
            | SKESK PacketVersion SymmetricAlgorithm S2K (Maybe SessionKey)
            | OnePassSignature PacketVersion SigType HashAlgorithm PubKeyAlgorithm EightOctetKeyId NestedFlag
            | SecretKey PKPayload SKAddendum
            | PublicKey PKPayload
            | SecretSubkey PKPayload SKAddendum
            | CompressedData CompressionAlgorithm CompressedDataPayload
            | SymEncData ByteString
            | Marker ByteString
            | LiteralData DataType FileName TimeStamp ByteString
            | Trust ByteString
            | UserId String
            | PublicSubkey PKPayload
            | UserAttribute [UserAttrSubPacket]
            | SymEncIntegrityProtectedData PacketVersion ByteString
            | ModificationDetectionCode ByteString
            | OtherPacket Word8 ByteString
    deriving (Show, Eq) -- FIXME

data S2K = Simple HashAlgorithm
         | Salted HashAlgorithm Salt
         | IteratedSalted HashAlgorithm Salt Count
         | OtherS2K Word8 ByteString
    deriving (Show, Eq) -- FIXME

data UserAttrSubPacket = ImageAttribute ImageHeader ImageData
                       | OtherUASub Word8 ByteString
    deriving (Show, Eq) -- FIXME

data ImageHeader = ImageHV1 ImageFormat
    deriving (Show, Eq)

data ImageFormat = JPEG
                 | OtherImage Word8
    deriving (Show)

instance Eq ImageFormat where
    (==) a b = fromFVal a == fromFVal b

instance Ord ImageFormat where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal ImageFormat where
    fromFVal JPEG = 1
    fromFVal (OtherImage o) = o

    toFVal 1 = JPEG
    toFVal o = OtherImage o

data SigType = BinarySig
             | CanonicalTextSig
             | StandaloneSig
             | GenericCert
             | PersonaCert
             | CasualCert
             | PositiveCert
             | SubkeyBindingSig
             | PrimaryKeyBindingSig
             | SignatureDirectlyOnAKey
             | KeyRevocationSig
             | SubkeyRevocationSig
             | CertRevocationSig
             | TimestampSig
             | ThirdPartyConfirmationSig
             | OtherSig Word8
    deriving (Show)

instance Eq SigType where
    (==) a b = fromFVal a == fromFVal b

instance Ord SigType where
    compare a b = fromFVal a `compare` fromFVal b

instance FutureVal SigType where
    fromFVal BinarySig = 0x00
    fromFVal CanonicalTextSig = 0x01
    fromFVal StandaloneSig = 0x02
    fromFVal GenericCert = 0x10
    fromFVal PersonaCert = 0x11
    fromFVal CasualCert = 0x12
    fromFVal PositiveCert = 0x13
    fromFVal SubkeyBindingSig = 0x18
    fromFVal PrimaryKeyBindingSig = 0x19
    fromFVal SignatureDirectlyOnAKey = 0x1F
    fromFVal KeyRevocationSig = 0x20
    fromFVal SubkeyRevocationSig = 0x28
    fromFVal CertRevocationSig = 0x30
    fromFVal TimestampSig = 0x40
    fromFVal ThirdPartyConfirmationSig = 0x50
    fromFVal (OtherSig o) = o

    toFVal 0x00 = BinarySig
    toFVal 0x01 = CanonicalTextSig
    toFVal 0x02 = StandaloneSig
    toFVal 0x10 = GenericCert
    toFVal 0x11 = PersonaCert
    toFVal 0x12 = CasualCert
    toFVal 0x13 = PositiveCert
    toFVal 0x18 = SubkeyBindingSig
    toFVal 0x19 = PrimaryKeyBindingSig
    toFVal 0x1F = SignatureDirectlyOnAKey
    toFVal 0x20 = KeyRevocationSig
    toFVal 0x28 = SubkeyRevocationSig
    toFVal 0x30 = CertRevocationSig
    toFVal 0x40 = TimestampSig
    toFVal 0x50 = ThirdPartyConfirmationSig
    toFVal o = OtherSig o