<?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 $_attachments = 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->_attachments = 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 attachment
     *
     * @access  public
     * @return  void
     */
    function attach($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->_attachments[] = 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->_attachments) > 0) {
            $data['Attachments'] = $this->_attachments;
        }

        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) AND $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_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)];
    }
}