proton-bridge/internal/transfer/message.go

126 lines
3.6 KiB
Go

// Copyright (c) 2021 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package transfer
import (
"fmt"
"mime"
"net/mail"
"time"
)
// Message is data holder passed between import and export.
type Message struct {
ID string
Unread bool
Body []byte
Sources []Mailbox
Targets []Mailbox
}
// sourceNames returns array of source mailbox names.
func (msg Message) sourceNames() (names []string) {
for _, mailbox := range msg.Sources {
names = append(names, mailbox.Name)
}
return
}
// targetNames returns array of target mailbox names.
func (msg Message) targetNames() (names []string) {
for _, mailbox := range msg.Targets {
names = append(names, mailbox.Name)
}
return
}
// MessageStatus holds status for message used by progress manager.
type MessageStatus struct {
eventTime time.Time // Time of adding message to the process.
sourceNames []string // Source mailbox names message is in.
SourceID string // Message ID at the source.
targetNames []string // Target mailbox names message is in.
targetID string // Message ID at the target (if any).
bodyHash string // Hash of the message body.
skipped bool
exported bool
imported bool
exportErr error
importErr error
// Info about message displayed to user.
// This is needed only for failed messages, but we cannot know in advance
// which message will fail. We could clear it once the message passed
// without any error. However, if we say one message takes about 100 bytes
// in average, it's about 100 MB per million of messages, which is fine.
Subject string
From string
Time time.Time
}
func (status *MessageStatus) String() string {
return fmt.Sprintf("%s (%s, %s, %s): %s", status.SourceID, status.Subject, status.From, status.Time, status.GetErrorMessage())
}
func (status *MessageStatus) setDetailsFromHeader(header mail.Header) {
dec := &mime.WordDecoder{}
status.Subject = header.Get("subject")
if subject, err := dec.Decode(status.Subject); err == nil {
status.Subject = subject
}
status.From = header.Get("from")
if from, err := dec.Decode(status.From); err == nil {
status.From = from
}
if msgTime, err := header.Date(); err == nil {
status.Time = msgTime
}
}
func (status *MessageStatus) hasError(includeMissing bool) bool {
return status.exportErr != nil || status.importErr != nil || (includeMissing && !status.skipped && !status.imported)
}
// GetErrorMessage returns error message.
func (status *MessageStatus) GetErrorMessage() string {
return status.getErrorMessage(true)
}
func (status *MessageStatus) getErrorMessage(includeMissing bool) string {
if status.skipped {
return ""
}
if status.exportErr != nil {
return fmt.Sprintf("failed to export: %s", status.exportErr)
}
if status.importErr != nil {
return fmt.Sprintf("failed to import: %s", status.importErr)
}
if includeMissing && !status.imported {
if !status.exported {
return "failed to import: lost before read"
}
return "failed to import: lost in the process"
}
return ""
}