Skip to content

Commit

Permalink
fix(attachments:sandbox): fix the empty attachment bug on macos
Browse files Browse the repository at this point in the history
when having a sandboxed app, and using NSOpenPanel for letting users the selecting a file, the attachments did contain sizeof file times zero bytes.

Using the FileManager to access the file contents did solve the problem.

Also the base64 and cutting off after n characters is now simplified
  • Loading branch information
sassman committed Apr 24, 2020
1 parent 4937eca commit b258e7a
Showing 1 changed file with 56 additions and 21 deletions.
77 changes: 56 additions & 21 deletions Sources/PerfectSMTP/PerfectSMTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public enum SMTPError:Error {
case INVALID_PROTOCOL
/// base64 failed
case INVALID_ENCRYPTION

case general(Int, String)
}

Expand Down Expand Up @@ -90,7 +90,7 @@ extension String {
}
return nil
}

/// get RFC 5322-compliant date for email
static var rfc5322Date: String {
let dateFormatter = DateFormatter()
Expand All @@ -99,7 +99,7 @@ extension String {
let compliantDate = dateFormatter.string(from: Date())
return compliantDate
}

/// convert a recipient to standard email format: "Full Name"<[email protected]>
/// - parameters:
/// - recipient: the email receiver name / address structure
Expand All @@ -115,14 +115,14 @@ extension String {
}
}
}

/// convert a group of recipients into an address list, joined by comma
/// - parameters:
/// - recipients: array of recipient
init(recipients: [Recipient]) {
self = recipients.map{String(recipient: $0)}.joined(separator: ", ")
}

/// MIME mail header: To/Cc/Bcc + recipients
/// - parameters:
/// - prefix: To / Cc or Bcc
Expand All @@ -131,7 +131,7 @@ extension String {
let r = String(recipients: recipients)
self = "\(prefix): \(r)\r\n"
}

/// get the address info from a recipient, i.e, someone@somewhere -> @somewhere
var emailSuffix: String {
get {
Expand All @@ -145,15 +145,15 @@ extension String {
#endif
}
}

/// extract file name from a full path
var fileNameWithoutPath: String {
get {
let segments = self.split(separator: "/")
return String(segments[segments.count - 1])
}
}

/// extract file suffix from a file name
var suffix: String {
get {
Expand All @@ -167,11 +167,11 @@ private struct EmailBodyGen: CURLRequestBodyGenerator {
let bytes: [UInt8]
var offset = 0
var contentLength: Int? { return bytes.count }

init(_ string: String) {
bytes = Array(string.utf8)
}

mutating func next(byteCount: Int) -> [UInt8]? {
let count = bytes.count
let remaining = count - offset
Expand Down Expand Up @@ -215,16 +215,16 @@ public class EMail {
public var connectTimeoutSeconds: Int = 15
/// for debugging purposes
public var debug = false

var progress = 0

/// constructor
/// - parameters:
/// - client: SMTP client for login info
public init(client: SMTPClient) {
self.client = client
}

/// transform an attachment into an MIME part
/// - parameters:
/// - path: local full path
Expand Down Expand Up @@ -255,6 +255,7 @@ public class EMail {
return ""
}
}
<<<<<<< Updated upstream

/// encode a file by base64 method
/// - parameters:
Expand Down Expand Up @@ -284,12 +285,46 @@ public class EMail {
wraped.append(contentsOf: buffer[cursor ..< mark])
wraped.append(contentsOf: newline)
cursor += szline
=======

/// https://www.ietf.org/rfc/rfc2047.txt
/// encode a string to url encode conform string
/// - parameters:
/// - something: a string to be encoded
/// - returns:
/// base64 but rfc2047 conform string
private func contentTypefilenameParameter(something: String) -> String {
let something = something.base64Encoded()!
// from rfc2047 encoded-word = "=?" charset "?" encoding "?" encoded-text "?="
// Q is "Quoted-Printable" content-transfer-encoding defined in RFC 2045
// B is Base64
return "=?utf-8?B?\(something)?="
}
fd.close()
wraped.append(0)
return String(validatingUTF8: wraped)
}


/// https://tools.ietf.org/html/rfc2231
/// encode a string to url encode conform string
/// - parameters:
/// - something: a string to be encoded
/// - returns:
/// url encoded string
private func paramterRfc2231(something: String) -> String {
let something = something.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
return "utf-8''\(something)"
}

/// encode a file by base64 method
/// - parameters:
/// - path: full path of the file to encode
/// - returns:
/// base64 encoded text WITH A TRAILING NEWLINE
@discardableResult
private func encode(path: String) throws -> String? {
return FileManager.default.contents(atPath: path)?
.base64EncodedString(options:
.init(arrayLiteral: [.endLineWithCarriageReturn, .endLineWithLineFeed, .lineLength76Characters]))
>>>>>>> Stashed changes
}

private func makeBody() throws -> (String, String) {
// !FIX! quoted printable?
var body = "Date: \(String.rfc5322Date)\r\n"
Expand Down Expand Up @@ -320,7 +355,7 @@ public class EMail {
body += "In-Reply-To: \(reference)\r\n"
body += "References: \(reference)\r\n"
}

// add the email title
if subject.isEmpty {
throw SMTPError.INVALID_SUBJECT
Expand Down Expand Up @@ -358,7 +393,7 @@ public class EMail {
body += "--\(boundary)--\r\n"
return (body, uuid)
}

private func getResponse(_ body : String) throws -> CURLResponse {
let recipients = to + cc + bcc
guard recipients.count > 0 else {
Expand All @@ -376,7 +411,7 @@ public class EMail {
let request = CURLRequest(client.url, options: options)
return try request.perform()
}

/// send an email with the current settings
/// - parameters:
/// - completion: once sent, callback to the main thread with curl code, header & body string
Expand Down

0 comments on commit b258e7a

Please sign in to comment.