-
Notifications
You must be signed in to change notification settings - Fork 2
/
import.go
142 lines (117 loc) · 3.67 KB
/
import.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright (c) 2022 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 pmapi
import (
"bytes"
"context"
"encoding/json"
"errors"
"strconv"
"github.com/go-resty/resty/v2"
)
const (
MaxImportMessageRequestLength = 10
MaxImportMessageRequestSize = 25 * 1024 * 1024 // 25 MB total limit
)
type ImportMsgReq struct {
Metadata *ImportMetadata // Metadata about the message to import.
Message []byte // The raw RFC822 message.
}
type ImportMsgReqs []*ImportMsgReq
func (reqs ImportMsgReqs) buildMultipartFormData() ([]*resty.MultipartField, error) {
metadata := make(map[string]*ImportMetadata, len(reqs))
fields := make([]*resty.MultipartField, 0, len(reqs))
for i, req := range reqs {
name := strconv.Itoa(i)
metadata[name] = req.Metadata
fields = append(fields, &resty.MultipartField{
Param: name,
FileName: name + ".eml",
ContentType: "message/rfc822",
Reader: bytes.NewReader(req.Message),
})
}
b, err := json.Marshal(metadata)
if err != nil {
return nil, err
}
fields = append(fields, &resty.MultipartField{
Param: "Metadata",
ContentType: "application/json",
Reader: bytes.NewReader(b),
})
return fields, nil
}
type ImportMetadata struct {
AddressID string
Unread Boolean // 0: read, 1: unread.
IsReplied Boolean // 1 if the message has been replied.
IsRepliedAll Boolean // 1 if the message has been replied to all.
IsForwarded Boolean // 1 if the message has been forwarded.
Time int64 // The time when the message was received as a Unix time.
Flags int64 // The type of the imported message.
LabelIDs []string // The labels to apply to the imported message. Must contain at least one system label.
}
type ImportMsgRes struct {
// The error encountered while importing the message, if any.
Error error
// The newly created message ID.
MessageID string
}
// Import imports messages to the user's account.
func (c *client) Import(ctx context.Context, reqs ImportMsgReqs) ([]*ImportMsgRes, error) {
if len(reqs) > MaxImportMessageRequestLength {
return nil, errors.New("request is too long")
}
remainingSize := MaxImportMessageRequestSize
for _, req := range reqs {
remainingSize -= len(req.Message)
if remainingSize < 0 {
return nil, errors.New("request size is too big")
}
}
fields, err := reqs.buildMultipartFormData()
if err != nil {
return nil, err
}
var res struct {
Responses []struct {
Name string
Response struct {
Error
MessageID string
}
}
}
if _, err := c.do(ctx, func(r *resty.Request) (*resty.Response, error) {
return r.SetMultipartFields(fields...).SetResult(&res).Post("/mail/v4/messages/import")
}); err != nil {
return nil, err
}
resps := make([]*ImportMsgRes, 0, len(res.Responses))
for _, resp := range res.Responses {
var err error
if resp.Response.Code != 1000 {
err = resp.Response.Error
}
resps = append(resps, &ImportMsgRes{
Error: err,
MessageID: resp.Response.MessageID,
})
}
return resps, nil
}