-- PacketClass.hs: OpenPGP (RFC9580) data types
-- Copyright © 2012-2026  Clint Adams
-- This software is released under the terms of the Expat license.
-- (See the LICENSE file).
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

module Codec.Encryption.OpenPGP.Types.Internal.PacketClass where

import Control.Lens (makeLenses)
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL
import Data.Data (Data)
import qualified Data.Kind
import Data.List.NonEmpty (NonEmpty)
import Data.Text (Text)
import Data.Typeable (Typeable)
import Data.Word (Word8)
import Prettyprinter (Pretty (..))

import Codec.Encryption.OpenPGP.Types.Internal.Base
import Codec.Encryption.OpenPGP.Types.Internal.PKITypes
import Codec.Encryption.OpenPGP.Types.Internal.Pkt

class Packet a where
    data PacketType a :: Data.Kind.Type
    packetType :: a -> PacketType a
    packetCode :: PacketType a -> Word8
    dynamicPacketCode :: a -> Word8
    toPkt :: a -> Pkt
    fromPktMaybe :: Pkt -> Maybe a
    fromPktEither :: Pkt -> Either String a

    fromPktMaybe = either (const Nothing) Just . fromPktEither
    dynamicPacketCode = packetCode . packetType

coercionError :: String -> Pkt -> Either String a
coercionError expected pkt =
    Left
        ( "Cannot coerce non-"
            ++ expected
            ++ " packet (tag "
            ++ show (pktTag pkt)
            ++ ")"
        )

data PKESK (v :: PKESKPayloadVersion) where
    PKESK3Packet
        :: PacketVersion
        -> EightOctetKeyId
        -> PubKeyAlgorithm
        -> NonEmpty MPI
        -> PKESK 'PKESKV3
    PKESK6Packet
        :: BL.ByteString
        -> PubKeyAlgorithm
        -> BL.ByteString
        -> PKESK 'PKESKV6

deriving instance Eq (PKESK v)
deriving instance Show (PKESK v)

instance Packet (PKESK 'PKESKV3) where
    data PacketType (PKESK 'PKESKV3) = PKESKType
        deriving (Eq, Show)
    packetType _ = PKESKType
    packetCode _ = 1
    toPkt (PKESK3Packet version keyid pka mpis) =
        PKESKPkt
            (PKESKPayloadV3Packet (PKESKPayloadV3 version keyid pka mpis))
    fromPktEither (PKESKPkt (PKESKPayloadV3Packet (PKESKPayloadV3 _ keyid pka mpis))) =
        Right (PKESK3Packet 3 keyid pka mpis)
    fromPktEither (PKESKPkt (PKESKPayloadV6Packet (PKESKPayloadV6 _ _ _))) =
        Left "Cannot coerce PKESKv6 packet to PKESKv3"
    fromPktEither pkt = coercionError "PKESK" pkt

instance Pretty (PKESK 'PKESKV3) where
    pretty = pretty . toPkt

instance Packet (PKESK 'PKESKV6) where
    data PacketType (PKESK 'PKESKV6) = PKESK6Type
        deriving (Eq, Show)
    packetType _ = PKESK6Type
    packetCode _ = 1
    toPkt (PKESK6Packet recipientKeyIdentifier pka esk) =
        PKESKPkt
            ( PKESKPayloadV6Packet
                (PKESKPayloadV6 recipientKeyIdentifier pka esk)
            )
    fromPktEither
        ( PKESKPkt
                ( PKESKPayloadV6Packet
                        (PKESKPayloadV6 recipientKeyIdentifier pka esk)
                    )
            ) =
            Right (PKESK6Packet recipientKeyIdentifier pka esk)
    fromPktEither (PKESKPkt (PKESKPayloadV3Packet (PKESKPayloadV3 _ _ _ _))) =
        Left "Cannot coerce PKESKv3 packet to PKESKv6"
    fromPktEither pkt = coercionError "PKESKv6" pkt

instance Pretty (PKESK 'PKESKV6) where
    pretty = pretty . toPkt

newtype Signature
    = Signature
    { _signaturePayload :: SignaturePayload
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet Signature where
    data PacketType Signature = SignatureType
        deriving (Eq, Show)
    packetType _ = SignatureType
    packetCode _ = 2
    toPkt (Signature a) = SignaturePkt a
    fromPktMaybe (SignaturePkt a) = Just (Signature a)
    fromPktMaybe _ = Nothing
    fromPktEither (SignaturePkt a) = Right (Signature a)
    fromPktEither pkt = coercionError "Signature" pkt

instance Pretty Signature where
    pretty = pretty . toPkt

data SignatureV (v :: SignaturePayloadVersion) where
    SignatureV3Packet
        :: SignaturePayloadV 'SigPayloadV3 -> SignatureV 'SigPayloadV3
    SignatureV4Packet
        :: SignaturePayloadV 'SigPayloadV4 -> SignatureV 'SigPayloadV4
    SignatureV6Packet
        :: SignaturePayloadV 'SigPayloadV6 -> SignatureV 'SigPayloadV6
    SignatureVOtherPacket
        :: SignaturePayloadV 'SigPayloadVOther
        -> SignatureV 'SigPayloadVOther

deriving instance Eq (SignatureV v)
deriving instance Show (SignatureV v)

data SomeSignatureV where
    SomeSignatureV :: SignatureV v -> SomeSignatureV

signaturePayloadFromSignatureV
    :: SignatureV v -> SignaturePayload
signaturePayloadFromSignatureV (SignatureV3Packet payload) = toSignaturePayload payload
signaturePayloadFromSignatureV (SignatureV4Packet payload) = toSignaturePayload payload
signaturePayloadFromSignatureV (SignatureV6Packet payload) = toSignaturePayload payload
signaturePayloadFromSignatureV (SignatureVOtherPacket payload) = toSignaturePayload payload

fromPktEitherSomeSignatureV
    :: Pkt -> Either String SomeSignatureV
fromPktEitherSomeSignatureV (SignaturePkt payload) =
    Right (someSignatureVFromPayload payload)
fromPktEitherSomeSignatureV pkt =
    coercionError "Signature" pkt

someSignatureVFromPayload :: SignaturePayload -> SomeSignatureV
someSignatureVFromPayload payload =
    case toSomeSignaturePayload payload of
        SomeSignaturePayload (typedPayload@SigPayloadV3Data {}) ->
            SomeSignatureV (SignatureV3Packet typedPayload)
        SomeSignaturePayload (typedPayload@SigPayloadV4Data {}) ->
            SomeSignatureV (SignatureV4Packet typedPayload)
        SomeSignaturePayload (typedPayload@SigPayloadV6Data {}) ->
            SomeSignatureV (SignatureV6Packet typedPayload)
        SomeSignaturePayload (typedPayload@SigPayloadOtherData {}) ->
            SomeSignatureV (SignatureVOtherPacket typedPayload)

instance Packet (SignatureV 'SigPayloadV3) where
    data PacketType (SignatureV 'SigPayloadV3) = SignatureV3Type
        deriving (Eq, Show)
    packetType _ = SignatureV3Type
    packetCode _ = 2
    toPkt = SignaturePkt . signaturePayloadFromSignatureV
    fromPktEither (SignaturePkt payload) =
        SignatureV3Packet <$> asSignaturePayloadV3 payload
    fromPktEither pkt = coercionError "SignatureV3" pkt

instance Pretty (SignatureV 'SigPayloadV3) where
    pretty = pretty . toPkt

instance Packet (SignatureV 'SigPayloadV4) where
    data PacketType (SignatureV 'SigPayloadV4) = SignatureV4Type
        deriving (Eq, Show)
    packetType _ = SignatureV4Type
    packetCode _ = 2
    toPkt = SignaturePkt . signaturePayloadFromSignatureV
    fromPktEither (SignaturePkt payload) =
        SignatureV4Packet <$> asSignaturePayloadV4 payload
    fromPktEither pkt = coercionError "SignatureV4" pkt

instance Pretty (SignatureV 'SigPayloadV4) where
    pretty = pretty . toPkt

instance Packet (SignatureV 'SigPayloadV6) where
    data PacketType (SignatureV 'SigPayloadV6) = SignatureV6Type
        deriving (Eq, Show)
    packetType _ = SignatureV6Type
    packetCode _ = 2
    toPkt = SignaturePkt . signaturePayloadFromSignatureV
    fromPktEither (SignaturePkt payload) =
        SignatureV6Packet <$> asSignaturePayloadV6 payload
    fromPktEither pkt = coercionError "SignatureV6" pkt

instance Pretty (SignatureV 'SigPayloadV6) where
    pretty = pretty . toPkt

instance Packet (SignatureV 'SigPayloadVOther) where
    data PacketType (SignatureV 'SigPayloadVOther) = SignatureVOtherType
        deriving (Eq, Show)
    packetType _ = SignatureVOtherType
    packetCode _ = 2
    toPkt = SignaturePkt . signaturePayloadFromSignatureV
    fromPktEither (SignaturePkt payload) =
        SignatureVOtherPacket <$> asSignaturePayloadOther payload
    fromPktEither pkt = coercionError "SignatureVOther" pkt

instance Pretty (SignatureV 'SigPayloadVOther) where
    pretty = pretty . toPkt

data SKESK (v :: SKESKPayloadVersion) where
    SKESK4Packet
        :: SymmetricAlgorithm
        -> S2K
        -> Maybe BL.ByteString
        -> SKESK 'SKESKV4
    SKESK6Packet
        :: SymmetricAlgorithm
        -> AEADAlgorithm
        -> S2K
        -> BL.ByteString
        -> BL.ByteString
        -> BL.ByteString
        -> SKESK 'SKESKV6

deriving instance Eq (SKESK v)
deriving instance Show (SKESK v)

instance Packet (SKESK 'SKESKV4) where
    data PacketType (SKESK 'SKESKV4) = SKESKType
        deriving (Eq, Show)
    packetType _ = SKESKType
    packetCode _ = 3
    toPkt (SKESK4Packet symalgo s2k esk) =
        SKESKPkt (SKESKPayloadV4Packet (SKESKPayloadV4 symalgo s2k esk))
    fromPktEither (SKESKPkt (SKESKPayloadV4Packet (SKESKPayloadV4 symalgo s2k esk))) =
        Right (SKESK4Packet symalgo s2k esk)
    fromPktEither (SKESKPkt (SKESKPayloadV6Packet (SKESKPayloadV6 _ _ _ _ _ _))) =
        Left "Cannot coerce SKESKv6 packet to SKESKv4"
    fromPktEither pkt = coercionError "SKESK" pkt

instance Pretty (SKESK 'SKESKV4) where
    pretty = pretty . toPkt

instance Packet (SKESK 'SKESKV6) where
    data PacketType (SKESK 'SKESKV6) = SKESK6Type
        deriving (Eq, Show)
    packetType _ = SKESK6Type
    packetCode _ = 3
    toPkt (SKESK6Packet symalgo aead s2k iv esk tag) =
        SKESKPkt
            (SKESKPayloadV6Packet (SKESKPayloadV6 symalgo aead s2k iv esk tag))
    fromPktEither
        ( SKESKPkt
                (SKESKPayloadV6Packet (SKESKPayloadV6 symalgo aead s2k iv esk tag))
            ) =
            Right (SKESK6Packet symalgo aead s2k iv esk tag)
    fromPktEither (SKESKPkt (SKESKPayloadV4Packet (SKESKPayloadV4 _ _ _))) =
        Left "Cannot coerce SKESKv4 packet to SKESKv6"
    fromPktEither pkt = coercionError "SKESKv6" pkt

instance Pretty (SKESK 'SKESKV6) where
    pretty = pretty . toPkt

data OnePassSignature (v :: OnePassSignatureVersion) where
    OnePassSignatureV3Packet
        :: PacketVersion
        -> SigType
        -> HashAlgorithm
        -> PubKeyAlgorithm
        -> EightOctetKeyId
        -> NestedFlag
        -> OnePassSignature 'OPSV3
    OnePassSignatureV6Packet
        :: SigType
        -> HashAlgorithm
        -> PubKeyAlgorithm
        -> SignatureSalt
        -> ByteString
        -> NestedFlag
        -> OnePassSignature 'OPSV6

deriving instance Eq (OnePassSignature v)
deriving instance Show (OnePassSignature v)

instance Packet (OnePassSignature 'OPSV3) where
    data PacketType (OnePassSignature 'OPSV3) = OnePassSignatureType
        deriving (Eq, Show)
    packetType _ = OnePassSignatureType
    packetCode _ = 4
    toPkt (OnePassSignatureV3Packet a b c d e f) =
        OnePassSignaturePkt
            (OPSPayloadV3Packet (OPSPayloadV3 a b c d e f))
    fromPktEither
        ( OnePassSignaturePkt
                (OPSPayloadV3Packet (OPSPayloadV3 a b c d e f))
            ) =
            Right (OnePassSignatureV3Packet a b c d e f)
    fromPktEither pkt = coercionError "OnePassSignature" pkt

instance Pretty (OnePassSignature 'OPSV3) where
    pretty = pretty . toPkt

instance Packet (OnePassSignature 'OPSV6) where
    data PacketType (OnePassSignature 'OPSV6) = OnePassSignatureV6Type
        deriving (Eq, Show)
    packetType _ = OnePassSignatureV6Type
    packetCode _ = 4
    toPkt (OnePassSignatureV6Packet a b c d e f) =
        OnePassSignaturePkt
            (OPSPayloadV6Packet (OPSPayloadV6 a b c d e f))
    fromPktEither
        ( OnePassSignaturePkt
                (OPSPayloadV6Packet (OPSPayloadV6 a b c d e f))
            ) =
            Right (OnePassSignatureV6Packet a b c d e f)
    fromPktEither pkt = coercionError "OnePassSignatureV6" pkt

instance Pretty (OnePassSignature 'OPSV6) where
    pretty = pretty . toPkt

data SecretKey
    = SecretKey
    { _secretKeyPKPayload :: SomePKPayload
    , _secretKeySKAddendum :: SKAddendum
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet SecretKey where
    data PacketType SecretKey = SecretKeyType
        deriving (Eq, Show)
    packetType _ = SecretKeyType
    packetCode _ = 5
    toPkt (SecretKey a b) = SecretKeyPkt a b
    fromPktEither (SecretKeyPkt a b) = Right (SecretKey a b)
    fromPktEither pkt = coercionError "SecretKey" pkt

instance Pretty SecretKey where
    pretty = pretty . toPkt

newtype PublicKey
    = PublicKey
    { _publicKeyPKPayload :: SomePKPayload
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet PublicKey where
    data PacketType PublicKey = PublicKeyType
        deriving (Eq, Show)
    packetType _ = PublicKeyType
    packetCode _ = 6
    toPkt (PublicKey a) = PublicKeyPkt a
    fromPktEither (PublicKeyPkt a) = Right (PublicKey a)
    fromPktEither pkt = coercionError "PublicKey" pkt

instance Pretty PublicKey where
    pretty = pretty . toPkt

data SecretSubkey
    = SecretSubkey
    { _secretSubkeyPKPayload :: SomePKPayload
    , _secretSubkeySKAddendum :: SKAddendum
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet SecretSubkey where
    data PacketType SecretSubkey = SecretSubkeyType
        deriving (Eq, Show)
    packetType _ = SecretSubkeyType
    packetCode _ = 7
    toPkt (SecretSubkey a b) = SecretSubkeyPkt a b
    fromPktEither (SecretSubkeyPkt a b) = Right (SecretSubkey a b)
    fromPktEither pkt = coercionError "SecretSubkey" pkt

instance Pretty SecretSubkey where
    pretty = pretty . toPkt

data CompressedData
    = CompressedData
    { _compressedDataCompressionAlgorithm :: CompressionAlgorithm
    , _compressedDataPayload :: CompressedDataPayload
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet CompressedData where
    data PacketType CompressedData = CompressedDataType
        deriving (Eq, Show)
    packetType _ = CompressedDataType
    packetCode _ = 8
    toPkt (CompressedData a b) = CompressedDataPkt a b
    fromPktEither (CompressedDataPkt a b) = Right (CompressedData a b)
    fromPktEither pkt = coercionError "CompressedData" pkt

instance Pretty CompressedData where
    pretty = pretty . toPkt

newtype SymEncData
    = SymEncData
    { _symEncDataPayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet SymEncData where
    data PacketType SymEncData = SymEncDataType
        deriving (Eq, Show)
    packetType _ = SymEncDataType
    packetCode _ = 9
    toPkt (SymEncData a) = SymEncDataPkt a
    fromPktEither (SymEncDataPkt a) = Right (SymEncData a)
    fromPktEither pkt = coercionError "SymEncData" pkt

instance Pretty SymEncData where
    pretty = pretty . toPkt

newtype Marker
    = Marker
    { _markerPayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet Marker where
    data PacketType Marker = MarkerType
        deriving (Eq, Show)
    packetType _ = MarkerType
    packetCode _ = 10
    toPkt (Marker a) = MarkerPkt a
    fromPktEither (MarkerPkt a) = Right (Marker a)
    fromPktEither pkt = coercionError "Marker" pkt

instance Pretty Marker where
    pretty = pretty . toPkt

data LiteralData
    = LiteralData
    { _literalDataDataType :: LiteralDataType
    , _literalDataFileName :: FileName
    , _literalDataTimeStamp :: ThirtyTwoBitTimeStamp
    , _literalDataPayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet LiteralData where
    data PacketType LiteralData = LiteralDataType
        deriving (Eq, Show)
    packetType _ = LiteralDataType
    packetCode _ = 11
    toPkt (LiteralData a b c d) = LiteralDataPkt a b c d
    fromPktEither (LiteralDataPkt a b c d) = Right (LiteralData a b c d)
    fromPktEither pkt = coercionError "LiteralData" pkt

instance Pretty LiteralData where
    pretty = pretty . toPkt

newtype Trust
    = Trust
    { _trustPayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet Trust where
    data PacketType Trust = TrustType
        deriving (Eq, Show)
    packetType _ = TrustType
    packetCode _ = 12
    toPkt (Trust a) = TrustPkt a
    fromPktEither (TrustPkt a) = Right (Trust a)
    fromPktEither pkt = coercionError "Trust" pkt

instance Pretty Trust where
    pretty = pretty . toPkt

newtype UserId
    = UserId
    { _userIdPayload :: Text
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet UserId where
    data PacketType UserId = UserIdType
        deriving (Eq, Show)
    packetType _ = UserIdType
    packetCode _ = 13
    toPkt (UserId a) = UserIdPkt a
    fromPktEither (UserIdPkt a) = Right (UserId a)
    fromPktEither pkt = coercionError "UserId" pkt

instance Pretty UserId where
    pretty = pretty . toPkt

newtype PublicSubkey
    = PublicSubkey
    { _publicSubkeyPKPayload :: SomePKPayload
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet PublicSubkey where
    data PacketType PublicSubkey = PublicSubkeyType
        deriving (Eq, Show)
    packetType _ = PublicSubkeyType
    packetCode _ = 14
    toPkt (PublicSubkey a) = PublicSubkeyPkt a
    fromPktEither (PublicSubkeyPkt a) = Right (PublicSubkey a)
    fromPktEither pkt = coercionError "PublicSubkey" pkt

instance Pretty PublicSubkey where
    pretty = pretty . toPkt

newtype UserAttribute
    = UserAttribute
    { _userAttributeSubPackets :: [UserAttrSubPacket]
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet UserAttribute where
    data PacketType UserAttribute = UserAttributeType
        deriving (Eq, Show)
    packetType _ = UserAttributeType
    packetCode _ = 17
    toPkt (UserAttribute a) = UserAttributePkt a
    fromPktEither (UserAttributePkt a) = Right (UserAttribute a)
    fromPktEither pkt = coercionError "UserAttribute" pkt

instance Pretty UserAttribute where
    pretty = pretty . toPkt

data SymEncIntegrityProtectedData
    = SymEncIntegrityProtectedData
        { _symEncIntegrityProtectedDataPacketVersion :: PacketVersion
        , _symEncIntegrityProtectedDataPayload :: ByteString
        }
    | SymEncIntegrityProtectedDataV2
        SymmetricAlgorithm
        AEADAlgorithm
        Word8
        Salt
        ByteString
    deriving (Data, Eq, Show, Typeable)

instance Packet SymEncIntegrityProtectedData where
    data
        PacketType
            SymEncIntegrityProtectedData
        = SymEncIntegrityProtectedDataType
        deriving (Eq, Show)
    packetType _ = SymEncIntegrityProtectedDataType
    packetCode _ = 18
    toPkt (SymEncIntegrityProtectedData a b) = SymEncIntegrityProtectedDataPkt (SEIPD1 a b)
    toPkt (SymEncIntegrityProtectedDataV2 a b c d e) =
        SymEncIntegrityProtectedDataPkt (SEIPD2 a b c d e)
    fromPktEither (SymEncIntegrityProtectedDataPkt (SEIPD1 a b)) =
        Right (SymEncIntegrityProtectedData a b)
    fromPktEither (SymEncIntegrityProtectedDataPkt (SEIPD2 a b c d e)) =
        Right (SymEncIntegrityProtectedDataV2 a b c d e)
    fromPktEither pkt = coercionError "SymEncIntegrityProtectedData" pkt

instance Pretty SymEncIntegrityProtectedData where
    pretty = pretty . toPkt

newtype ModificationDetectionCode
    = ModificationDetectionCode
    { _modificationDetectionCodePayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet ModificationDetectionCode where
    data
        PacketType
            ModificationDetectionCode
        = ModificationDetectionCodeType
        deriving (Eq, Show)
    packetType _ = ModificationDetectionCodeType
    packetCode _ = 19
    toPkt (ModificationDetectionCode a) = ModificationDetectionCodePkt a
    fromPktEither (ModificationDetectionCodePkt a) = Right (ModificationDetectionCode a)
    fromPktEither pkt = coercionError "ModificationDetectionCode" pkt

instance Pretty ModificationDetectionCode where
    pretty = pretty . toPkt

newtype Padding
    = Padding
    { _padding :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet Padding where
    data
        PacketType
            Padding
        = PaddingType
        deriving (Eq, Show)
    packetType _ = PaddingType
    packetCode _ = 21
    toPkt (Padding a) = PaddingPkt a
    fromPktEither (PaddingPkt a) = Right (Padding a)
    fromPktEither pkt = coercionError "Padding" pkt

instance Pretty Padding where
    pretty = pretty . toPkt

data OtherPacket
    = OtherPacket
    { _otherPacketType :: Word8
    , _otherPacketPayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet OtherPacket where
    data PacketType OtherPacket = OtherPacketType
        deriving (Eq, Show)
    packetType _ = OtherPacketType
    packetCode _ = error "OtherPacket has no static packet type code"
    dynamicPacketCode = _otherPacketType
    toPkt (OtherPacket a b) = OtherPacketPkt a b
    fromPktEither (OtherPacketPkt a b) = Right (OtherPacket a b)
    fromPktEither pkt = coercionError "OtherPacket" pkt

instance Pretty OtherPacket where
    pretty = pretty . toPkt

data BrokenPacket
    = BrokenPacket
    { _brokenPacketParseError :: String
    , _brokenPacketType :: Word8
    , _brokenPacketPayload :: ByteString
    }
    deriving (Data, Eq, Show, Typeable)

instance Packet BrokenPacket where
    data PacketType BrokenPacket = BrokenPacketType
        deriving (Eq, Show)
    packetType _ = BrokenPacketType
    packetCode _ = error "BrokenPacket has no static packet type code"
    dynamicPacketCode = _brokenPacketType
    toPkt (BrokenPacket a b c) = BrokenPacketPkt a b c
    fromPktEither (BrokenPacketPkt a b c) = Right (BrokenPacket a b c)
    fromPktEither pkt = coercionError "BrokenPacket" pkt

instance Pretty BrokenPacket where
    pretty = pretty . toPkt

$(makeLenses ''Signature)

$(makeLenses ''SecretKey)

$(makeLenses ''PublicKey)

$(makeLenses ''SecretSubkey)

$(makeLenses ''CompressedData)

$(makeLenses ''SymEncData)

$(makeLenses ''Marker)

$(makeLenses ''LiteralData)

$(makeLenses ''Trust)

$(makeLenses ''UserId)

$(makeLenses ''PublicSubkey)

$(makeLenses ''UserAttribute)

$(makeLenses ''SymEncIntegrityProtectedData)

$(makeLenses ''ModificationDetectionCode)

$(makeLenses ''OtherPacket)

$(makeLenses ''BrokenPacket)
