// Copyright (c) 2020 Proton Technologies AG // // This file is part of ProtonMail Bridge. // // ProtonMail Bridge is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ProtonMail Bridge is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . package transfer import ( "bufio" "bytes" "io" "mime" "os" "strings" ) type stringSet map[string]bool const xGmailLabelsHeader = "X-Gmail-Labels" // filteredOutGmailLabels is set of labels which we don't want to show to users // as they might be auto-generated by Gmail and unwanted. var filteredOutGmailLabels = []string{ //nolint[gochecknoglobals] "Unread", "Opened", "IMAP_Junk", "IMAP_NonJunk", "IMAP_NotJunk", "IMAP_$NotJunk", } func getGmailLabelsFromMboxFile(filePath string) (stringSet, error) { f, err := os.Open(filePath) //nolint[gosec] if err != nil { return nil, err } return getGmailLabelsFromMboxReader(f) } func getGmailLabelsFromMboxReader(f io.Reader) (stringSet, error) { allLabels := stringSet{} // Scanner is not used as it does not support long lines and some mbox // files contain very long lines even though that should not be happening. r := bufio.NewReader(f) for { b, isPrefix, err := r.ReadLine() if err == io.EOF { break } if err != nil { return nil, err } for isPrefix { _, isPrefix, err = r.ReadLine() if err != nil { break } } if bytes.HasPrefix(b, []byte(xGmailLabelsHeader)) { for label := range getGmailLabelsFromValue(string(b)) { allLabels[label] = true } } } return allLabels, nil } func getGmailLabelsFromMessage(body []byte) (stringSet, error) { header, err := getMessageHeader(body) if err != nil { return nil, err } labels := header.Get(xGmailLabelsHeader) return getGmailLabelsFromValue(labels), nil } func getGmailLabelsFromValue(value string) stringSet { value = strings.TrimPrefix(value, xGmailLabelsHeader+":") if decoded, err := new(mime.WordDecoder).DecodeHeader(value); err != nil { log.WithError(err).Error("Failed to decode header") } else { value = decoded } labels := stringSet{} for _, label := range strings.Split(value, ",") { label = strings.TrimSpace(label) if label == "" { continue } skip := false for _, filteredOutLabel := range filteredOutGmailLabels { if label == filteredOutLabel { skip = true break } } if skip { continue } labels[label] = true } return labels }