Skip to content

Commit

Permalink
Add attachments copied to the results string
Browse files Browse the repository at this point in the history
  • Loading branch information
tagatac committed Jul 26, 2022
1 parent c50b14c commit 86f9b32
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 73 deletions.
47 changes: 24 additions & 23 deletions bagoup.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
)

func (cfg configuration) bagoup() error {
opts := cfg.Options
opts := cfg.opts
if err := validatePaths(cfg.OS, opts); err != nil {
return err
}
Expand All @@ -34,11 +34,11 @@ func (cfg configuration) bagoup() error {
log.SetOutput(io.MultiWriter(logFile, os.Stdout))

if opts.MacOSVersion != nil {
cfg.MacOSVersion, err = semver.NewVersion(*opts.MacOSVersion)
cfg.macOSVersion, err = semver.NewVersion(*opts.MacOSVersion)
if err != nil {
return errors.Wrapf(err, "parse Mac OS version %q", *opts.MacOSVersion)
}
} else if cfg.MacOSVersion, err = cfg.OS.GetMacOSVersion(); err != nil {
} else if cfg.macOSVersion, err = cfg.OS.GetMacOSVersion(); err != nil {
return errors.Wrap(err, "get Mac OS version - FIX: specify the Mac OS version from which chat.db was copied with the --mac-os-version option")
}

Expand All @@ -50,18 +50,18 @@ func (cfg configuration) bagoup() error {
}
}

if err := cfg.ChatDB.Init(cfg.MacOSVersion); err != nil {
return errors.Wrapf(err, "initialize the database for reading on Mac OS version %s", cfg.MacOSVersion.String())
if err := cfg.ChatDB.Init(cfg.macOSVersion); err != nil {
return errors.Wrapf(err, "initialize the database for reading on Mac OS version %s", cfg.macOSVersion.String())
}

cfg.HandleMap, err = cfg.ChatDB.GetHandleMap(contactMap)
cfg.handleMap, err = cfg.ChatDB.GetHandleMap(contactMap)
if err != nil {
return errors.Wrap(err, "get handle map")
}

defer cfg.OS.RmTempDir()
err = cfg.exportChats(contactMap)
printResults(opts.ExportPath, cfg.Counts, time.Since(cfg.StartTime))
printResults(opts.ExportPath, cfg.counts, time.Since(cfg.startTime))
if err != nil {
return errors.Wrap(err, "export chats")
}
Expand All @@ -81,26 +81,16 @@ func validatePaths(s opsys.OS, opts options) error {
}

func printResults(exportPath string, c counts, duration time.Duration) {
var attachmentsString string
for mimeType, count := range c.attachments {
attachmentsString += fmt.Sprintf("\n\t%s: %d", mimeType, count)
}
if attachmentsString == "" {
attachmentsString = "0"
}
var attachmentsEmbeddedString string
for mimeType, count := range c.attachmentsEmbedded {
attachmentsEmbeddedString += fmt.Sprintf("\n\t%s: %d", mimeType, count)
}
if attachmentsEmbeddedString == "" {
attachmentsEmbeddedString = "0"
}
attCpString := makeAttachmentsString(c.attachmentsCopied)
attString := makeAttachmentsString(c.attachments)
attEmbdString := makeAttachmentsString(c.attachmentsEmbedded)
log.Printf(`%sBAGOUP RESULTS:
bagoup version: %s
Export folder: %q
Export files written: %d
Chats exported: %d
Messages exported: %d
Attachments copied: %s
Attachments referenced or embedded: %s
Attachments embedded: %s
Attachments missing (see warnings above): %d
Expand All @@ -113,12 +103,23 @@ Time elapsed: %s%s`,
c.files,
c.chats,
c.messages,
attachmentsString,
attachmentsEmbeddedString,
attCpString,
attString,
attEmbdString,
c.attachmentsMissing,
c.conversions,
c.conversionsFailed,
duration.String(),
"\x1b[0m",
)
}

func makeAttachmentsString(attCounts map[string]int) (attString string) {
attCount := 0
for mimeType, count := range attCounts {
attCount += count
attString += fmt.Sprintf("\n\t%s: %d", mimeType, count)
}
attString = fmt.Sprintf("%d%s", attCount, attString)
return
}
8 changes: 4 additions & 4 deletions bagoup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,10 @@ func TestBagoup(t *testing.T) {
tt.setupMocks(osMock, dbMock)

cfg := configuration{
Options: tt.opts,
OS: osMock,
ChatDB: dbMock,
logDir: "messages-export/.bagoup",
opts: tt.opts,
OS: osMock,
ChatDB: dbMock,
logDir: "messages-export/.bagoup",
}
err := cfg.bagoup()
if tt.wantErr != "" {
Expand Down
8 changes: 4 additions & 4 deletions export.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ func getAttachmentPaths(cfg *configuration) error {
if err != nil {
return errors.Wrap(err, "get attachment paths")
}
cfg.AttachmentPaths = attPaths
if cfg.Options.OutputPDF || cfg.Options.CopyAttachments {
cfg.attachmentPaths = attPaths
if cfg.opts.OutputPDF || cfg.opts.CopyAttachments {
for _, msgPaths := range attPaths {
if len(msgPaths) == 0 {
continue
Expand All @@ -50,7 +50,7 @@ func getAttachmentPaths(cfg *configuration) error {
}

func (cfg *configuration) exportEntityChats(entityChats chatdb.EntityChats) error {
mergeChats := !cfg.Options.SeparateChats
mergeChats := !cfg.opts.SeparateChats
var guids []string
var entityMessageIDs []chatdb.DatedMessageID
for _, chat := range entityChats.Chats {
Expand All @@ -66,7 +66,7 @@ func (cfg *configuration) exportEntityChats(entityChats chatdb.EntityChats) erro
return err
}
}
cfg.Counts.chats += 1
cfg.counts.chats += 1
}
if mergeChats {
if err := cfg.writeFile(entityChats.Name, guids, entityMessageIDs); err != nil {
Expand Down
4 changes: 2 additions & 2 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,15 +307,15 @@ func TestExportChats(t *testing.T) {
attachmentsEmbedded: map[string]int{},
}
cfg := configuration{
Options: options{
opts: options{
ExportPath: "messages-export",
SeparateChats: tt.separateChats,
OutputPDF: tt.pdf,
CopyAttachments: tt.copyAttachments,
},
OS: osMock,
ChatDB: dbMock,
Counts: cnts,
counts: cnts,
}
err := cfg.exportChats(nil)
if tt.wantErr != "" {
Expand Down
29 changes: 17 additions & 12 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,22 @@ type (
PrintVersion bool `short:"v" long:"version" description:"Show the version of bagoup"`
}
configuration struct {
Options options
opts options
opsys.OS
chatdb.ChatDB
logDir string
MacOSVersion *semver.Version
HandleMap map[int]string
AttachmentPaths map[int][]chatdb.Attachment
Counts counts
StartTime time.Time
macOSVersion *semver.Version
handleMap map[int]string
attachmentPaths map[int][]chatdb.Attachment
counts counts
startTime time.Time
}
counts struct {
files int
chats int
messages int
attachments map[string]int
attachmentsCopied map[string]int
attachmentsEmbedded map[string]int
attachmentsMissing int
conversions int
Expand Down Expand Up @@ -104,12 +105,16 @@ func main() {

logDir := filepath.Join(opts.ExportPath, ".bagoup")
cfg := configuration{
Options: opts,
OS: s,
ChatDB: cdb,
logDir: logDir,
Counts: counts{attachments: map[string]int{}, attachmentsEmbedded: map[string]int{}},
StartTime: startTime,
opts: opts,
OS: s,
ChatDB: cdb,
logDir: logDir,
counts: counts{
attachments: map[string]int{},
attachmentsCopied: map[string]int{},
attachmentsEmbedded: map[string]int{},
},
startTime: startTime,
}
logFatalOnErr(cfg.bagoup())
logFatalOnErr(errors.Wrapf(db.Close(), "close DB file %q", dbPath))
Expand Down
40 changes: 21 additions & 19 deletions write.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ import (
)

func (cfg *configuration) writeFile(entityName string, guids []string, messageIDs []chatdb.DatedMessageID) error {
chatDirPath := filepath.Join(cfg.Options.ExportPath, entityName)
chatDirPath := filepath.Join(cfg.opts.ExportPath, entityName)
if err := cfg.OS.MkdirAll(chatDirPath, os.ModePerm); err != nil {
return errors.Wrapf(err, "create directory %q", chatDirPath)
}
filename := strings.Join(guids, ";;;")
chatPath := filepath.Join(chatDirPath, filename)
outFile, err := cfg.OS.NewOutFile(chatPath, cfg.Options.OutputPDF, cfg.Options.IncludePPA)
outFile, err := cfg.OS.NewOutFile(chatPath, cfg.opts.OutputPDF, cfg.opts.IncludePPA)
if err != nil {
return errors.Wrapf(err, "open/create file %q", chatPath)
}
defer outFile.Close()
attDir := filepath.Join(chatDirPath, "attachments")
if cfg.Options.CopyAttachments && !cfg.Options.PreservePaths {
if cfg.opts.CopyAttachments && !cfg.opts.PreservePaths {
if err := cfg.OS.Mkdir(attDir, os.ModePerm); err != nil {
return errors.Wrapf(err, "create directory %q", attDir)
}
Expand All @@ -37,7 +37,7 @@ func (cfg *configuration) writeFile(entityName string, guids []string, messageID
sort.SliceStable(messageIDs, func(i, j int) bool { return messageIDs[i].Date < messageIDs[j].Date })
msgCount := 0
for _, messageID := range messageIDs {
msg, err := cfg.ChatDB.GetMessage(messageID.ID, cfg.HandleMap)
msg, err := cfg.ChatDB.GetMessage(messageID.ID, cfg.handleMap)
if err != nil {
return errors.Wrapf(err, "get message with ID %d", messageID.ID)
}
Expand All @@ -61,13 +61,13 @@ func (cfg *configuration) writeFile(entityName string, guids []string, messageID
if err := outFile.Close(); err != nil {
return errors.Wrapf(err, "write/close chat file %q", outFile.Name())
}
cfg.Counts.files += 1
cfg.Counts.messages += msgCount
cfg.counts.files += 1
cfg.counts.messages += msgCount
return nil
}

func (cfg *configuration) handleAttachments(outFile opsys.OutFile, msgID int, attDir string) error {
msgPaths, ok := cfg.AttachmentPaths[msgID]
msgPaths, ok := cfg.attachmentPaths[msgID]
if !ok {
return nil
}
Expand All @@ -76,17 +76,17 @@ func (cfg *configuration) handleAttachments(outFile opsys.OutFile, msgID int, at
err := validateAttachmentPath(cfg.OS, attPath)
if _, ok := err.(errorMissingAttachment); ok {
// Attachment is missing. Just reference it, and skip copying/embedding.
cfg.Counts.attachmentsMissing += 1
cfg.counts.attachmentsMissing += 1
log.Printf("WARN: chat file %q - message %d - %s attachment %q (ID %d) - %s", outFile.Name(), msgID, mimeType, transferName, att.ID, err)
if err := outFile.ReferenceAttachment(transferName); err != nil {
return errors.Wrapf(err, "reference attachment %q", transferName)
}
cfg.Counts.attachments[mimeType] += 1
cfg.counts.attachments[mimeType] += 1
continue
} else if err != nil {
return err
}
if err := cfg.copyAttachment(attPath, attDir); err != nil {
if err := cfg.copyAttachment(att, attDir); err != nil {
return err
}
if err := cfg.writeAttachment(outFile, att); err != nil {
Expand All @@ -112,32 +112,34 @@ func validateAttachmentPath(s opsys.OS, attPath string) error {
return nil
}

func (cfg configuration) copyAttachment(attPath, attDir string) error {
if !cfg.Options.CopyAttachments {
func (cfg *configuration) copyAttachment(att chatdb.Attachment, attDir string) error {
if !cfg.opts.CopyAttachments {
return nil
}
attPath, mimeType := att.Filename, att.MIMEType
unique := true
if cfg.Options.PreservePaths {
if cfg.opts.PreservePaths {
unique = false
attDir = filepath.Join(cfg.Options.ExportPath, "bagoup-attachments", filepath.Dir(attPath))
attDir = filepath.Join(cfg.opts.ExportPath, "bagoup-attachments", filepath.Dir(attPath))
if err := cfg.OS.MkdirAll(attDir, os.ModePerm); err != nil {
return errors.Wrapf(err, "create directory %q", attDir)
}
}
if err := cfg.OS.CopyFile(attPath, attDir, unique); err != nil {
return errors.Wrapf(err, "copy attachment %q to %q", attPath, attDir)
}
cfg.counts.attachmentsCopied[mimeType] += 1
return nil
}

func (cfg *configuration) writeAttachment(outFile opsys.OutFile, att chatdb.Attachment) error {
attPath, mimeType := att.Filename, att.MIMEType
if cfg.Options.OutputPDF {
if cfg.opts.OutputPDF {
if jpgPath, err := cfg.OS.HEIC2JPG(attPath); err != nil {
cfg.Counts.conversionsFailed += 1
cfg.counts.conversionsFailed += 1
log.Printf("WARN: chat file %q - convert HEIC file %q to JPG: %s", outFile.Name(), attPath, err)
} else if jpgPath != attPath {
cfg.Counts.conversions += 1
cfg.counts.conversions += 1
attPath, mimeType = jpgPath, "image/jpeg"
}
}
Expand All @@ -146,8 +148,8 @@ func (cfg *configuration) writeAttachment(outFile opsys.OutFile, att chatdb.Atta
return errors.Wrapf(err, "include attachment %q", attPath)
}
if embedded {
cfg.Counts.attachmentsEmbedded[mimeType] += 1
cfg.counts.attachmentsEmbedded[mimeType] += 1
}
cfg.Counts.attachments[mimeType] += 1
cfg.counts.attachments[mimeType] += 1
return nil
}
19 changes: 10 additions & 9 deletions write_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,26 +460,27 @@ func TestWriteFile(t *testing.T) {

cnts := counts{
attachments: map[string]int{},
attachmentsCopied: map[string]int{},
attachmentsEmbedded: map[string]int{},
}
cfg := configuration{
Options: options{
opts: options{
ExportPath: "messages-export",
OutputPDF: tt.pdf,
CopyAttachments: tt.copyAttachments,
PreservePaths: tt.preservePaths,
},
OS: osMock,
ChatDB: dbMock,
MacOSVersion: semver.MustParse("12.4"),
AttachmentPaths: map[int][]chatdb.Attachment{
macOSVersion: semver.MustParse("12.4"),
attachmentPaths: map[int][]chatdb.Attachment{
2: {
chatdb.Attachment{Filename: "attachment1.heic", MIMEType: "image/heic", TransferName: "att1transfer.heic"},
chatdb.Attachment{Filename: "attachment2.jpeg", MIMEType: "image/jpeg", TransferName: "att2transfer.jpeg"},
chatdb.Attachment{Filename: "", MIMEType: "image/png", TransferName: "att3transfer.png"},
},
},
Counts: cnts,
counts: cnts,
}
err := cfg.writeFile(
"friend",
Expand All @@ -494,11 +495,11 @@ func TestWriteFile(t *testing.T) {
return
}
assert.NilError(t, err)
assert.Equal(t, 2, cfg.Counts.messages)
assert.Equal(t, tt.wantJPGs, cfg.Counts.attachments["image/jpeg"])
assert.Equal(t, tt.wantEmbedded, cfg.Counts.attachmentsEmbedded["image/jpeg"])
assert.Equal(t, tt.wantConv, cfg.Counts.conversions)
assert.Equal(t, tt.wantConvFail, cfg.Counts.conversionsFailed)
assert.Equal(t, 2, cfg.counts.messages)
assert.Equal(t, tt.wantJPGs, cfg.counts.attachments["image/jpeg"])
assert.Equal(t, tt.wantEmbedded, cfg.counts.attachmentsEmbedded["image/jpeg"])
assert.Equal(t, tt.wantConv, cfg.counts.conversions)
assert.Equal(t, tt.wantConvFail, cfg.counts.conversionsFailed)
})
}
}

0 comments on commit 86f9b32

Please sign in to comment.