1package memory 2 3import ( 4 "io/ioutil" 5 "time" 6 7 "github.com/emersion/go-imap" 8 "github.com/emersion/go-imap/backend" 9 "github.com/emersion/go-imap/backend/backendutil" 10) 11 12var Delimiter = "/" 13 14type Mailbox struct { 15 Subscribed bool 16 Messages []*Message 17 18 name string 19 user *User 20} 21 22func (mbox *Mailbox) Name() string { 23 return mbox.name 24} 25 26func (mbox *Mailbox) Info() (*imap.MailboxInfo, error) { 27 info := &imap.MailboxInfo{ 28 Delimiter: Delimiter, 29 Name: mbox.name, 30 } 31 return info, nil 32} 33 34func (mbox *Mailbox) uidNext() uint32 { 35 var uid uint32 36 for _, msg := range mbox.Messages { 37 if msg.Uid > uid { 38 uid = msg.Uid 39 } 40 } 41 uid++ 42 return uid 43} 44 45func (mbox *Mailbox) flags() []string { 46 flagsMap := make(map[string]bool) 47 for _, msg := range mbox.Messages { 48 for _, f := range msg.Flags { 49 if !flagsMap[f] { 50 flagsMap[f] = true 51 } 52 } 53 } 54 55 var flags []string 56 for f := range flagsMap { 57 flags = append(flags, f) 58 } 59 return flags 60} 61 62func (mbox *Mailbox) unseenSeqNum() uint32 { 63 for i, msg := range mbox.Messages { 64 seqNum := uint32(i + 1) 65 66 seen := false 67 for _, flag := range msg.Flags { 68 if flag == imap.SeenFlag { 69 seen = true 70 break 71 } 72 } 73 74 if !seen { 75 return seqNum 76 } 77 } 78 return 0 79} 80 81func (mbox *Mailbox) Status(items []imap.StatusItem) (*imap.MailboxStatus, error) { 82 status := imap.NewMailboxStatus(mbox.name, items) 83 status.Flags = mbox.flags() 84 status.PermanentFlags = []string{"\\*"} 85 status.UnseenSeqNum = mbox.unseenSeqNum() 86 87 for _, name := range items { 88 switch name { 89 case imap.StatusMessages: 90 status.Messages = uint32(len(mbox.Messages)) 91 case imap.StatusUidNext: 92 status.UidNext = mbox.uidNext() 93 case imap.StatusUidValidity: 94 status.UidValidity = 1 95 case imap.StatusRecent: 96 status.Recent = 0 // TODO 97 case imap.StatusUnseen: 98 status.Unseen = 0 // TODO 99 } 100 } 101 102 return status, nil 103} 104 105func (mbox *Mailbox) SetSubscribed(subscribed bool) error { 106 mbox.Subscribed = subscribed 107 return nil 108} 109 110func (mbox *Mailbox) Check() error { 111 return nil 112} 113 114func (mbox *Mailbox) ListMessages(uid bool, seqSet *imap.SeqSet, items []imap.FetchItem, ch chan<- *imap.Message) error { 115 defer close(ch) 116 117 for i, msg := range mbox.Messages { 118 seqNum := uint32(i + 1) 119 120 var id uint32 121 if uid { 122 id = msg.Uid 123 } else { 124 id = seqNum 125 } 126 if !seqSet.Contains(id) { 127 continue 128 } 129 130 m, err := msg.Fetch(seqNum, items) 131 if err != nil { 132 continue 133 } 134 135 ch <- m 136 } 137 138 return nil 139} 140 141func (mbox *Mailbox) SearchMessages(uid bool, criteria *imap.SearchCriteria) ([]uint32, error) { 142 var ids []uint32 143 for i, msg := range mbox.Messages { 144 seqNum := uint32(i + 1) 145 146 ok, err := msg.Match(seqNum, criteria) 147 if err != nil || !ok { 148 continue 149 } 150 151 var id uint32 152 if uid { 153 id = msg.Uid 154 } else { 155 id = seqNum 156 } 157 ids = append(ids, id) 158 } 159 return ids, nil 160} 161 162func (mbox *Mailbox) CreateMessage(flags []string, date time.Time, body imap.Literal) error { 163 if date.IsZero() { 164 date = time.Now() 165 } 166 167 b, err := ioutil.ReadAll(body) 168 if err != nil { 169 return err 170 } 171 172 mbox.Messages = append(mbox.Messages, &Message{ 173 Uid: mbox.uidNext(), 174 Date: date, 175 Size: uint32(len(b)), 176 Flags: flags, 177 Body: b, 178 }) 179 return nil 180} 181 182func (mbox *Mailbox) UpdateMessagesFlags(uid bool, seqset *imap.SeqSet, op imap.FlagsOp, flags []string) error { 183 for i, msg := range mbox.Messages { 184 var id uint32 185 if uid { 186 id = msg.Uid 187 } else { 188 id = uint32(i + 1) 189 } 190 if !seqset.Contains(id) { 191 continue 192 } 193 194 msg.Flags = backendutil.UpdateFlags(msg.Flags, op, flags) 195 } 196 197 return nil 198} 199 200func (mbox *Mailbox) CopyMessages(uid bool, seqset *imap.SeqSet, destName string) error { 201 dest, ok := mbox.user.mailboxes[destName] 202 if !ok { 203 return backend.ErrNoSuchMailbox 204 } 205 206 for i, msg := range mbox.Messages { 207 var id uint32 208 if uid { 209 id = msg.Uid 210 } else { 211 id = uint32(i + 1) 212 } 213 if !seqset.Contains(id) { 214 continue 215 } 216 217 msgCopy := *msg 218 msgCopy.Uid = dest.uidNext() 219 dest.Messages = append(dest.Messages, &msgCopy) 220 } 221 222 return nil 223} 224 225func (mbox *Mailbox) Expunge() error { 226 for i := len(mbox.Messages) - 1; i >= 0; i-- { 227 msg := mbox.Messages[i] 228 229 deleted := false 230 for _, flag := range msg.Flags { 231 if flag == imap.DeletedFlag { 232 deleted = true 233 break 234 } 235 } 236 237 if deleted { 238 mbox.Messages = append(mbox.Messages[:i], mbox.Messages[i+1:]...) 239 } 240 } 241 242 return nil 243} 244