protocol.go

  1package daemonrpc
  2
  3import "encoding/json"
  4
  5// Request from client to daemon. Has an ID for matching responses.
  6type Request struct {
  7	ID     uint64          `json:"id"`
  8	Method string          `json:"method"`
  9	Params json.RawMessage `json:"params,omitempty"`
 10}
 11
 12// Response from daemon to client. Matched to request by ID.
 13type Response struct {
 14	ID     uint64          `json:"id"`
 15	Result json.RawMessage `json:"result,omitempty"`
 16	Error  *Error          `json:"error,omitempty"`
 17}
 18
 19// Event pushed from daemon to subscribed clients. No ID field.
 20type Event struct {
 21	Type string          `json:"type"`
 22	Data json.RawMessage `json:"data,omitempty"`
 23}
 24
 25// Error returned in a Response.
 26type Error struct {
 27	Code    int    `json:"code"`
 28	Message string `json:"message"`
 29}
 30
 31func (e *Error) Error() string { return e.Message }
 32
 33// Message is a union type for wire decoding. Exactly one of the
 34// fields will be populated based on the presence of "id" and "type".
 35type Message struct {
 36	Request  *Request
 37	Response *Response
 38	Event    *Event
 39}
 40
 41// Discriminate: if "type" present → Event, if "method" present → Request, else → Response.
 42func DecodeMessage(raw json.RawMessage) (Message, error) {
 43	var probe struct {
 44		Type   string  `json:"type"`
 45		Method string  `json:"method"`
 46		ID     *uint64 `json:"id"`
 47	}
 48	if err := json.Unmarshal(raw, &probe); err != nil {
 49		return Message{}, err
 50	}
 51
 52	var m Message
 53	if probe.Type != "" {
 54		var ev Event
 55		if err := json.Unmarshal(raw, &ev); err != nil {
 56			return m, err
 57		}
 58		m.Event = &ev
 59	} else if probe.Method != "" {
 60		var req Request
 61		if err := json.Unmarshal(raw, &req); err != nil {
 62			return m, err
 63		}
 64		m.Request = &req
 65	} else {
 66		var resp Response
 67		if err := json.Unmarshal(raw, &resp); err != nil {
 68			return m, err
 69		}
 70		m.Response = &resp
 71	}
 72	return m, nil
 73}
 74
 75// Standard error codes.
 76const (
 77	ErrCodeParse      = -32700
 78	ErrCodeInvalidReq = -32600
 79	ErrCodeNotFound   = -32601
 80	ErrCodeInternal   = -32603
 81)
 82
 83// RPC method names.
 84const (
 85	MethodPing            = "Ping"
 86	MethodGetStatus       = "GetStatus"
 87	MethodGetAccounts     = "GetAccounts"
 88	MethodReloadConfig    = "ReloadConfig"
 89	MethodFetchEmails     = "FetchEmails"
 90	MethodFetchEmailBody  = "FetchEmailBody"
 91	MethodSendEmail       = "SendEmail"
 92	MethodDeleteEmails    = "DeleteEmails"
 93	MethodArchiveEmails   = "ArchiveEmails"
 94	MethodMoveEmails      = "MoveEmails"
 95	MethodMarkRead        = "MarkRead"
 96	MethodFetchFolders    = "FetchFolders"
 97	MethodRefreshFolder   = "RefreshFolder"
 98	MethodSubscribe       = "Subscribe"
 99	MethodUnsubscribe     = "Unsubscribe"
100	MethodSendRSVP        = "SendRSVP"
101	MethodGetCachedEmails = "GetCachedEmails"
102	MethodGetCachedBody   = "GetCachedBody"
103	MethodExportContacts  = "ExportContacts"
104)
105
106// Event type names.
107const (
108	EventNewMail        = "NewMail"
109	EventSyncStarted    = "SyncStarted"
110	EventSyncComplete   = "SyncComplete"
111	EventSyncError      = "SyncError"
112	EventEmailsUpdated  = "EmailsUpdated"
113	EventConfigReloaded = "ConfigReloaded"
114)
115
116// Param/result types for RPC methods.
117
118type PingResult struct {
119	Pong bool `json:"pong"`
120}
121
122type StatusResult struct {
123	Running  bool     `json:"running"`
124	Uptime   int64    `json:"uptime_seconds"`
125	Accounts []string `json:"accounts"`
126	PID      int      `json:"pid"`
127}
128
129type AccountInfo struct {
130	ID       string `json:"id"`
131	Name     string `json:"name"`
132	Email    string `json:"email"`
133	Protocol string `json:"protocol"`
134}
135
136type FetchEmailsParams struct {
137	AccountID string `json:"account_id"`
138	Folder    string `json:"folder"`
139	Limit     uint32 `json:"limit"`
140	Offset    uint32 `json:"offset"`
141}
142
143type FetchEmailBodyParams struct {
144	AccountID string `json:"account_id"`
145	Folder    string `json:"folder"`
146	UID       uint32 `json:"uid"`
147}
148
149type FetchEmailBodyResult struct {
150	Body         string           `json:"body"`
151	BodyMIMEType string           `json:"body_mime_type,omitempty"`
152	Attachments  []AttachmentInfo `json:"attachments"`
153}
154
155type AttachmentInfo struct {
156	Filename         string `json:"filename"`
157	PartID           string `json:"part_id"`
158	Encoding         string `json:"encoding"`
159	MIMEType         string `json:"mime_type"`
160	IsCalendarInvite bool   `json:"is_calendar_invite,omitempty"`
161	CalendarData     []byte `json:"calendar_data,omitempty"`
162}
163
164type SendEmailParams struct {
165	AccountID    string            `json:"account_id"`
166	To           []string          `json:"to"`
167	Cc           []string          `json:"cc,omitempty"`
168	Bcc          []string          `json:"bcc,omitempty"`
169	Subject      string            `json:"subject"`
170	Body         string            `json:"body"`
171	HTMLBody     string            `json:"html_body,omitempty"`
172	Attachments  map[string][]byte `json:"attachments,omitempty"`
173	InReplyTo    string            `json:"in_reply_to,omitempty"`
174	References   []string          `json:"references,omitempty"`
175	SignSMIME    bool              `json:"sign_smime,omitempty"`
176	EncryptSMIME bool              `json:"encrypt_smime,omitempty"`
177	SignPGP      bool              `json:"sign_pgp,omitempty"`
178	EncryptPGP   bool              `json:"encrypt_pgp,omitempty"`
179}
180
181type DeleteEmailsParams struct {
182	AccountID string   `json:"account_id"`
183	Folder    string   `json:"folder"`
184	UIDs      []uint32 `json:"uids"`
185}
186
187type ArchiveEmailsParams struct {
188	AccountID string   `json:"account_id"`
189	Folder    string   `json:"folder"`
190	UIDs      []uint32 `json:"uids"`
191}
192
193type MoveEmailsParams struct {
194	AccountID    string   `json:"account_id"`
195	UIDs         []uint32 `json:"uids"`
196	SourceFolder string   `json:"source_folder"`
197	DestFolder   string   `json:"dest_folder"`
198}
199
200type MarkReadParams struct {
201	AccountID string   `json:"account_id"`
202	Folder    string   `json:"folder"`
203	UIDs      []uint32 `json:"uids"`
204	Read      bool     `json:"read"`
205}
206
207type FetchFoldersParams struct {
208	AccountID string `json:"account_id"`
209}
210
211type RefreshFolderParams struct {
212	AccountID string `json:"account_id"`
213	Folder    string `json:"folder"`
214}
215
216type SubscribeParams struct {
217	AccountID string `json:"account_id"`
218	Folder    string `json:"folder"`
219}
220
221type UnsubscribeParams struct {
222	AccountID string `json:"account_id"`
223	Folder    string `json:"folder"`
224}
225
226type SendRSVPParams struct {
227	AccountID   string   `json:"account_id"`
228	OriginalICS []byte   `json:"original_ics"`
229	Response    string   `json:"response"`
230	InReplyTo   string   `json:"in_reply_to,omitempty"`
231	References  []string `json:"references,omitempty"`
232}
233
234type GetCachedEmailsParams struct {
235	Folder string `json:"folder"`
236}
237
238type GetCachedBodyParams struct {
239	Folder    string `json:"folder"`
240	UID       uint32 `json:"uid"`
241	AccountID string `json:"account_id"`
242}
243
244type ExportContactsParams struct {
245	Format string `json:"format"` // "json" or "csv"
246}
247
248// Event data types.
249
250type NewMailEvent struct {
251	AccountID string `json:"account_id"`
252	Folder    string `json:"folder"`
253}
254
255type SyncStartedEvent struct {
256	AccountID string `json:"account_id"`
257	Folder    string `json:"folder"`
258}
259
260type SyncCompleteEvent struct {
261	AccountID  string `json:"account_id"`
262	Folder     string `json:"folder"`
263	EmailCount int    `json:"email_count"`
264}
265
266type SyncErrorEvent struct {
267	AccountID string `json:"account_id"`
268	Folder    string `json:"folder"`
269	Error     string `json:"error"`
270}