Added files.
This commit is contained in:
212
capability.go
Normal file
212
capability.go
Normal file
@@ -0,0 +1,212 @@
|
||||
package imap
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cap represents an IMAP capability.
|
||||
type Cap string
|
||||
|
||||
// Registered capabilities.
|
||||
//
|
||||
// See: https://www.iana.org/assignments/imap-capabilities/
|
||||
const (
|
||||
CapIMAP4rev1 Cap = "IMAP4rev1" // RFC 3501
|
||||
CapIMAP4rev2 Cap = "IMAP4rev2" // RFC 9051
|
||||
|
||||
CapStartTLS Cap = "STARTTLS"
|
||||
CapLoginDisabled Cap = "LOGINDISABLED"
|
||||
|
||||
// Folded in IMAP4rev2
|
||||
CapNamespace Cap = "NAMESPACE" // RFC 2342
|
||||
CapUnselect Cap = "UNSELECT" // RFC 3691
|
||||
CapUIDPlus Cap = "UIDPLUS" // RFC 4315
|
||||
CapESearch Cap = "ESEARCH" // RFC 4731
|
||||
CapSearchRes Cap = "SEARCHRES" // RFC 5182
|
||||
CapEnable Cap = "ENABLE" // RFC 5161
|
||||
CapIdle Cap = "IDLE" // RFC 2177
|
||||
CapSASLIR Cap = "SASL-IR" // RFC 4959
|
||||
CapListExtended Cap = "LIST-EXTENDED" // RFC 5258
|
||||
CapListStatus Cap = "LIST-STATUS" // RFC 5819
|
||||
CapMove Cap = "MOVE" // RFC 6851
|
||||
CapLiteralMinus Cap = "LITERAL-" // RFC 7888
|
||||
CapStatusSize Cap = "STATUS=SIZE" // RFC 8438
|
||||
CapChildren Cap = "CHILDREN" // RFC 3348
|
||||
|
||||
CapACL Cap = "ACL" // RFC 4314
|
||||
CapAppendLimit Cap = "APPENDLIMIT" // RFC 7889
|
||||
CapBinary Cap = "BINARY" // RFC 3516
|
||||
CapCatenate Cap = "CATENATE" // RFC 4469
|
||||
CapCondStore Cap = "CONDSTORE" // RFC 7162
|
||||
CapConvert Cap = "CONVERT" // RFC 5259
|
||||
CapCreateSpecialUse Cap = "CREATE-SPECIAL-USE" // RFC 6154
|
||||
CapESort Cap = "ESORT" // RFC 5267
|
||||
CapFilters Cap = "FILTERS" // RFC 5466
|
||||
CapID Cap = "ID" // RFC 2971
|
||||
CapLanguage Cap = "LANGUAGE" // RFC 5255
|
||||
CapListMyRights Cap = "LIST-MYRIGHTS" // RFC 8440
|
||||
CapLiteralPlus Cap = "LITERAL+" // RFC 7888
|
||||
CapLoginReferrals Cap = "LOGIN-REFERRALS" // RFC 2221
|
||||
CapMailboxReferrals Cap = "MAILBOX-REFERRALS" // RFC 2193
|
||||
CapMetadata Cap = "METADATA" // RFC 5464
|
||||
CapMetadataServer Cap = "METADATA-SERVER" // RFC 5464
|
||||
CapMultiAppend Cap = "MULTIAPPEND" // RFC 3502
|
||||
CapMultiSearch Cap = "MULTISEARCH" // RFC 7377
|
||||
CapNotify Cap = "NOTIFY" // RFC 5465
|
||||
CapObjectID Cap = "OBJECTID" // RFC 8474
|
||||
CapPreview Cap = "PREVIEW" // RFC 8970
|
||||
CapQResync Cap = "QRESYNC" // RFC 7162
|
||||
CapQuota Cap = "QUOTA" // RFC 9208
|
||||
CapQuotaSet Cap = "QUOTASET" // RFC 9208
|
||||
CapReplace Cap = "REPLACE" // RFC 8508
|
||||
CapSaveDate Cap = "SAVEDATE" // RFC 8514
|
||||
CapSearchFuzzy Cap = "SEARCH=FUZZY" // RFC 6203
|
||||
CapSort Cap = "SORT" // RFC 5256
|
||||
CapSortDisplay Cap = "SORT=DISPLAY" // RFC 5957
|
||||
CapSpecialUse Cap = "SPECIAL-USE" // RFC 6154
|
||||
CapUnauthenticate Cap = "UNAUTHENTICATE" // RFC 8437
|
||||
CapURLPartial Cap = "URL-PARTIAL" // RFC 5550
|
||||
CapURLAuth Cap = "URLAUTH" // RFC 4467
|
||||
CapUTF8Accept Cap = "UTF8=ACCEPT" // RFC 6855
|
||||
CapUTF8Only Cap = "UTF8=ONLY" // RFC 6855
|
||||
CapWithin Cap = "WITHIN" // RFC 5032
|
||||
CapUIDOnly Cap = "UIDONLY" // RFC 9586
|
||||
CapListMetadata Cap = "LIST-METADATA" // RFC 9590
|
||||
CapInProgress Cap = "INPROGRESS" // RFC 9585
|
||||
)
|
||||
|
||||
var imap4rev2Caps = CapSet{
|
||||
CapNamespace: {},
|
||||
CapUnselect: {},
|
||||
CapUIDPlus: {},
|
||||
CapESearch: {},
|
||||
CapSearchRes: {},
|
||||
CapEnable: {},
|
||||
CapIdle: {},
|
||||
CapSASLIR: {},
|
||||
CapListExtended: {},
|
||||
CapListStatus: {},
|
||||
CapMove: {},
|
||||
CapLiteralMinus: {},
|
||||
CapStatusSize: {},
|
||||
CapChildren: {},
|
||||
}
|
||||
|
||||
// AuthCap returns the capability name for an SASL authentication mechanism.
|
||||
func AuthCap(mechanism string) Cap {
|
||||
return Cap("AUTH=" + mechanism)
|
||||
}
|
||||
|
||||
// CapSet is a set of capabilities.
|
||||
type CapSet map[Cap]struct{}
|
||||
|
||||
func (set CapSet) has(c Cap) bool {
|
||||
_, ok := set[c]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (set CapSet) Copy() CapSet {
|
||||
newSet := make(CapSet, len(set))
|
||||
for c := range set {
|
||||
newSet[c] = struct{}{}
|
||||
}
|
||||
return newSet
|
||||
}
|
||||
|
||||
// Has checks whether a capability is supported.
|
||||
//
|
||||
// Some capabilities are implied by others, as such Has may return true even if
|
||||
// the capability is not in the map.
|
||||
func (set CapSet) Has(c Cap) bool {
|
||||
if set.has(c) {
|
||||
return true
|
||||
}
|
||||
|
||||
if set.has(CapIMAP4rev2) && imap4rev2Caps.has(c) {
|
||||
return true
|
||||
}
|
||||
|
||||
if c == CapLiteralMinus && set.has(CapLiteralPlus) {
|
||||
return true
|
||||
}
|
||||
if c == CapCondStore && set.has(CapQResync) {
|
||||
return true
|
||||
}
|
||||
if c == CapUTF8Accept && set.has(CapUTF8Only) {
|
||||
return true
|
||||
}
|
||||
if c == CapAppendLimit {
|
||||
_, ok := set.AppendLimit()
|
||||
return ok
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// AuthMechanisms returns the list of supported SASL mechanisms for
|
||||
// authentication.
|
||||
func (set CapSet) AuthMechanisms() []string {
|
||||
var l []string
|
||||
for c := range set {
|
||||
if !strings.HasPrefix(string(c), "AUTH=") {
|
||||
continue
|
||||
}
|
||||
mech := strings.TrimPrefix(string(c), "AUTH=")
|
||||
l = append(l, mech)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// AppendLimit checks the APPENDLIMIT capability.
|
||||
//
|
||||
// If the server supports APPENDLIMIT, ok is true. If the server doesn't have
|
||||
// the same upload limit for all mailboxes, limit is nil and per-mailbox
|
||||
// limits must be queried via STATUS.
|
||||
func (set CapSet) AppendLimit() (limit *uint32, ok bool) {
|
||||
if set.has(CapAppendLimit) {
|
||||
return nil, true
|
||||
}
|
||||
|
||||
for c := range set {
|
||||
if !strings.HasPrefix(string(c), "APPENDLIMIT=") {
|
||||
continue
|
||||
}
|
||||
|
||||
limitStr := strings.TrimPrefix(string(c), "APPENDLIMIT=")
|
||||
limit64, err := strconv.ParseUint(limitStr, 10, 32)
|
||||
if err == nil && limit64 > 0 {
|
||||
limit32 := uint32(limit64)
|
||||
return &limit32, true
|
||||
}
|
||||
}
|
||||
|
||||
limit32 := ^uint32(0)
|
||||
return &limit32, false
|
||||
}
|
||||
|
||||
// QuotaResourceTypes returns the list of supported QUOTA resource types.
|
||||
func (set CapSet) QuotaResourceTypes() []QuotaResourceType {
|
||||
var l []QuotaResourceType
|
||||
for c := range set {
|
||||
if !strings.HasPrefix(string(c), "QUOTA=RES-") {
|
||||
continue
|
||||
}
|
||||
t := strings.TrimPrefix(string(c), "QUOTA=RES-")
|
||||
l = append(l, QuotaResourceType(t))
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// ThreadAlgorithms returns the list of supported threading algorithms.
|
||||
func (set CapSet) ThreadAlgorithms() []ThreadAlgorithm {
|
||||
var l []ThreadAlgorithm
|
||||
for c := range set {
|
||||
if !strings.HasPrefix(string(c), "THREAD=") {
|
||||
continue
|
||||
}
|
||||
alg := strings.TrimPrefix(string(c), "THREAD=")
|
||||
l = append(l, ThreadAlgorithm(alg))
|
||||
}
|
||||
return l
|
||||
}
|
||||
Reference in New Issue
Block a user