Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions imapclient/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ func getReturnOpts(options *imap.ListOptions) []string {
if options.ReturnSpecialUse {
l = append(l, "SPECIAL-USE")
}
if options.ReturnMetadata {
l = append(l, "METADATA")
}
return l
}

Expand All @@ -63,8 +66,9 @@ func getReturnOpts(options *imap.ListOptions) []string {
// extension.
func (c *Client) List(ref, pattern string, options *imap.ListOptions) *ListCommand {
cmd := &ListCommand{
mailboxes: make(chan *imap.ListData, 64),
returnStatus: options != nil && options.ReturnStatus != nil,
mailboxes: make(chan *imap.ListData, 64),
returnStatus: options != nil && options.ReturnStatus != nil,
returnMetadata: options != nil && options.ReturnMetadata != nil,
}
enc := c.beginCommand("LIST", cmd)
if selectOpts := getSelectOpts(options); len(selectOpts) > 0 {
Expand All @@ -77,11 +81,16 @@ func (c *Client) List(ref, pattern string, options *imap.ListOptions) *ListComma
enc.SP().Atom("RETURN").SP().List(len(returnOpts), func(i int) {
opt := returnOpts[i]
enc.Atom(opt)
if opt == "STATUS" {
switch opt {
case "STATUS":
returnStatus := statusItems(options.ReturnStatus)
enc.SP().List(len(returnStatus), func(j int) {
enc.Atom(returnStatus[j])
})
case "METADATA":
enc.SP().List(len(options.ReturnMetadata), func(j int) {
enc.String(options.ReturnMetadata[j])
})
}
})
}
Expand Down Expand Up @@ -127,8 +136,9 @@ type ListCommand struct {
cmd
mailboxes chan *imap.ListData

returnStatus bool
pendingData *imap.ListData
returnStatus bool
returnMetadata bool
pendingData *imap.ListData
}

// Next advances to the next mailbox.
Expand Down
46 changes: 33 additions & 13 deletions imapclient/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,28 +108,48 @@ func (c *Client) handleMetadata() error {
return fmt.Errorf("in metadata-resp: %v", err)
}

cmd := c.findPendingCmdFunc(func(anyCmd command) bool {
cmd, ok := anyCmd.(*GetMetadataCommand)
return ok && cmd.mailbox == data.Mailbox
})
if cmd != nil && len(data.EntryValues) > 0 {
cmd := cmd.(*GetMetadataCommand)
cmd.data.Mailbox = data.Mailbox
if cmd.data.Entries == nil {
cmd.data.Entries = make(map[string]*[]byte)
cmd := c.findPendingCmdFunc(func(cmd command) bool {
switch cmd := cmd.(type) {
case *GetMetadataCommand:
return cmd.mailbox == data.Mailbox
case *ListCommand:
return cmd.returnMetadata && cmd.pendingData != nil && cmd.pendingData.Mailbox == data.Mailbox
default:
return false
}
})
if len(data.EntryValues) == 0 {
cmd = nil // Response is unsolicited
}
switch cmd := cmd.(type) {
case *GetMetadataCommand:
// The server might send multiple METADATA responses for a single
// METADATA command
for k, v := range data.EntryValues {
cmd.data.Entries[k] = v
populateMetadata(cmd.data, data)
case *ListCommand:
// TODO: populateMetadata(cmd.pendingData.Metadata, data)
// TODO: send to chan
default:
if handler := c.options.unilateralDataHandler().Metadata; handler != nil && len(data.EntryList) > 0 {
handler(data.Mailbox, data.EntryList)
}
} else if handler := c.options.unilateralDataHandler().Metadata; handler != nil && len(data.EntryList) > 0 {
handler(data.Mailbox, data.EntryList)
}

return nil
}

func populateMetadata(dst, src *GetMetadataData) {
cmd.data.Mailbox = data.Mailbox
if cmd.data.Entries == nil {
cmd.data.Entries = make(map[string]*[]byte)
}
// The server might send multiple METADATA responses for a single
// METADATA command
for k, v := range data.EntryValues {
cmd.data.Entries[k] = v
}
}

// GetMetadataCommand is a GETMETADATA command.
type GetMetadataCommand struct {
cmd
Expand Down
2 changes: 2 additions & 0 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type ListOptions struct {
ReturnChildren bool
ReturnStatus *StatusOptions // requires IMAP4rev2 or LIST-STATUS
ReturnSpecialUse bool // requires SPECIAL-USE
ReturnMetadata []string // requires LIST-METADATA
}

// ListData is the mailbox data returned by a LIST command.
Expand All @@ -23,6 +24,7 @@ type ListData struct {
ChildInfo *ListDataChildInfo
OldName string
Status *StatusData
Metadata struct{} // TODO: *GetMetadataData
}

type ListDataChildInfo struct {
Expand Down