backup-utils

Backup utilities
git clone http://git.omkov.net/backup-utils
Log | Tree | Refs | Download

backup-utils/src/backup-imap/main.go (150 lines, 2.8 KiB) -rw-r--r-- file download

f28abe4 Jakob Wakeling 2024-01-28 21:13:23
0
package main
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
1
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
2
import (
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
3
	"fmt"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
4
	"log"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
5
	"os"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
6
	"path/filepath"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
7
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
8
	"github.com/alexflint/go-arg"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
9
	"github.com/emersion/go-imap"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
10
	"github.com/emersion/go-imap/client"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
11
)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
12
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
13
const Version = "0.0.1"
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
14
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
15
func main() {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
16
	var args struct {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
17
		Address  string `arg:"positional,required"`
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
18
		Username string `arg:"positional,required"`
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
19
		Password string `arg:"positional,required"`
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
20
		Output   string `arg:"-o" help:"Output directory" default:"mail"`
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
21
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
22
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
23
	if err := arg.Parse(&args); err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
24
		switch err {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
25
		case arg.ErrHelp:
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
26
			fmt.Print(help)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
27
			os.Exit(0)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
28
		case arg.ErrVersion:
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
29
			fmt.Print(version)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
30
			os.Exit(0)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
31
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
32
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
33
		fmt.Println(err.Error())
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
34
		os.Exit(-1)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
35
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
36
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
37
	c, err := client.DialTLS(args.Address, nil)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
38
	if err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
39
		log.Fatalln(err.Error())
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
40
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
41
	defer c.Logout()
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
42
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
43
	if err := c.Login(args.Username, args.Password); err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
44
		log.Fatalln(err.Error())
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
45
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
46
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
47
	mailboxes, err := Mailboxes(c)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
48
	if err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
49
		log.Fatalln(err.Error())
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
50
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
51
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
52
	for _, m := range mailboxes {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
53
		if m.Name == "Trash" {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
54
			log.Println("Skipping Trash")
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
55
			continue
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
56
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
57
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
58
		log.Println(m.Name)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
59
		if err := FetchMailbox(c, m, args.Output); err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
60
			log.Fatalln(err.Error())
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
61
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
62
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
63
}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
64
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
65
/* Get list of Mailboxes. */
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
66
func Mailboxes(c *client.Client) ([]*imap.MailboxInfo, error) {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
67
	ch := make(chan *imap.MailboxInfo, 6)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
68
	done := make(chan error, 1)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
69
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
70
	go func() { done <- c.List("", "*", ch) }()
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
71
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
72
	var mailboxes []*imap.MailboxInfo
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
73
	for m := range ch {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
74
		mailboxes = append(mailboxes, m)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
75
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
76
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
77
	if err := <-done; err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
78
		return nil, err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
79
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
80
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
81
	return mailboxes, nil
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
82
}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
83
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
84
func FetchMailbox(c *client.Client, mailbox *imap.MailboxInfo, dir string) error {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
85
	mbox, err := c.Select(mailbox.Name, true)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
86
	if err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
87
		return err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
88
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
89
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
90
	if err := os.MkdirAll(filepath.Join(dir, mailbox.Name), 0o777); err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
91
		return err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
92
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
93
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
94
	if mbox.Messages == 0 {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
95
		return nil
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
96
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
97
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
98
	seqset := new(imap.SeqSet)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
99
	seqset.AddRange(1, mbox.Messages)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
100
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
101
	section := &imap.BodySectionName{Peek: false}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
102
	items := []imap.FetchItem{imap.FetchAll, section.FetchItem()}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
103
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
104
	messages := make(chan *imap.Message, 10)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
105
	done := make(chan error, 1)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
106
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
107
	go func() {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
108
		done <- c.Fetch(seqset, items, messages)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
109
	}()
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
110
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
111
	for msg := range messages {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
112
		body := msg.GetBody(section)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
113
		if body == nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
114
			return fmt.Errorf("message body is nil")
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
115
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
116
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
117
		data := make([]byte, body.Len())
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
118
		if _, err := body.Read(data); err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
119
			return err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
120
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
121
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
122
		file, err := os.Create(
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
123
			filepath.Join(dir, mailbox.Name, fmt.Sprintf(
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
124
				"%s_%d.eml", msg.InternalDate.UTC().Format("20060102T150405Z"), msg.SeqNum,
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
125
			)),
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
126
		)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
127
		if err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
128
			return err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
129
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
130
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
131
		if _, err := file.Write(data); err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
132
			file.Close()
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
133
			return err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
134
		}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
135
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
136
		log.Println(mailbox.Name, "->", msg.Envelope.Subject)
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
137
		file.Close()
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
138
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
139
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
140
	if err := <-done; err != nil {
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
141
		return err
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
142
	}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
143
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
144
	return nil
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
145
}
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
146
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
147
const help = ``
f28abe4 Jakob Wakeling 2024-01-28 21:13:23
148
const version = "backup-imap, version " + Version + "\n"
149