<commit_before>//
//  SendGrid.swift
//  SendGrid-Swift
//
//  Created by <NAME> on 6/18/14.
//  Copyright (c) 2014 SendGrid. All rights reserved.
//

import Foundation

class SendGrid {
    
    // MARK: VERSION
    //=========================================================================
    class var version: String {
        return "0.0.1"
    }
    
    // MARK: PROPERTIES
    //=========================================================================
    
    let username: String
    let password: String
    
    // MARK: INITIALIZATION
    //=========================================================================
    
    init(username: String, password: String) {
        self.username = username;
        self.password = password;
    }
    
    // MARK: FUNCTIONS
    //=========================================================================
    
    func send(email: SendGrid.Email, completionHandler: ((NSURLResponse!, NSData!, NSError!) -> Void)?) {
        let url = NSURL(string: "https://api.sendgrid.com/api/mail.send.json")!
        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"
        
        // BODY
        var params = [String:AnyObject]()
        if let apiUser = self.username.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
            params["api_user"] = apiUser
        }
        
        if let apiKey = self.password.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
            params["api_key"] = apiKey
        }
        
        var addToParamsIfPresent = { (key: String, param: AnyObject?) -> Bool in
            if let p: AnyObject = param {
                params[key] = p
                return true
            }
            return false
        }
        
        if !addToParamsIfPresent("from", email.from) {
            Logger.error("SendGrid send: Could not send message due to required `from` parameter missing.")
            return
        }
        
        addToParamsIfPresent("fromname", email.fromname)
        
        if email.hasRecipientsInSmtpApi && email.smtpapi.to != nil && countElements(email.smtpapi.to!) > 0 {
            params["to"] = email.from!
        } else if !email.hasRecipientsInSmtpApi && email.to != nil && countElements(email.to!) > 0 {
            params["to"] = email.to!
        } else {
            Logger.error("SendGrid send: Could not send message as no recipients were specified.")
            return
        }
        
        addToParamsIfPresent("toname", email.toname)
        
        if !addToParamsIfPresent("subject", email.subject) {
            Logger.error("SendGrid send: Could not send message - a subject is required.")
            return
        }
        
        addToParamsIfPresent("text", email.text)
        addToParamsIfPresent("html", email.html)
        addToParamsIfPresent("cc", email.cc)
        addToParamsIfPresent("bcc", email.bcc)
        addToParamsIfPresent("replyto", email.replyto)
        addToParamsIfPresent("headers", email.headers)
        
        var body = NSMutableData()
        let boundary = "0xKhTmLbOuNdArY"
        var contentType = "multipart/form-data; boundary=\(boundary)"
        request.addValue(contentType, forHTTPHeaderField: "Content-Type")
        
        var addBoundary = { () -> Void in
            var b = "--\(boundary)\r\n"
            if let data = b.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                body.appendData(data)
            }
        }
        
        var addDisposition: ((param: String, filename: String?) -> Void) = { (param, filename) -> Void in
            var d = "Content-Disposition: form-data; name=\"\(param)\";"
            if let f = filename {
                d += " filename=\"\(filename)\""
            }
            d += "\r\n\r\n"
            if let data = d.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                body.appendData(data)
            }
        }
        
        var addParamValue: ((value: String) -> Void) = { (value) -> Void in
            var v = "\(value)\r\n"
            if let data = v.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                body.appendData(data)
            }
        }
        
        for (paramName, paramValue) in params {
            if let arr = paramValue as? [String] {
                for value in arr {
                    addBoundary()
                    addDisposition(param: "\(paramName)[]", filename: nil)
                    addParamValue(value: value)
                }
            } else {
                addBoundary()
                addDisposition(param: paramName, filename: nil)
                if paramName == "headers" {
                    var error: NSError?
                    var data = NSJSONSerialization.dataWithJSONObject(paramValue, options: nil, error: &error)
                    if let err = error {
                        Logger.error("Error converting headers to JSON - \(err.localizedDescription)")
                    } else if let d = data {
                        if let json = NSString(data: d, encoding: NSUTF8StringEncoding) {
                            addParamValue(value: json)
                        }
                    }
                } else if let value = paramValue as? String {
                    addParamValue(value: value)
                }
            }
        }
        
        if let cids = email.content {
            for (filename, id) in cids {
                addBoundary()
                addDisposition(param: "content[\(filename)]", filename: nil)
                addParamValue(value: id)
            }
        }
        
        if let files = email.attachments {
            for (file, data) in files {
                addBoundary()
                addDisposition(param: "files[\(file)]", filename: file)
                if let data = "Content-Type: application/octet-stream\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                    body.appendData(data)
                }
                body.appendData(data)
            }
        }
        
        if let data = "--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
            body.appendData(data)
        }
        
        //println(NSString(data: body, encoding: NSUTF8StringEncoding)!)
        
        request.HTTPBody = body
        let queue:NSOperationQueue = NSOperationQueue()
        NSURLConnection.sendAsynchronousRequest(request, queue: queue) { (response, data, error) -> Void in
            if let handler = completionHandler {
                handler(response, data, error)
            }
        }
    }
    
    
    class Email {
        
        // MARK: PROPERTIES<commit_msg>Support for attachments and CIDs<commit_after>//
//  SendGrid.swift
//  SendGrid-Swift
//
//  Created by <NAME> on 6/18/14.
//  Copyright (c) 2014 SendGrid. All rights reserved.
//

import Foundation

class SendGrid {
    
    // MARK: VERSION
    //=========================================================================
    class var version: String {
        return "0.0.1"
    }
    
    // MARK: PROPERTIES
    //=========================================================================
    
    let username: String
    let password: String
    
    // MARK: INITIALIZATION
    //=========================================================================
    
    init(username: String, password: String) {
        self.username = username;
        self.password = password;
    }
    
    // MARK: FUNCTIONS
    //=========================================================================
    
    func send(email: SendGrid.Email, completionHandler: ((NSURLResponse!, NSData!, NSError!) -> Void)?) {
        let url = NSURL(string: "https://api.sendgrid.com/api/mail.send.json")!
        let request = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"
        
        // BODY
        var params = [String:AnyObject]()
        if let apiUser = self.username.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
            params["api_user"] = apiUser
        }
        
        if let apiKey = self.password.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
            params["api_key"] = apiKey
        }
        
        var addToParamsIfPresent = { (key: String, param: AnyObject?) -> Bool in
            if let p: AnyObject = param {
                params[key] = p
                return true
            }
            return false
        }
        
        if !addToParamsIfPresent("from", email.from) {
            Logger.error("SendGrid send: Could not send message due to required `from` parameter missing.")
            return
        }
        
        addToParamsIfPresent("fromname", email.fromname)
        
        if email.hasRecipientsInSmtpApi && email.smtpapi.to != nil && countElements(email.smtpapi.to!) > 0 {
            params["to"] = email.from!
        } else if !email.hasRecipientsInSmtpApi && email.to != nil && countElements(email.to!) > 0 {
            params["to"] = email.to!
        } else {
            Logger.error("SendGrid send: Could not send message as no recipients were specified.")
            return
        }
        
        addToParamsIfPresent("toname", email.toname)
        
        if !addToParamsIfPresent("subject", email.subject) {
            Logger.error("SendGrid send: Could not send message - a subject is required.")
            return
        }
        
        addToParamsIfPresent("text", email.text)
        addToParamsIfPresent("html", email.html)
        addToParamsIfPresent("cc", email.cc)
        addToParamsIfPresent("bcc", email.bcc)
        addToParamsIfPresent("replyto", email.replyto)
        addToParamsIfPresent("headers", email.headers)
        
        var body = NSMutableData()
        let boundary = "0xKhTmLbOuNdArY"
        var contentType = "multipart/form-data; boundary=\(boundary)"
        request.addValue(contentType, forHTTPHeaderField: "Content-Type")
        
        var addBoundary = { () -> Void in
            var b = "--\(boundary)\r\n"
            if let data = b.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                body.appendData(data)
            }
        }
        
        var addDisposition: ((param: String, filename: String?) -> Void) = { (param, filename) -> Void in
            var d = "Content-Disposition: form-data; name=\"\(param)\""
            if let f = filename {
                d += "; filename=\"\(filename)\""
            }
            d += "\r\n\r\n"
            if let data = d.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                body.appendData(data)
            }
        }
        
        var addParamValue: ((value: String) -> Void) = { (value) -> Void in
            var v = "\(value)\r\n"
            if let data = v.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                body.appendData(data)
            }
        }
        
        for (paramName, paramValue) in params {
            if let arr = paramValue as? [String] {
                for value in arr {
                    addBoundary()
                    addDisposition(param: "\(paramName)[]", filename: nil)
                    addParamValue(value: value)
                }
            } else {
                addBoundary()
                addDisposition(param: paramName, filename: nil)
                if paramName == "headers" {
                    var error: NSError?
                    var data = NSJSONSerialization.dataWithJSONObject(paramValue, options: nil, error: &error)
                    if let err = error {
                        Logger.error("Error converting headers to JSON - \(err.localizedDescription)")
                    } else if let d = data {
                        if let json = NSString(data: d, encoding: NSUTF8StringEncoding) {
                            addParamValue(value: json)
                        }
                    }
                } else if let value = paramValue as? String {
                    addParamValue(value: value)
                }
            }
        }
        
        if email.smtpapi.hasSmtpApi {
            addBoundary()
            addDisposition(param: "x-smtpapi", filename: nil)
            addParamValue(value: email.smtpapi.jsonValue)
        }
        
        if let cids = email.content {
            for (filename, id) in cids {
                addBoundary()
                addDisposition(param: "content[\(filename)]", filename: nil)
                addParamValue(value: id)
            }
        }
        
        if let files = email.attachments {
            for (file, data) in files {
                addBoundary()
                addDisposition(param: "files[\(file)]", filename: file)
                if let d = "Content-Type: application/octet-stream\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
                   // body.appendData(d)
                }
                body.appendData(data)
            }
        }
        
        if let data = "--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
            body.appendData(data)
        }
        
        //println(NSString(data: body, encoding: NSUTF8StringEncoding)!)
        
        request.HTTPBody = body
        let queue:NSOperationQueue = NSOperationQueue()
        NSURLConnection.sendAsynchronousRequest(request, queue: queue) { (response, data, error) -> Void in
            if let handler = completionHandler {
                handler(response, data, error)
            }
        }
    }
    
    
    class Email {
        
        // MARK: PROPERTIES
{'fraction_non_alphanumeric': 0.1423931870669746, 'fraction_numerical': 0.003464203233256351, 'mean_word_length': 1.710680751173709, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 25, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1335729', 'n_tokens_mistral': 3786, 'n_tokens_neox': 3563, 'n_words': 812}