2023-01-15 16:14:19 +01:00
|
|
|
// SPDX-FileCopyrightText: 2022-2023 The go-mail Authors
|
2022-08-14 12:07:59 +02:00
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2022-08-14 12:06:26 +02:00
|
|
|
package mail
|
|
|
|
|
2022-09-08 11:47:11 +02:00
|
|
|
import (
|
2024-08-16 10:16:53 +02:00
|
|
|
"errors"
|
2022-09-08 11:47:11 +02:00
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2024-10-04 19:50:10 +02:00
|
|
|
// newlineBytes is a byte slice representation of the SingleNewLine constant used for line breaking
|
|
|
|
// in encoding processes.
|
|
|
|
var newlineBytes = []byte(SingleNewLine)
|
|
|
|
|
|
|
|
// ErrNoOutWriter is the error message returned when no io.Writer is set for Base64LineBreaker.
|
2022-09-08 15:43:14 +02:00
|
|
|
const ErrNoOutWriter = "no io.Writer set for Base64LineBreaker"
|
|
|
|
|
2024-10-06 12:39:02 +02:00
|
|
|
// Base64LineBreaker handles base64 encoding with the insertion of new lines after a certain number
|
|
|
|
// of characters.
|
2024-10-04 19:50:10 +02:00
|
|
|
//
|
2024-10-06 12:39:02 +02:00
|
|
|
// This struct is used to manage base64 encoding while ensuring that new lines are inserted after
|
|
|
|
// reaching a specific line length. It satisfies the io.WriteCloser interface.
|
|
|
|
//
|
|
|
|
// References:
|
|
|
|
// - https://datatracker.ietf.org/doc/html/rfc2045 (Base64 and line length limitations)
|
2022-08-14 12:06:26 +02:00
|
|
|
type Base64LineBreaker struct {
|
|
|
|
line [MaxBodyLength]byte
|
|
|
|
used int
|
|
|
|
out io.Writer
|
|
|
|
}
|
|
|
|
|
2024-10-04 19:50:10 +02:00
|
|
|
// Write writes data to the Base64LineBreaker, ensuring lines do not exceed MaxBodyLength.
|
2024-10-06 12:39:02 +02:00
|
|
|
//
|
|
|
|
// This method writes the provided data to the Base64LineBreaker. It ensures that the written
|
|
|
|
// lines do not exceed the MaxBodyLength. If the data exceeds the limit, it handles the
|
|
|
|
// continuation by splitting the data and writing new lines as necessary.
|
|
|
|
//
|
|
|
|
// Parameters:
|
|
|
|
// - data: A byte slice containing the data to be written.
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
// - numBytes: The number of bytes written.
|
|
|
|
// - err: An error if one occurred during the write operation.
|
2024-02-24 21:38:20 +01:00
|
|
|
func (l *Base64LineBreaker) Write(data []byte) (numBytes int, err error) {
|
2022-09-08 11:47:11 +02:00
|
|
|
if l.out == nil {
|
2024-08-16 10:16:53 +02:00
|
|
|
err = errors.New(ErrNoOutWriter)
|
2022-09-08 15:40:42 +02:00
|
|
|
return
|
2022-09-08 11:47:11 +02:00
|
|
|
}
|
2024-02-24 21:38:20 +01:00
|
|
|
if l.used+len(data) < MaxBodyLength {
|
|
|
|
copy(l.line[l.used:], data)
|
|
|
|
l.used += len(data)
|
|
|
|
return len(data), nil
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
|
|
|
|
2024-02-24 21:38:20 +01:00
|
|
|
numBytes, err = l.out.Write(l.line[0:l.used])
|
2022-08-14 12:06:26 +02:00
|
|
|
if err != nil {
|
2022-09-08 15:40:42 +02:00
|
|
|
return
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
|
|
|
excess := MaxBodyLength - l.used
|
|
|
|
l.used = 0
|
|
|
|
|
2024-02-24 21:38:20 +01:00
|
|
|
numBytes, err = l.out.Write(data[0:excess])
|
2022-08-14 12:06:26 +02:00
|
|
|
if err != nil {
|
2022-09-08 15:40:42 +02:00
|
|
|
return
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
|
|
|
|
2024-02-24 21:38:20 +01:00
|
|
|
numBytes, err = l.out.Write(newlineBytes)
|
2022-08-14 12:06:26 +02:00
|
|
|
if err != nil {
|
2022-09-08 15:40:42 +02:00
|
|
|
return
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
|
|
|
|
2024-02-24 21:38:20 +01:00
|
|
|
return l.Write(data[excess:])
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
|
|
|
|
2024-10-04 19:50:10 +02:00
|
|
|
// Close finalizes the Base64LineBreaker, writing any remaining buffered data and appending a newline.
|
2024-10-06 12:39:02 +02:00
|
|
|
//
|
|
|
|
// This method ensures that any remaining data in the buffer is written to the output and appends
|
|
|
|
// a newline. It is used to finalize the Base64LineBreaker and should be called when no more data
|
|
|
|
// is expected to be written.
|
|
|
|
//
|
|
|
|
// Returns:
|
|
|
|
// - err: An error if one occurred during the final write operation.
|
2022-08-14 12:06:26 +02:00
|
|
|
func (l *Base64LineBreaker) Close() (err error) {
|
|
|
|
if l.used > 0 {
|
|
|
|
_, err = l.out.Write(l.line[0:l.used])
|
|
|
|
if err != nil {
|
2022-09-08 15:40:42 +02:00
|
|
|
return
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
2024-02-24 21:38:20 +01:00
|
|
|
_, err = l.out.Write(newlineBytes)
|
2022-08-14 12:06:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|