messages.go

  1package tui
  2
  3import (
  4	calendar "github.com/floatpane/go-icalendar"
  5	"github.com/floatpane/matcha/backend"
  6	"github.com/floatpane/matcha/config"
  7	"github.com/floatpane/matcha/daemonrpc"
  8	"github.com/floatpane/matcha/fetcher"
  9)
 10
 11type MailboxKind string
 12
 13const (
 14	MailboxInbox   MailboxKind = "inbox"
 15	MailboxSent    MailboxKind = "sent"
 16	MailboxTrash   MailboxKind = "trash"
 17	MailboxArchive MailboxKind = "archive"
 18)
 19
 20type ViewEmailMsg struct {
 21	Index     int
 22	UID       uint32
 23	AccountID string
 24	Mailbox   MailboxKind
 25	Email     *fetcher.Email
 26}
 27
 28type SendEmailMsg struct {
 29	To              string
 30	Cc              string // Cc recipient(s)
 31	Bcc             string // Bcc recipient(s)
 32	Subject         string
 33	Body            string
 34	AttachmentPaths []string
 35	InReplyTo       string
 36	References      []string
 37	AccountID       string // ID of the account to send from
 38	FromOverride    string // Custom From address (used when account is catch-all)
 39	QuotedText      string // Hidden quoted text appended when sending
 40	Signature       string // Signature to append to email body
 41	SignSMIME       bool   // Whether to sign the email using S/MIME
 42	EncryptSMIME    bool   // Whether to encrypt the email using S/MIME
 43	SignPGP         bool   // Whether to sign the email using PGP
 44}
 45
 46type EmailQueuedMsg struct {
 47	JobID        string
 48	DelaySeconds int
 49}
 50
 51type EmailDelayExpiredMsg struct {
 52	JobID string
 53}
 54
 55type UndoSendMsg struct {
 56	JobID string
 57}
 58
 59type Credentials struct {
 60	Provider     string
 61	Name         string
 62	Host         string // Host (this was the previous "Email Address" field in the UI)
 63	FetchEmail   string // Single email address to fetch messages for. If empty, code should default this to Host when creating the account.
 64	SendAsEmail  string // Optional From header email. If empty, sending falls back to FetchEmail, then Host.
 65	CatchAll     bool   // Show all inbox messages regardless of To address.
 66	Password     string
 67	IMAPServer   string
 68	IMAPPort     int
 69	SMTPServer   string
 70	SMTPPort     int
 71	Insecure     bool
 72	AuthMethod   string // "password" or "oauth2"
 73	Protocol     string // "imap" (default), "jmap", or "pop3"
 74	JMAPEndpoint string // JMAP session URL
 75	POP3Server   string // POP3 server hostname
 76	POP3Port     int    // POP3 server port
 77	MaildirPath  string // Local Maildir root
 78}
 79
 80// StartOAuth2Msg is sent when the user requests OAuth2 authorization for a Gmail account.
 81type StartOAuth2Msg struct {
 82	Email string
 83}
 84
 85// OAuth2CompleteMsg is sent when OAuth2 authorization completes.
 86type OAuth2CompleteMsg struct {
 87	Email string
 88	Err   error
 89}
 90
 91type ChooseServiceMsg struct {
 92	Service string
 93}
 94
 95type EmailResultMsg struct {
 96	Err error
 97}
 98
 99type ClearStatusMsg struct{}
100
101type EmailsFetchedMsg struct {
102	Emails    []fetcher.Email
103	AccountID string
104	Mailbox   MailboxKind
105}
106
107type UpdatePreviewMsg struct {
108	UID       uint32
109	AccountID string
110}
111
112type PreviewBodyFetchedMsg struct {
113	UID          uint32
114	AccountID    string
115	Body         string
116	BodyMIMEType string
117	Attachments  []fetcher.Attachment
118	Err          error
119}
120
121type FetchErr error
122
123type SearchRequestedMsg struct {
124	Query      backend.SearchQuery
125	Mailbox    MailboxKind
126	FolderName string
127	AccountID  string
128}
129
130type SearchResultsMsg struct {
131	Query  backend.SearchQuery
132	Emails []fetcher.Email
133	Err    error
134}
135
136type ApplySearchResultsMsg struct {
137	Query  backend.SearchQuery
138	Emails []fetcher.Email
139}
140
141type GoToInboxMsg struct{}
142
143type GoToSentInboxMsg struct{}
144
145type GoToSendMsg struct {
146	To      string
147	Subject string
148	Body    string
149}
150
151type GoToSettingsMsg struct{}
152
153type GoToTrashArchiveMsg struct{}
154
155type GoToSignatureEditorMsg struct {
156	AccountID string
157}
158
159type FetchMoreEmailsMsg struct {
160	Offset    uint32
161	AccountID string
162	Mailbox   MailboxKind
163	Limit     uint32
164}
165
166type FetchingMoreEmailsMsg struct{}
167
168type EmailsAppendedMsg struct {
169	Emails    []fetcher.Email
170	AccountID string
171	Mailbox   MailboxKind
172}
173
174type ReplyToEmailMsg struct {
175	Email fetcher.Email
176}
177
178type ForwardEmailMsg struct {
179	Email fetcher.Email
180}
181
182type SetComposerCursorToStartMsg struct{}
183
184type GoToFilePickerMsg struct{}
185
186type FileSelectedMsg struct {
187	Paths []string
188}
189
190type CancelFilePickerMsg struct{}
191
192type DeleteEmailMsg struct {
193	UID       uint32
194	AccountID string
195	Mailbox   MailboxKind
196}
197
198type ArchiveEmailMsg struct {
199	UID       uint32
200	AccountID string
201	Mailbox   MailboxKind
202}
203
204type EmailActionDoneMsg struct {
205	UID       uint32
206	AccountID string
207	Mailbox   MailboxKind
208	Err       error
209}
210
211// Batch operation messages
212type BatchDeleteEmailsMsg struct {
213	UIDs      []uint32
214	AccountID string
215	Mailbox   MailboxKind
216}
217
218type BatchArchiveEmailsMsg struct {
219	UIDs      []uint32
220	AccountID string
221	Mailbox   MailboxKind
222}
223
224type BatchMoveEmailsMsg struct {
225	UIDs         []uint32
226	AccountID    string
227	SourceFolder string
228	DestFolder   string
229}
230
231type BatchEmailActionDoneMsg struct {
232	Count        int
233	SuccessCount int
234	FailureCount int
235	Action       string // "delete", "archive", or "move"
236	Mailbox      MailboxKind
237	Err          error
238}
239
240type GoToChoiceMenuMsg struct{}
241
242type DownloadAttachmentMsg struct {
243	Index     int
244	Filename  string
245	PartID    string
246	Data      []byte
247	AccountID string
248	Encoding  string
249	Mailbox   MailboxKind
250}
251
252type AttachmentDownloadedMsg struct {
253	Path string
254	Err  error
255}
256
257type RestoreViewMsg struct{}
258
259type BackToInboxMsg struct{}
260
261type BackToMailboxMsg struct {
262	Mailbox MailboxKind
263}
264
265// --- Draft Messages ---
266
267// DiscardDraftMsg signals that a draft should be cached.
268type DiscardDraftMsg struct {
269	ComposerState *Composer
270}
271
272type EmailBodyFetchedMsg struct {
273	UID          uint32
274	Body         string
275	BodyMIMEType string
276	Attachments  []fetcher.Attachment
277	Err          error
278	AccountID    string
279	Mailbox      MailboxKind
280}
281
282// --- Multi-Account Messages ---
283
284// GoToAddAccountMsg signals navigation to the add account screen.
285type GoToAddAccountMsg struct{}
286
287// GoToAddMailingListMsg signals navigation to the add mailing list screen.
288type GoToAddMailingListMsg struct{}
289
290// GoToEditAccountMsg signals navigation to edit an existing account.
291type GoToEditAccountMsg struct {
292	AccountID    string
293	Provider     string
294	Name         string
295	Email        string
296	FetchEmail   string
297	SendAsEmail  string
298	CatchAll     bool
299	IMAPServer   string
300	IMAPPort     int
301	SMTPServer   string
302	SMTPPort     int
303	Insecure     bool
304	Protocol     string
305	JMAPEndpoint string
306	POP3Server   string
307	POP3Port     int
308	MaildirPath  string
309}
310
311// GoToEditMailingListMsg signals navigation to edit an existing mailing list.
312type GoToEditMailingListMsg struct {
313	Index     int
314	Name      string
315	Addresses string
316}
317
318// SaveMailingListMsg signals that a new or edited mailing list should be saved.
319type SaveMailingListMsg struct {
320	Name      string
321	Addresses string
322	EditIndex int // -1 means new, >= 0 means editing existing
323}
324
325// AddAccountMsg signals that a new account should be added.
326type AddAccountMsg struct {
327	Credentials Credentials
328}
329
330// AccountAddedMsg signals that an account was successfully added.
331type AccountAddedMsg struct {
332	AccountID string
333	Err       error
334}
335
336// DeleteAccountMsg signals that an account should be deleted.
337type DeleteAccountMsg struct {
338	AccountID string
339}
340
341// AccountDeletedMsg signals that an account was successfully deleted.
342type AccountDeletedMsg struct {
343	AccountID string
344	Err       error
345}
346
347// SwitchAccountMsg signals switching to view a specific account's inbox.
348type SwitchAccountMsg struct {
349	AccountID string // Empty string means "ALL" accounts
350}
351
352// AllEmailsFetchedMsg signals that emails from all accounts have been fetched.
353type AllEmailsFetchedMsg struct {
354	EmailsByAccount map[string][]fetcher.Email
355	Mailbox         MailboxKind
356}
357
358// SwitchFromAccountMsg signals changing the "From" account in composer.
359type SwitchFromAccountMsg struct {
360	AccountID string
361}
362
363// GoToAccountListMsg signals navigation to the account list in settings.
364type GoToAccountListMsg struct{}
365
366// --- Draft Messages (persisted) ---
367
368// SaveDraftMsg signals that the current draft should be saved to disk.
369type SaveDraftMsg struct {
370	Draft config.Draft
371}
372
373// DraftSavedMsg signals that a draft was saved successfully.
374type DraftSavedMsg struct {
375	DraftID string
376	Err     error
377}
378
379// LoadDraftsMsg signals a request to load all saved drafts.
380type LoadDraftsMsg struct{}
381
382// DraftsLoadedMsg signals that drafts were loaded from disk.
383type DraftsLoadedMsg struct {
384	Drafts []config.Draft
385}
386
387// OpenDraftMsg signals that a specific draft should be opened in the composer.
388type OpenDraftMsg struct {
389	Draft config.Draft
390}
391
392// DeleteDraftMsg signals that a draft should be deleted.
393type DeleteSavedDraftMsg struct {
394	DraftID string
395}
396
397// DraftDeletedMsg signals that a draft was deleted.
398type DraftDeletedMsg struct {
399	DraftID string
400	Err     error
401}
402
403// GoToDraftsMsg signals navigation to the drafts list.
404type GoToDraftsMsg struct{}
405
406// --- Cache Messages ---
407
408// CachedEmailsLoadedMsg signals that cached emails were loaded from disk.
409type CachedEmailsLoadedMsg struct {
410	Cache *config.EmailCache
411}
412
413// RefreshingEmailsMsg signals that a background refresh is in progress.
414type RefreshingEmailsMsg struct {
415	Mailbox MailboxKind
416}
417
418// EmailsRefreshedMsg signals that fresh emails have been fetched in the background.
419type EmailsRefreshedMsg struct {
420	EmailsByAccount map[string][]fetcher.Email
421	Mailbox         MailboxKind
422}
423
424// RequestRefreshMsg signals a request to refresh emails from the server.
425type RequestRefreshMsg struct {
426	Mailbox    MailboxKind
427	Counts     map[string]int
428	FolderName string
429}
430
431// --- Folder Messages ---
432
433// FoldersFetchedMsg signals that IMAP folders have been fetched for all accounts.
434//
435// Errors holds per-account fetch failures (e.g. broken IMAP login, network
436// unreachable). Accounts that succeeded appear in FoldersByAccount; accounts
437// that failed appear in Errors. The two are disjoint by construction. This
438// lets the TUI surface a non-fatal warning instead of silently dropping the
439// affected account's folder list.
440type FoldersFetchedMsg struct {
441	FoldersByAccount map[string][]fetcher.Folder // accountID -> folders
442	MergedFolders    []fetcher.Folder            // unique folders across all accounts
443	Errors           map[string]error            // accountID -> fetch error, if any
444}
445
446// SwitchFolderMsg signals switching to a different IMAP folder.
447type SwitchFolderMsg struct {
448	FolderName     string
449	PreviousFolder string
450	AccountID      string
451}
452
453// FolderEmailsFetchedMsg signals that emails from a folder have been fetched.
454type FolderEmailsFetchedMsg struct {
455	Emails     []fetcher.Email
456	AccountID  string
457	FolderName string
458}
459
460// FolderEmailsAppendedMsg signals that more emails from a folder have been fetched (pagination).
461type FolderEmailsAppendedMsg struct {
462	Emails     []fetcher.Email
463	AccountID  string
464	FolderName string
465}
466
467// MoveEmailMsg signals a request to show the move-to-folder picker.
468type MoveEmailMsg struct {
469	UID          uint32
470	AccountID    string
471	SourceFolder string
472}
473
474// MoveEmailToFolderMsg signals that an email should be moved to a folder.
475type MoveEmailToFolderMsg struct {
476	UID          uint32
477	AccountID    string
478	SourceFolder string
479	DestFolder   string
480}
481
482// EmailMovedMsg signals that an email was moved to a folder.
483type EmailMovedMsg struct {
484	UID          uint32
485	AccountID    string
486	SourceFolder string
487	DestFolder   string
488	Err          error
489}
490
491// MarkEmailAsReadMsg signals that an email should be marked as read on the server.
492type MarkEmailAsReadMsg struct {
493	UID        uint32
494	AccountID  string
495	FolderName string
496}
497
498// EmailMarkedReadMsg signals that an email was marked as read.
499type EmailMarkedReadMsg struct {
500	UID       uint32
501	AccountID string
502	Err       error
503}
504
505// EmailMarkedUnreadMsg signals that an email was marked as unread.
506type EmailMarkedUnreadMsg struct {
507	UID       uint32
508	AccountID string
509	Err       error
510}
511
512// FetchFolderMoreEmailsMsg signals a request to fetch more emails from a folder (pagination).
513type FetchFolderMoreEmailsMsg struct {
514	Offset     uint32
515	AccountID  string
516	FolderName string
517	Limit      uint32
518}
519
520// --- External Editor Messages ---
521
522// OpenEditorMsg signals that the composer body should be opened in $EDITOR.
523type OpenEditorMsg struct{}
524
525// EditorFinishedMsg signals that the external editor has closed.
526type EditorFinishedMsg struct {
527	Body string
528	Err  error
529}
530
531// --- IDLE Messages ---
532
533// IdleNewMailMsg signals that IMAP IDLE detected new mail for an account/folder.
534type IdleNewMailMsg struct {
535	AccountID  string
536	FolderName string
537}
538
539// --- Daemon Messages ---
540
541// DaemonEventMsg wraps an event pushed from the daemon process.
542type DaemonEventMsg struct {
543	Event *daemonrpc.Event
544}
545
546// --- Plugin Messages ---
547
548// PluginNotifyMsg signals that a plugin wants to show a notification.
549type PluginNotifyMsg struct {
550	Message  string
551	Duration float64 // Duration in seconds (default 2)
552}
553
554// PluginKeyBinding describes a plugin-registered keyboard shortcut for display in the help bar.
555type PluginKeyBinding struct {
556	Key         string
557	Description string
558}
559
560// PluginPromptSubmitMsg signals that the user submitted a plugin prompt input.
561type PluginPromptSubmitMsg struct {
562	Value string
563}
564
565// PluginPromptCancelMsg signals that the user cancelled a plugin prompt input.
566type PluginPromptCancelMsg struct{}
567
568// GoToMarketplaceMsg signals navigation to the plugin marketplace.
569type GoToMarketplaceMsg struct{}
570
571// PasswordVerifiedMsg signals that the encryption password was verified (or failed).
572type PasswordVerifiedMsg struct {
573	Key []byte // The derived encryption key (nil on failure)
574	Err error  // Non-nil if verification failed
575}
576
577// SecureModeEnabledMsg signals that encryption was enabled from settings.
578type SecureModeEnabledMsg struct {
579	Err error
580}
581
582// SecureModeDisabledMsg signals that encryption was disabled from settings.
583type SecureModeDisabledMsg struct {
584	Err error
585}
586
587// SendRSVPMsg signals that user wants to send RSVP to calendar invite
588type SendRSVPMsg struct {
589	OriginalICS []byte
590	Event       *calendar.Event
591	Response    string // "ACCEPTED", "DECLINED", "TENTATIVE"
592	AccountID   string
593	InReplyTo   string
594	References  []string
595}
596
597// RSVPResultMsg signals that RSVP was sent (or failed)
598type LanguageChangedMsg struct{}
599
600// ConfigSavedMsg signals the config was written to disk and downstream
601// consumers (notably the daemon) should reload it.
602type ConfigSavedMsg struct{}
603
604type RSVPResultMsg struct {
605	Err       error
606	Response  string // "ACCEPTED", "DECLINED", "TENTATIVE"
607	Organizer string // organizer email for Google Calendar note
608}