charset.go raw

   1  package message
   2  
   3  import (
   4  	"errors"
   5  	"fmt"
   6  	"io"
   7  	"mime"
   8  	"strings"
   9  )
  10  
  11  type UnknownCharsetError struct {
  12  	e error
  13  }
  14  
  15  func (u UnknownCharsetError) Unwrap() error { return u.e }
  16  
  17  func (u UnknownCharsetError) Error() string {
  18  	return "unknown charset: " + u.e.Error()
  19  }
  20  
  21  // IsUnknownCharset returns a boolean indicating whether the error is known to
  22  // report that the charset advertised by the entity is unknown.
  23  func IsUnknownCharset(err error) bool {
  24  	return errors.As(err, new(UnknownCharsetError))
  25  }
  26  
  27  // CharsetReader, if non-nil, defines a function to generate charset-conversion
  28  // readers, converting from the provided charset into UTF-8. Charsets are always
  29  // lower-case. utf-8 and us-ascii charsets are handled by default. One of the
  30  // the CharsetReader's result values must be non-nil.
  31  //
  32  // Importing github.com/emersion/go-message/charset will set CharsetReader to
  33  // a function that handles most common charsets. Alternatively, CharsetReader
  34  // can be set to e.g. golang.org/x/net/html/charset.NewReaderLabel.
  35  var CharsetReader func(charset string, input io.Reader) (io.Reader, error)
  36  
  37  // charsetReader calls CharsetReader if non-nil.
  38  func charsetReader(charset string, input io.Reader) (io.Reader, error) {
  39  	charset = strings.ToLower(charset)
  40  	if charset == "utf-8" || charset == "us-ascii" {
  41  		return input, nil
  42  	}
  43  	if CharsetReader != nil {
  44  		r, err := CharsetReader(charset, input)
  45  		if err != nil {
  46  			return r, UnknownCharsetError{err}
  47  		}
  48  		return r, nil
  49  	}
  50  	return input, UnknownCharsetError{fmt.Errorf("message: unhandled charset %q", charset)}
  51  }
  52  
  53  // decodeHeader decodes an internationalized header field. If it fails, it
  54  // returns the input string and the error.
  55  func decodeHeader(s string) (string, error) {
  56  	wordDecoder := mime.WordDecoder{CharsetReader: charsetReader}
  57  	dec, err := wordDecoder.DecodeHeader(s)
  58  	if err != nil {
  59  		return s, err
  60  	}
  61  	return dec, nil
  62  }
  63  
  64  func encodeHeader(s string) string {
  65  	return mime.QEncoding.Encode("utf-8", s)
  66  }
  67