<?php

if (!defined('BASEPATH'))
    exit('No direct script access allowed');

/**
 * Postmark Email Library
 *
 * Permits email to be sent using Postmarkapp.com's Servers
 *
 * @category    Libraries
 * @author      Based on work by János Rusiczki & Markus Hedlund’s.
 * @modified    Heavily Modified by Zack Kitzmiller
 * @link        http://www.github.com/zackkitzmiller/postmark-codeigniter
 */
class Postmark
{

    //private
    var $CI;
    var $api_key = '';
    var $validation = FALSE;
    var $strip_html = FALSE;
    var $develop = FALSE;
    var $from_name;
    var $from_address;
    var $_reply_to_name;
    var $_reply_to_address;
    var $_to_name;
    var $_to_address;
    var $_cc_name;
    var $_cc_address;
    var $_bcc_address;
    var $_subject;
    var $_message_plain;
    var $_message_html;
    var $_tag;
    var $_resourcements = array();

    /**
     * Constructor
     *
     * @access  public
     * @param   array   initialization parameters
     */
    function Postmark($params = array())
    {
        $this->CI = &get_instance();

        if (count($params) > 0) {
            $this->initialize($params);
        }

        if ($this->develop == TRUE) {
            $this->api_key = 'POSTMARK_API_TEST';
        }

        log_message('debug', 'Postmark Class Initialized');
    }

    // --------------------------------------------------------------------

    /**
     * Initialize Preferences
     *
     * @access  public
     * @param   array   initialization parameters
     * @return  void
     */
    function initialize($params)
    {
        $this->clear();
        if (count($params) > 0) {
            foreach ($params as $key => $value) {
                if (isset($this->$key)) {
                    $this->$key = $value;
                }
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Clear the Email Data
     *
     * @access  public
     * @return  void
     */
    function clear()
    {

        $this->from_name = '';
        $this->from_address = '';

        $this->_to_name = '';
        $this->_to_address = '';

        $this->_cc_name = '';
        $this->_cc_address = '';

        $this->_subject = '';
        $this->_message_plain = '';
        $this->_message_html = '';

        $this->_tag = '';

        $this->_resourcements = array();
    }

    // --------------------------------------------------------------------

    /**
     * Set Email FROM address
     *
     * This could also be set in the config file
     *
     * TODO:
     * Validate Email Addresses ala CodeIgniter's Email Class
     *
     * @access  public
     * @return  void
     */
    function from($address, $name = null)
    {

        if (!$this->validation == TRUE) {
            $this->from_address = $address;
            $this->from_name = $name;
        } else {
            if ($this->_validate_email($address)) {
                $this->from_address = $address;
                $this->from_name = $name;
            } else {
                show_error('You have entered an invalid sender address.');
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set Email TO address
     *
     * TODO:
     * Validate Email Addresses ala CodeIgniter's Email Class
     *
     * @access  public
     * @return  void
     */
    function to($address, $name = null)
    {

        if (!$this->validation == TRUE) {
            $this->_to_address = $address;
            $this->_to_name = $name;
        } else {
            if ($this->_validate_email($address)) {
                $this->_to_address = $address;
                $this->_to_name = $name;
            } else {
                show_error('You have entered an invalid recipient address.');
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set Email ReplyTo address
     *
     * TODO:
     * Validate Email Addresses ala CodeIgniter's Email Class
     *
     * @access  public
     * @return  void
     */
    function reply_to($address, $name = null)
    {

        if (!$this->validation == TRUE) {
            $this->_reply_to_address = $address;
            $this->_reply_to_name = $name;
        } else {
            if ($this->_validate_email($address)) {
                $this->_reply_to_address = $address;
                $this->_reply_to_name = $name;
            } else {
                show_error('You have entered an invalid reply to address.');
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set Email CC address
     *
     * TODO:
     * Validate Email Addresses ala CodeIgniter's Email Class
     *
     * @access  public
     * @return  void
     */
    function cc($address, $name = null)
    {

        if (!$this->validation == TRUE) {
            $this->_cc_address = $address;
            $this->_cc_name = $name;
        } else {
            if ($this->_validate_email($address)) {
                $this->_cc_address = $address;
                $this->_cc_name = $name;
            } else {
                show_error('You have entered an invalid recipient address.');
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set Email BCC address
     *
     * TODO:
     * Validate Email Addresses ala CodeIgniter's Email Class
     *
     * @access  public
     * @return  void
     * @author  Adam Jackett, based on cc method
     */
    function bcc($address)
    {

        if (!$this->validation == TRUE) {
            $this->_bcc_address = $address;
        } else {
            if ($this->_validate_email($address)) {
                $this->_bcc_address = $address;
            } else {
                show_error('You have entered an invalid recipient address.');
            }
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set Email Subject
     *
     * @access  public
     * @return  void
     */
    function subject($subject)
    {
        $this->_subject = $subject;
    }

    // --------------------------------------------------------------------

    /**
     * Set Tag
     *
     * @access  public
     * @return  void
     */
    function tag($tag)
    {
        $this->_tag = $tag;
    }

    // --------------------------------------------------------------------

    /**
     * Set Email Message in Plain Text
     *
     * @access  public
     * @return  void
     */
    function message_plain($message)
    {
        if (!$this->strip_html) {
            $this->_message_plain = $message;
        } else {
            $this->_message_plain = $this->_strip_html($message);
        }
    }

    // --------------------------------------------------------------------

    /**
     * Set Email Message in HTML
     *
     * @access  public
     * @return  void
     */
    function message_html($message)
    {
        $this->_message_html = $message;
    }

    // --------------------------------------------------------------------

    /**
     * Add an resourcement
     *
     * @access  public
     * @return  void
     */
    function resource($file, $filename = FALSE)
    {
        $filesize = filesize($file) + 1;
        if (!$fp = fopen($file, FOPEN_READ)) {
            return FALSE;
        }

        $content = chunk_split(base64_encode(fread($fp, $filesize)));
        fclose($fp);

        if (!$filename)
            $filename = end(explode('/', $file));

        $this->_resourcements[] = array(
            'Name' => $filename,
            'Content' => $content,
            'ContentType' => $this->_mime_types(end(explode('.', basename($filename))))
        );

        return TRUE;
    }

    // --------------------------------------------------------------------
    /**
     * Private Function to prepare and send email
     */
    function _prepare_data()
    {
        $data = array();
        $data['Subject'] = $this->_subject;

        $data['From'] = is_null($this->from_name) ? $this->from_address : "{$this->from_name} <{$this->from_address}>";
        $data['To'] = is_null($this->_to_name) ? $this->_to_address : "{$this->_to_name} <{$this->_to_address}>";

        if (!is_null($this->_cc_address) && ($this->_cc_address != '')) {
            $data['Cc'] = is_null($this->_cc_name) ? $this->_cc_address : "{$this->_cc_name} <{$this->_cc_address}>";
        }

        if (!is_null($this->_bcc_address) && ($this->_bcc_address != '')) {
            $data['Bcc'] = $this->_bcc_address;
        }

        if (!is_null($this->_reply_to_address) && ($this->_reply_to_address != '')) {
            $data['ReplyTo'] = is_null($this->_reply_to_name) ? $this->_reply_to_address : "{$this->_reply_to_name} <{$this->_reply_to_address}>";
        }

        if (!is_null($this->_tag) && ($this->_tag != '')) {
            $data['tag'] = $this->_tag;
        }

        if (!is_null($this->_message_html)) {
            $data['HtmlBody'] = $this->_message_html;
        }

        if (!is_null($this->_message_plain)) {
            $data['TextBody'] = $this->_message_plain;
        }

        if (count($this->_resourcements) > 0) {
            $data['resourcements'] = $this->_resourcements;
        }

        return $data;
    }

    function send($from_address = null, $from_name = null, $to_address = null, $to_name = null, $subject = null, $message_plain = null, $message_html = null, $display_unprocessable_messages = FALSE)
    {

        if (!function_exists('curl_init')) {

            if (function_exists('log_message')) {
                log_message('error', 'Postmark - PHP was not built with cURL enabled. Rebuild PHP with --with-curl to use cURL.');
            }

            return false;
        }

        if (!is_null($from_address))
            $this->from($from_address, $from_name);
        if (!is_null($to_address))
            $this->to($to_address, $to_name);
        if (!is_null($subject))
            $this->subject($subject);
        if (!is_null($message_plain))
            $this->message_plain($message_plain);
        if (!is_null($message_html))
            $this->message_html($message_html);

        if (is_null($this->api_key)) {
            show_error("Postmark API key is not set!");
        }

        if (is_null($this->from_address)) {
            show_error("From address is not set!");
        }

        if (is_null($this->_to_address)) {
            show_error("To address is not set!");
        }

        if (is_null($this->_subject)) {
            show_error("Subject is not set!");
        }

        if (is_null($this->_message_plain) && is_null($this->_message_html)) {
            show_error("Please either set plain message, HTML message or both!");
        }

        $encoded_data = json_encode($this->_prepare_data());

        $headers = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'X-Postmark-Server-Token: ' . $this->api_key
        );

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, 'http://api.postmarkapp.com/email');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $return = curl_exec($ch);
        log_message('debug', 'POSTMARK JSON: ' . $encoded_data . "\nHeaders: \n\t" . implode("\n\t", $headers) . "\nReturn:\n$return");

        if (curl_error($ch) != '') {
            show_error(curl_error($ch));
        }

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        log_message('debug', 'POSTMARK http code:' . $httpCode);

        if ((intval($httpCode / 100) != 2) && $display_unprocessable_messages) {
            $message = json_decode($return)->Message;
            show_error('Error while mailing. Postmark returned HTTP code ' . $httpCode . ' with message "' . $message . '"');
        }
    }

    // --------------------------------------------------------------------

    /**
     * Email Validation
     *
     * @access  public
     * @param   string
     * @return  bool
     */
    function _validate_email($address)
    {
        $addresses = explode(',', $address);

        foreach ($addresses as $k => $v) {
            if (!preg_match("/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix", trim($v))) {
                return FALSE;
            }
        }

        return TRUE;
    }

    // --------------------------------------------------------------------

    /**
     * Strip Html
     *
     * @access  public
     * @param   string
     * @return  string
     */
    function _strip_html($message)
    {
        $message = preg_replace('/\<br(\s*)?\/?\>/i', "\n", $message);
        return strip_html_tags($message);
    }

    // --------------------------------------------------------------------

    /**
     * Mime Types
     *
     * @access  private
     * @param   string
     * @return  string
     */
    function _mime_types($ext = "")
    {
        $mimes = array('hqx' => 'application/mac-binhex40',
            'cpt' => 'application/mac-compactpro',
            'doc' => 'application/msword',
            'bin' => 'application/macbinary',
            'dms' => 'application/octet-stream',
            'lha' => 'application/octet-stream',
            'lzh' => 'application/octet-stream',
            'exe' => 'application/octet-stream',
            'class' => 'application/octet-stream',
            'psd' => 'application/octet-stream',
            'so' => 'application/octet-stream',
            'sea' => 'application/octet-stream',
            'dll' => 'application/octet-stream',
            'oda' => 'application/oda',
            'pdf' => 'application/pdf',
            'ai' => 'application/postscript',
            'eps' => 'application/postscript',
            'ps' => 'application/postscript',
            'smi' => 'application/smil',
            'smil' => 'application/smil',
            'mif' => 'application/vnd.mif',
            'xls' => 'application/vnd.ms-excel',
            'ppt' => 'application/vnd.ms-powerpoint',
            'wbxml' => 'application/vnd.wap.wbxml',
            'wmlc' => 'application/vnd.wap.wmlc',
            'dcr' => 'application/x-director',
            'dir' => 'application/x-director',
            'dxr' => 'application/x-director',
            'dvi' => 'application/x-dvi',
            'gtar' => 'application/x-gtar',
            'php' => 'application/x-httpd-php',
            'php4' => 'application/x-httpd-php',
            'php3' => 'application/x-httpd-php',
            'phtml' => 'application/x-httpd-php',
            'phps' => 'application/x-httpd-php-source',
            'js' => 'application/x-javascript',
            'swf' => 'application/x-shockwave-flash',
            'sit' => 'application/x-stuffit',
            'tar' => 'application/x-tar',
            'tgz' => 'application/x-tar',
            'xhtml' => 'application/xhtml+xml',
            'xht' => 'application/xhtml+xml',
            'zip' => 'application/zip',
            'mid' => 'audio/midi',
            'midi' => 'audio/midi',
            'mpga' => 'audio/mpeg',
            'mp2' => 'audio/mpeg',
            'mp3' => 'audio/mpeg',
            'aif' => 'audio/x-aiff',
            'aiff' => 'audio/x-aiff',
            'aifc' => 'audio/x-aiff',
            'ram' => 'audio/x-pn-realaudio',
            'rm' => 'audio/x-pn-realaudio',
            'rpm' => 'audio/x-pn-realaudio-plugin',
            'ra' => 'audio/x-realaudio',
            'rv' => 'video/vnd.rn-realvideo',
            'wav' => 'audio/x-wav',
            'bmp' => 'image/bmp',
            'gif' => 'image/gif',
            'jpeg' => 'image/jpeg',
            'jpg' => 'image/jpeg',
            'jpe' => 'image/jpeg',
            'png' => 'image/png',
            'tiff' => 'image/tiff',
            'tif' => 'image/tiff',
            'css' => 'text/css',
            'html' => 'text/html',
            'htm' => 'text/html',
            'shtml' => 'text/html',
            'txt' => 'text/plain',
            'text' => 'text/plain',
            'log' => 'text/plain',
            'rtx' => 'text/richtext',
            'rtf' => 'text/rtf',
            'xml' => 'text/xml',
            'xsl' => 'text/xml',
            'mpeg' => 'video/mpeg',
            'mpg' => 'video/mpeg',
            'mpe' => 'video/mpeg',
            'qt' => 'video/quicktime',
            'mov' => 'video/quicktime',
            'avi' => 'video/x-msvideo',
            'movie' => 'video/x-sgi-movie',
            'word' => 'application/msword',
            'xl' => 'application/excel',
            'eml' => 'message/rfc822'
        );

        return (!isset($mimes[strtolower($ext)])) ? "application/x-unknown-content-type" : $mimes[strtolower($ext)];
    }

}
