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	Attachments []AttachmentInfo `json:"attachments"`
152}
153
154type AttachmentInfo struct {
155	Filename         string `json:"filename"`
156	PartID           string `json:"part_id"`
157	Encoding         string `json:"encoding"`
158	MIMEType         string `json:"mime_type"`
159	IsCalendarInvite bool   `json:"is_calendar_invite,omitempty"`
160	CalendarData     []byte `json:"calendar_data,omitempty"`
161}
162
163type SendEmailParams struct {
164	AccountID    string            `json:"account_id"`
165	To           []string          `json:"to"`
166	Cc           []string          `json:"cc,omitempty"`
167	Bcc          []string          `json:"bcc,omitempty"`
168	Subject      string            `json:"subject"`
169	Body         string            `json:"body"`
170	HTMLBody     string            `json:"html_body,omitempty"`
171	Attachments  map[string][]byte `json:"attachments,omitempty"`
172	InReplyTo    string            `json:"in_reply_to,omitempty"`
173	References   []string          `json:"references,omitempty"`
174	SignSMIME    bool              `json:"sign_smime,omitempty"`
175	EncryptSMIME bool              `json:"encrypt_smime,omitempty"`
176	SignPGP      bool              `json:"sign_pgp,omitempty"`
177	EncryptPGP   bool              `json:"encrypt_pgp,omitempty"`
178}
179
180type DeleteEmailsParams struct {
181	AccountID string   `json:"account_id"`
182	Folder    string   `json:"folder"`
183	UIDs      []uint32 `json:"uids"`
184}
185
186type ArchiveEmailsParams struct {
187	AccountID string   `json:"account_id"`
188	Folder    string   `json:"folder"`
189	UIDs      []uint32 `json:"uids"`
190}
191
192type MoveEmailsParams struct {
193	AccountID    string   `json:"account_id"`
194	UIDs         []uint32 `json:"uids"`
195	SourceFolder string   `json:"source_folder"`
196	DestFolder   string   `json:"dest_folder"`
197}
198
199type MarkReadParams struct {
200	AccountID string   `json:"account_id"`
201	Folder    string   `json:"folder"`
202	UIDs      []uint32 `json:"uids"`
203	Read      bool     `json:"read"`
204}
205
206type FetchFoldersParams struct {
207	AccountID string `json:"account_id"`
208}
209
210type RefreshFolderParams struct {
211	AccountID string `json:"account_id"`
212	Folder    string `json:"folder"`
213}
214
215type SubscribeParams struct {
216	AccountID string `json:"account_id"`
217	Folder    string `json:"folder"`
218}
219
220type UnsubscribeParams struct {
221	AccountID string `json:"account_id"`
222	Folder    string `json:"folder"`
223}
224
225type SendRSVPParams struct {
226	AccountID   string   `json:"account_id"`
227	OriginalICS []byte   `json:"original_ics"`
228	Response    string   `json:"response"`
229	InReplyTo   string   `json:"in_reply_to,omitempty"`
230	References  []string `json:"references,omitempty"`
231}
232
233type GetCachedEmailsParams struct {
234	Folder string `json:"folder"`
235}
236
237type GetCachedBodyParams struct {
238	Folder    string `json:"folder"`
239	UID       uint32 `json:"uid"`
240	AccountID string `json:"account_id"`
241}
242
243type ExportContactsParams struct {
244	Format string `json:"format"` // "json" or "csv"
245}
246
247// Event data types.
248
249type NewMailEvent struct {
250	AccountID string `json:"account_id"`
251	Folder    string `json:"folder"`
252}
253
254type SyncStartedEvent struct {
255	AccountID string `json:"account_id"`
256	Folder    string `json:"folder"`
257}
258
259type SyncCompleteEvent struct {
260	AccountID  string `json:"account_id"`
261	Folder     string `json:"folder"`
262	EmailCount int    `json:"email_count"`
263}
264
265type SyncErrorEvent struct {
266	AccountID string `json:"account_id"`
267	Folder    string `json:"folder"`
268	Error     string `json:"error"`
269}