package main import ( "errors" "github.com/emersion/go-imap" "github.com/emersion/go-imap/backend" "github.com/google/uuid" ) type User struct { username string sub uuid.UUID openMessages map[*Message]struct{} } func (u *User) Username() string { return u.username } func (u *User) ListMailboxes(subscribed bool) (mailboxes []backend.Mailbox, err error) { mailboxQuery, err := Database.DB.Query("SELECT mailbox, subscribed FROM mailboxes") if err != nil { return nil, err } defer func() { err := mailboxQuery.Close() if err != nil { log("Failed to close rows: "+err.Error()+", resource leaks may occur", 1) } }() for mailboxQuery.Next() { var name string var subscribed bool err := mailboxQuery.Scan(&name, &subscribed) if err != nil { return nil, err } mbox := &Mailbox{ name: name, user: u, } mbox.Subscribed = subscribed err = Database.DB.QueryRow("SELECT id FROM mailboxes WHERE mailbox = $1", name).Scan(&mbox.id) if err != nil { return nil, err } mailboxes = append(mailboxes, mbox) } return mailboxes, nil } func (u *User) GetRawMailbox(name string) (mailbox *Mailbox, err error) { mailbox = &Mailbox{ name: name, user: u, } err = Database.DB.QueryRow("SELECT id, subscribed FROM mailboxes WHERE mailbox = $1", name).Scan(&mailbox.id, &mailbox.Subscribed) if err != nil { return nil, err } return mailbox, nil } func (u *User) GetMailbox(name string) (mailbox backend.Mailbox, err error) { return u.GetRawMailbox(name) } func (u *User) CreateMailbox(name string) error { newUUID := uuid.New() _, err := Database.DB.Exec("INSERT INTO mailboxes (mailbox, id, owner) VALUES ($1, $2, $3)", name, newUUID[:], u.sub[:]) if err != nil { return err } return nil } func (u *User) DeleteMailbox(name string) error { if name == "INBOX" { return errors.New("cannot delete INBOX") } _, err := Database.DB.Exec("DELETE FROM mailboxes WHERE mailbox = $1", name) if err != nil { return err } return nil } func (u *User) RenameMailbox(existingName, newName string) error { if existingName != "INBOX" { _, err := Database.DB.Exec("UPDATE mailboxes SET mailbox = $1 WHERE mailbox = $2", newName, existingName) if err != nil { return err } } else { // INBOX is a special case, we need to create a new mailbox and copy the contents err := u.CreateMailbox(newName) if err != nil { return err } inbox, err := u.GetRawMailbox(newName) if err != nil { return err } set := new(imap.SeqSet) set.AddRange(1, 4294967295) // uint32 maximum value, essentially means all messages err = inbox.CopyMessages(true, set, newName) if err != nil { return err } err = inbox.Expunge() if err != nil { return err } } return nil } func (u *User) Logout() error { for msg := range u.openMessages { err := msg.Close() if err != nil { return err } } return nil }