Files
pop/internal/mail/types.go
Michael Freno bf26cd3ed6 feat: implement Milestone 3 integration points
Add comprehensive integration capabilities to Pop CLI:

- Multi-account support with named profiles
- Webhook management with signature verification
- External PGP key management (import/export/encrypt/decrypt/sign/verify)
- CLI plugin system for extensibility
- Complete documentation in README.md

All compilation errors fixed and build verified CLEAN.

Security review delegated to FRE-5202.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-14 00:40:24 -04:00

267 lines
7.3 KiB
Go

package mail
import "time"
type Folder int
const (
FolderInbox Folder = 0
FolderSent Folder = 3
FolderDraft Folder = 2
FolderTrash Folder = 4
FolderSpam Folder = 5
)
const (
MessageTypeRegular = "0"
MessageTypeDraft = "2"
)
func (f Folder) Name() string {
names := map[Folder]string{
FolderInbox: "Inbox",
FolderSent: "Sent",
FolderDraft: "Drafts",
FolderTrash: "Trash",
FolderSpam: "Spam",
}
if name, ok := names[f]; ok {
return name
}
return "Unknown"
}
type Message struct {
MessageID string `json:"MessageID"`
ConversationID string `json:"ConversationID"`
CreatedAt time.Time `json:"-"`
Created int64 `json:"Created"`
UpdatedAt time.Time `json:"-"`
Updated int64 `json:"Updated"`
Type int `json:"Type"`
Starred bool `json:"Starred"`
Read bool `json:"Read"`
Category int `json:"Category"`
Sender Recipient `json:"Sender"`
Recipients []Recipient `json:"Recipients"`
Subject string `json:"Subject"`
Body string `json:"Body"`
BodyEnc string `json:"BodyEnc,omitempty"`
Attachments []Attachment `json:"Attachments,omitempty"`
MimeMessageID string `json:"MimeMessageID,omitempty"`
InReplyTo string `json:"InReplyTo,omitempty"`
}
func (m *Message) Folder() Folder {
if m.Type == int(FolderDraft) {
return FolderDraft
}
if m.Type == int(FolderSent) {
return FolderSent
}
return FolderInbox
}
type Recipient struct {
Name string `json:"Name"`
Address string `json:"Address"`
Label int `json:"Label"`
AddressID string `json:"AddressID,omitempty"`
KeyID string `json:"KeyID,omitempty"`
Fingerprint string `json:"Fingerprint,omitempty"`
}
func (r Recipient) DisplayName() string {
if r.Name != "" {
return r.Name + " <" + r.Address + ">"
}
return r.Address
}
func (r Recipient) ToRecipient() Recipient {
return Recipient{
Name: r.Name,
Address: r.Address,
}
}
type Attachment struct {
AttachmentID string `json:"AttachmentID"`
Name string `json:"Name"`
ContentType string `json:"ContentType"`
Size int `json:"Size"`
DataEnc string `json:"DataEnc,omitempty"`
Keys []AttachmentKey `json:"Keys,omitempty"`
}
type AttachmentKey struct {
DataEnc string `json:"DataEnc"`
}
type Draft struct {
MessageID string `json:"MessageID"`
To []Recipient `json:"To"`
CC []Recipient `json:"CC,omitempty"`
BCC []Recipient `json:"BCC,omitempty"`
Subject string `json:"Subject"`
Body string `json:"Body"`
BodyEnc string `json:"BodyEnc,omitempty"`
Attachments []Attachment `json:"Attachments,omitempty"`
}
type ListMessagesRequest struct {
Folder Folder `json:"-"`
Page int `json:"Page"`
PageSize int `json:"PageSize"`
Passphrase string `json:"Passphrase"`
Starred *bool `json:"Starred,omitempty"`
Read *bool `json:"Read,omitempty"`
Since int64 `json:"Since,omitempty"`
}
type ListMessagesResponse struct {
Total int `json:"Total"`
Messages []Message `json:"Messages"`
}
type SendRequest struct {
To []Recipient `json:"To"`
CC []Recipient `json:"CC,omitempty"`
BCC []Recipient `json:"BCC,omitempty"`
Subject string `json:"Subject"`
Body string `json:"Body"`
HTML bool `json:"HTML,omitempty"`
ReplyTo []Recipient `json:"ReplyTo,omitempty"`
InReplyTo string `json:"InReplyTo,omitempty"`
References string `json:"References,omitempty"`
Attachments []Attachment `json:"Attachments,omitempty"`
Passphrase string `json:"Passphrase"`
}
type SearchRequest struct {
Query string `json:"Query"`
Page int `json:"Page"`
PageSize int `json:"PageSize"`
Passphrase string `json:"Passphrase"`
}
type SearchResponse struct {
Total int `json:"Total"`
Messages []Message `json:"Messages"`
}
// Conversation represents a threaded conversation (email thread)
type Conversation struct {
ConversationID string `json:"ConversationID"`
Subject string `json:"Subject"`
MessageCount int `json:"MessageCount"`
LastMessage *Message `json:"LastMessage"`
Participants []Recipient `json:"Participants"`
}
type ConversationResponse struct {
Total int `json:"Total"`
Conversations []Conversation `json:"Conversations"`
}
type GetConversationRequest struct {
ConversationID string `json:"ConversationID"`
Page int `json:"Page"`
PageSize int `json:"PageSize"`
Passphrase string `json:"Passphrase"`
}
type GetConversationResponse struct {
ConversationID string `json:"ConversationID"`
Subject string `json:"Subject"`
MessageCount int `json:"MessageCount"`
Messages []Message `json:"Messages"`
Participants []Recipient `json:"Participants"`
}
// BulkRequest represents a batch operation on multiple messages
type BulkRequest struct {
MessageIDs []string `json:"MessageIDs"`
Passphrase string `json:"Passphrase"`
}
type BulkResponse struct {
SuccessCount int `json:"SuccessCount"`
Total int `json:"Total"`
Errors []BulkError `json:"Errors,omitempty"`
}
type BulkError struct {
MessageID string `json:"MessageID"`
Error string `json:"Error"`
}
// ExportFormat represents the format for exporting messages
type ExportFormat int
const (
ExportFormatJSON ExportFormat = iota
ExportFormatMBOX
ExportFormatEMail
)
func (f ExportFormat) String() string {
names := map[ExportFormat]string{
ExportFormatJSON: "json",
ExportFormatMBOX: "mbox",
ExportFormatEMail: "eml",
}
if name, ok := names[f]; ok {
return name
}
return "json"
}
// ExportRequest represents a message export request
type ExportRequest struct {
MessageIDs []string `json:"MessageIDs,omitempty"`
Folder Folder `json:"Folder,omitempty"`
Format ExportFormat `json:"Format"`
Since int64 `json:"Since,omitempty"`
Before int64 `json:"Before,omitempty"`
Search string `json:"Search,omitempty"`
Passphrase string `json:"Passphrase"`
}
// ExportedMessage represents a message ready for export
type ExportedMessage struct {
MessageID string `json:"message_id"`
ConversationID string `json:"conversation_id"`
From Recipient `json:"from"`
To []Recipient `json:"to"`
CC []Recipient `json:"cc,omitempty"`
Subject string `json:"subject"`
Body string `json:"body"`
HTML bool `json:"html"`
Date string `json:"date"`
Starred bool `json:"starred"`
Read bool `json:"read"`
Attachments []Attachment `json:"attachments,omitempty"`
}
// ImportRequest represents a message import request
type ImportRequest struct {
FilePath string `json:"FilePath"`
Format ExportFormat `json:"Format"`
Folder Folder `json:"Folder,omitempty"`
Passphrase string `json:"Passphrase"`
}
type ImportResponse struct {
ImportedCount int `json:"ImportedCount"`
Total int `json:"Total"`
Errors []BulkError `json:"Errors,omitempty"`
}
// DraftAutoSaveConfig holds auto-save settings for drafts
type DraftAutoSaveConfig struct {
Enabled bool `json:"enabled"`
Interval int `json:"interval_seconds"`
LastSaved int64 `json:"last_saved_timestamp"`
}