1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package address2021import (22 "errors"2324 "golang.org/x/net/idna"25 "golang.org/x/text/unicode/norm"26)2728var ErrUnicodeMailbox = errors.New("address: cannot convert the Unicode local-part to the ACE form")2930// ToASCII converts the domain part of the email address to the A-label form and31// fails with ErrUnicodeMailbox if the local-part contains non-ASCII characters.32func ToASCII(addr string) (string, error) {33 mbox, domain, err := Split(addr)34 if err != nil {35 return addr, err36 }3738 for _, ch := range mbox {39 if ch > 128 {40 return addr, ErrUnicodeMailbox41 }42 }4344 if domain == "" {45 return mbox, nil46 }4748 aDomain, err := idna.ToASCII(domain)49 if err != nil {50 return addr, err51 }5253 return mbox + "@" + aDomain, nil54}5556// ToUnicode converts the domain part of the email address to the U-label form.57func ToUnicode(addr string) (string, error) {58 mbox, domain, err := Split(addr)59 if err != nil {60 return norm.NFC.String(addr), err61 }6263 if domain == "" {64 return mbox, nil65 }6667 uDomain, err := idna.ToUnicode(domain)68 if err != nil {69 return norm.NFC.String(addr), err70 }7172 return mbox + "@" + norm.NFC.String(uDomain), nil73}7475// SelectIDNA is a convenience function for conversion of domains in the email76// addresses to/from the Punycode form.77//78// ulabel=true => ToUnicode is used.79// ulabel=false => ToASCII is used.80func SelectIDNA(ulabel bool, addr string) (string, error) {81 if ulabel {82 return ToUnicode(addr)83 }84 return ToASCII(addr)85}