<?php
    
/**
    * o------------------------------------------------------------------------------o
    * | This package is licensed under the Phpguru license. A quick summary is       |
    * | that for commercial use, there is a small one-time licensing fee to pay. For |
    * | registered charities and educational institutes there is a reduced license   |
    * | fee available. You can read more  at:                                        |
    * |                                                                              |
    * |                  http://www.phpguru.org/static/license.html                  |
    * o------------------------------------------------------------------------------o
    */

require_once(dirname(__FILE__) . '/mimePart.php');

class 
Rmail
{
    
/**
    * The html part of the message
    * @var string
    */
    
private $html;

    
/**
    * The text part of the message(only used in TEXT only messages)
    * @private string
    */
    
private $text;

    
/**
    * The main body of the message after building
    * @private string
    */
    
private $output;

    
/**
    * An array of embedded images   /objects
    * @private array
    */
    
private $html_images;

    
/**
    * An array of recognised image types for the findHtmlImages() method
    * @private array
    */
    
private $image_types;

    
/**
    * Parameters that affect the build process
    * @private array
    */
    
private $build_params;

    
/**
    * Array of attachments
    * @private array
    */
    
private $attachments;

    
/**
    * The main message headers
    * @private array
    */
    
private $headers;
    
    
/**
    * The return path address. If not set the From:
    * address is used instead
    * @private string
    */
    
private $return_path;
    
    
/**
    * Array of information needed for smtp sending
    * @private array
    */
    
private $smtp_params;

    
/**
    * Sendmail path. Do not include -f
    * @private $sendmail_path
    */
    
private $sendmail_path;

    
/**
    * Constructor function.
    */
    
public function __construct()
    {
        
/**
        * Initialise some variables.
        */
        
$this->attachments   = array();
        
$this->html_images   = array();
        
$this->headers       = array();
        
$this->text          '';
        
$this->sendmail_path '/usr/lib/sendmail -ti';

        
/**
        * If you want the auto load functionality
        * to find other image/file types, add the
        * extension and content type here.
        */
        
$this->image_types = array('gif'  => 'image/gif',
                                   
'jpg'  => 'image/jpeg',
                                   
'jpeg' => 'image/jpeg',
                                   
'jpe'  => 'image/jpeg',
                                   
'bmp'  => 'image/bmp',
                                   
'png'  => 'image/png',
                                   
'tif'  => 'image/tiff',
                                   
'tiff' => 'image/tiff',
                                   
'swf'  => 'application/x-shockwave-flash');

        
/**
        * Set these up
        */
        
$this->build_params['html_encoding'] = new QPrintEncoding();
        
$this->build_params['text_encoding'] = new SevenBitEncoding();
        
$this->build_params['html_charset']  = 'ISO-8859-1';
        
$this->build_params['text_charset']  = 'ISO-8859-1';
        
$this->build_params['head_charset']  = 'ISO-8859-1';
        
$this->build_params['text_wrap']     = 998;

        
/**
        * Defaults for smtp sending
        */
        
if (!empty($_SERVER['HTTP_HOST'])) {
            
$helo $_SERVER['HTTP_HOST'];

        } elseif (!empty(
$_SERVER['SERVER_NAME'])) {
            
$helo $_SERVER['SERVER_NAME'];
        
        } else {
            
$helo 'localhost';
        }

        
$this->smtp_params['host'] = 'localhost';
        
$this->smtp_params['port'] = 25;
        
$this->smtp_params['helo'] = $helo;
        
$this->smtp_params['auth'] = false;
        
$this->smtp_params['user'] = '';
        
$this->smtp_params['pass'] = '';

        
/**
        * Make sure the MIME version header is first.
        */
        
$this->headers['MIME-Version'] = '1.0';
        
$this->headers['X-Mailer'] = 'Rmail <http://www.phpguru.org/>';
    }

    
/**
    * Accessor to set the CRLF style
    * 
    * @param string $crlf CRLF style to use.
    *                     Use \r\n for SMTP, and \n
    *                     for normal.
    */
    
public function setCRLF($crlf "\n")
    {
        if (!
defined('RMAIL_CRLF')) {
            
define('RMAIL_CRLF'$crlftrue);
        }

        if (!
defined('MAIL_MIMEPART_CRLF')) {
            
define('MAIL_MIMEPART_CRLF'$crlftrue);
        }
    }

    
/**
    * Accessor to set the SMTP parameters
    * 
    * @param string $host Hostname
    * @param string $port Port
    * @param string $helo HELO string to use
    * @param bool   $auth User authentication or not
    * @param string $user Username
    * @param string $pass Password
    */
    
public function setSMTPParams($host null$port null$helo null$auth null$user null$pass null)
    {
        if (!
is_null($host)) $this->smtp_params['host'] = $host;
        if (!
is_null($port)) $this->smtp_params['port'] = $port;
        if (!
is_null($helo)) $this->smtp_params['helo'] = $helo;
        if (!
is_null($auth)) $this->smtp_params['auth'] = $auth;
        if (!
is_null($user)) $this->smtp_params['user'] = $user;
        if (!
is_null($pass)) $this->smtp_params['pass'] = $pass;
    }

    
/**
    * Sets sendmail path and options (optionally) (when directly piping to sendmail)
    * 
    * @param string $path Path and options for sendmail command
    */
    
public function setSendmailPath($path)
    {
        
$this->sendmail_path $path;
    }

    
/**
    * Accessor function to set the text encoding
    * 
    * @param object $encoding Text encoding to use
    */
    
public function setTextEncoding(iEncoding $encoding)
    {
        
$this->build_params['text_encoding'] = $encoding;
    }

    
/**
    * Accessor function to set the HTML encoding
    * 
    * @param object $encoding HTML encoding to use
    */
    
public function setHTMLEncoding(iEncoding $encoding)
    {
        
$this->build_params['html_encoding'] = $encoding;
    }
    
    
/**
    * Accessor function to set the text charset
    * 
    * @param string $charset Character set to use
    */
    
public function setTextCharset($charset 'ISO-8859-1')
    {
        
$this->build_params['text_charset'] = $charset;
    }

    
/**
    * Accessor function to set the HTML charset
    * 
    * @param string $charset Character set to use
    */
    
public function setHTMLCharset($charset 'ISO-8859-1')
    {
        
$this->build_params['html_charset'] = $charset;
    }

    
/**
    * Accessor function to set the header encoding charset
    * 
    * @param string $charset Character set to use
    */
    
public function setHeadCharset($charset 'ISO-8859-1')
    {
        
$this->build_params['head_charset'] = $charset;
    }

    
/**
    * Accessor function to set the text wrap count
    * 
    * @param integer $count Point at which to wrap text
    */
    
public function setTextWrap($count 998)
    {
        
$this->build_params['text_wrap'] = $count;
    }

    
/**
    * Accessor to set a header
    * 
    * @param string $name  Name of header
    * @param string $value Value of header
    */
    
public function setHeader($name$value)
    {
        
$this->headers[$name] = $value;
    }
    
    
/**
    * Sets the delivery reciept address
    * 
    * @param string $email The address you want the delivery reciept
    *                      sent to. Note that this is sent at the
    *                      discretion of the recipient
    */
    
public function setReceipt($email)
    {
        
$this->headers['Disposition-Notification-To'] = $email;
    }

    
/**
    * Accessor to add a Subject: header
    * 
    * @param string $subject Subject to set
    */
    
public function setSubject($subject)
    {
        
$this->headers['Subject'] = $subject;
    }

    
/**
    * Accessor to add a From: header
    * 
    * @param string $from From address
    */
    
public function setFrom($from)
    {
        
$this->headers['From'] = $from;
    }
    
    
/**
    * Accessor to set priority. Priority given should be either
    * high, normal or low. Can also be specified numerically, 
    * being 1, 3 or 5 (respectively).
    * 
    * @param mixed $priority The priority to use.
    */
    
public function setPriority($priority 'normal')
    {
        switch (
strtolower($priority)) {
            case 
'high':
            case 
'1':
                
$this->headers['X-Priority'] = '1';
                
$this->headers['X-MSMail-Priority'] = 'High';
                break;

            case 
'normal':
            case 
'3':
                
$this->headers['X-Priority'] = '3';
                
$this->headers['X-MSMail-Priority'] = 'Normal';
                break;

            case 
'low':
            case 
'5':
                
$this->headers['X-Priority'] = '5';
                
$this->headers['X-MSMail-Priority'] = 'Low';
                break;
        }
    }

    
/**
    * Accessor to set the return path
    * 
    * @param string $return_path Return path to use
    */
    
public function setReturnPath($return_path)
    {
        
$this->return_path $return_path;
    }

    
/**
    * Accessor to add a Cc: header
    * 
    * @param string $cc Carbon Copy address
    */
    
public function setCc($cc)
    {
        
$this->headers['Cc'] = $cc;
    }

    
/**
    * Accessor to add a Bcc: header
    * 
    * @param string $bcc Blind Carbon Copy address
    */
    
public function setBcc($bcc)
    {
        
$this->headers['Bcc'] = $bcc;
    }

    
/**
    * Adds plain text. Use this function
    * when NOT sending html email
    * 
    * @param string $text Plain text of email
    */
    
public function setText($text)
    {
        
$this->text $text;
    }

    
/**
    * Adds HTML to the emails, with an associated text part.
    * If third part is given, images in the email will be loaded
    * from this directory.
    * 
    * @param string $html       HTML part of email
    * @param string $images_dir Images directory
    */
    
function setHTML($html$images_dir null)
    {
        
$this->html $html;

        if (!empty(
$images_dir)) {
            
$this->findHtmlImages($images_dir);
        }
    }

    
/**
    * Function for extracting images from
    * html source. This function will look
    * through the html code supplied by setHTML()
    * and find any file that ends in one of the
    * extensions defined in $obj->image_types.
    * If the file exists it will read it in and
    * embed it, (not an attachment).
    * 
    * @param string $images_dir Images directory to look in
    */
    
private function findHtmlImages($images_dir)
    {
        
// Build the list of image extensions
        
$extensions array_keys($this->image_types);

        
preg_match_all('/(?:"|\')([^"\']+\.('.implode('|'$extensions).'))(?:"|\')/Ui'$this->html$matches);

        foreach (
$matches[1] as $m) {
            if (
file_exists($images_dir $m)) {
                
$html_images[] = $m;
                
$this->html str_replace($mbasename($m), $this->html);
            }
        }

        
/**
        * Go thru found images
        */
        
if (!empty($html_images)) {

            
// If duplicate images are embedded, they may show up as attachments, so remove them.
            
$html_images array_unique($html_images);
            
sort($html_images);

            foreach (
$html_images as $img) {
                if (
$image file_get_contents($images_dir $img)) {
                    
$ext          preg_replace('#^.*\.(\w{3,4})$#e''strtolower("$1")'$img);
                    
$content_type $this->image_types[$ext];
                    
$this->addEmbeddedImage(new stringEmbeddedImage($imagebasename($img), $content_type));
                }
            }
        }
    }

    
/**
    * Adds an image to the list of embedded
    * images.
    * 
    * @param string $object Embedded image object
    */
    
public function addEmbeddedImage($embeddedImage)
    {
        
$embeddedImage->cid md5(uniqid(time()));

        
$this->html_images[] = $embeddedImage;
    }


    
/**
    * Adds a file to the list of attachments.
    * 
    * @param string $attachment Attachment object
    */
    
public function addAttachment($attachment)
    {
        
$this->attachments[] = $attachment;
    }

    
/**
    * Adds a text subpart to a mime_part object
    * 
    * @param  object $obj 
    * @return object      Mime part object
    */
    
private function addTextPart(&$message)
    {
        
$params['content_type'] = 'text/plain';
        
$params['encoding']     = $this->build_params['text_encoding']->getType();
        
$params['charset']      = $this->build_params['text_charset'];

        if (!empty(
$message)) {
            
$message->addSubpart($this->text$params);
        } else {
            
$message = new Mail_mimePart($this->text$params);
        }
    }

    
/**
    * Adds a html subpart to a mime_part object
    * 
    * @param object $obj
    * @return object     Mime part object
    */
    
private function addHtmlPart(&$message)
    {
        
$params['content_type'] = 'text/html';
        
$params['encoding']     = $this->build_params['html_encoding']->getType();
        
$params['charset']      = $this->build_params['html_charset'];

        if (!empty(
$message)) {
            
$message->addSubpart($this->html$params);
        } else {
            
$message = new Mail_mimePart($this->html$params);
        }
    }

    
/**
    * Starts a message with a mixed part
    * 
    * @return object Mime part object
    */
    
private function addMixedPart(&$message)
    {
        
$params['content_type'] = 'multipart/mixed';
        
        
$message = new Mail_mimePart(''$params);
    }

    
/**
    * Adds an alternative part to a mime_part object
    * 
    * @param  object $obj
    * @return object      Mime part object
    */
    
private function addAlternativePart(&$message)
    {
        
$params['content_type'] = 'multipart/alternative';

        if (!empty(
$message)) {
            return 
$message->addSubpart(''$params);
        } else {
            
$message = new Mail_mimePart(''$params);
        }
    }

    
/**
    * Adds a html subpart to a mime_part object
    * 
    * @param  object $obj
    * @return object      Mime part object
    */
    
private function addRelatedPart(&$message)
    {
        
$params['content_type'] = 'multipart/related';

        if (!empty(
$message)) {
            return 
$message->addSubpart(''$params);
        } else {
            
$message = new Mail_mimePart(''$params);
        }
    }

    
/**
    * Adds all html images to a mime_part object
    * 
    * @param  object $obj Message object
    */
    
private function addHtmlImageParts(&$message)
    {
        foreach (
$this->html_images as $value) {
            
$params['content_type'] = $value->contentType;
            
$params['encoding']     = $value->encoding->getType();
            
$params['disposition']  = 'inline';
            
$params['dfilename']    = $value->name;
            
$params['cid']          = $value->cid;
    
            
$message->addSubpart($value->data$params);
        }
    }

    
/**
    * Adds all attachments to a mime_part object
    * 
    * @param object $obj Message object
    */
    
private function addAttachmentParts(&$message)
    {
        foreach (
$this->attachments as $value) {
            
$params['content_type'] = $value->contentType;
            
$params['encoding']     = $value->encoding->getType();
            
$params['disposition']  = 'attachment';
            
$params['dfilename']    = $value->name;
        
            
$message->addSubpart($value->data$params);
        }
    }

    
/**
    * Builds the multipart message.
    */
    
private function build()
    {
        if (!empty(
$this->html_images)) {
            foreach (
$this->html_images as $value) {
                
$quoted preg_quote($value->name);
                
$cid    preg_quote($value->cid);

                
$this->html preg_replace("#src=\"$quoted\"|src='$quoted'#""src=\"cid:$cid\""$this->html);
                
$this->html preg_replace("#background=\"$quoted\"|background='$quoted'#""background=\"cid:$cid\""$this->html);
            }
        }

        
$message     null;
        
$attachments = !empty($this->attachments);
        
$html_images = !empty($this->html_images);
        
$html        = !empty($this->html);
        
$text        = !$html;

        switch (
true) {
            case 
$text:
                
$message null;
                if (
$attachments) {
                    
$this->addMixedPart($message);
                }

                
$this->addTextPart($message);

                
// Attachments
                
$this->addAttachmentParts($message);
                break;

            case 
$html AND !$attachments AND !$html_images:
                
$this->addAlternativePart($message);

                
$this->addTextPart($message);
                
$this->addHtmlPart($message);
                break;

            case 
$html AND !$attachments AND $html_images:
                
$this->addRelatedPart($message);
                
$alt $this->addAlternativePart($message);

                
$this->addTextPart($alt);
                
$this->addHtmlPart($alt);
                
                
// HTML images
                
$this->addHtmlImageParts($message);
                break;

            case 
$html AND $attachments AND !$html_images:
                
$this->addMixedPart($message);
                
$alt $this->addAlternativePart($message);

                
$this->addTextPart($alt);
                
$this->addHtmlPart($alt);
                
                
// Attachments
                
$this->addAttachmentParts($message);
                break;

            case 
$html AND $attachments AND $html_images:
                
$this->addMixedPart($message);
                
$rel $this->addRelatedPart($message);
                
$alt $this->addAlternativePart($rel);
                
                
$this->addTextPart($alt);
                
$this->addHtmlPart($alt);
                
                
// HTML images
                
$this->addHtmlImageParts($rel);
                
                
// Attachments
                
$this->addAttachmentParts($message);
                break;

        }

        if (isset(
$message)) {
            
$output $message->encode();
            
$this->output   $output['body'];
            
$this->headers  array_merge($this->headers$output['headers']);

            
// Figure out hostname
            
if (!empty($_SERVER['HTTP_HOST'])) {
                
$hostname $_SERVER['HTTP_HOST'];
            
            } else if (!empty(
$_SERVER['SERVER_NAME'])) {
                
$hostname $_SERVER['SERVER_NAME'];
            
            } else if (!empty(
$_ENV['HOSTNAME'])) {
                
$hostname $_ENV['HOSTNAME'];
            
            } else {
                
$hostname 'localhost';
            }
            
            
$message_id sprintf('<%s.%s@%s>'base_convert(time(), 1036), base_convert(rand(), 1036), $hostname);
            
$this->headers['Message-ID'] = $message_id;

            return 
true;
        } else {
            return 
false;
        }
    }

    
/**
    * Function to encode a header if necessary
    * according to RFC2047
    * 
    * @param  string $input   Value to encode
    * @param  string $charset Character set to use
    * @return string          Encoded value
    */
    
private function encodeHeader($input$charset 'ISO-8859-1')
    {
        
preg_match_all('/(\w*[\x80-\xFF]+\w*)/'$input$matches);
        foreach (
$matches[1] as $value) {
            
$replacement preg_replace('/([\x80-\xFF])/e''"=" . strtoupper(dechex(ord("\1")))'$value);
            
$input str_replace($value'=?' $charset '?Q?' $replacement '?='$input);
        }
        
        return 
$input;
    }

    
/**
    * Sends the mail.
    *
    * @param  array  $recipients Array of receipients to send the mail to
    * @param  string $type       How to send the mail ('mail' or 'sendmail' or 'smtp')
    * @return mixed
    */
    
public function send($recipients$type 'mail')
    {
        if (!
defined('RMAIL_CRLF')) {
            
$this->setCRLF( ($type == 'mail' OR $type == 'sendmail') ? "\n" "\r\n");
        }

        
$this->build();

        switch (
$type) {
            case 
'mail':
                
$subject '';
                if (!empty(
$this->headers['Subject'])) {
                    
$subject $this->encodeHeader($this->headers['Subject'], $this->build_params['head_charset']);
                    unset(
$this->headers['Subject']);
                }

                
// Get flat representation of headers
                
foreach ($this->headers as $name => $value) {
                    
$headers[] = $name ': ' $this->encodeHeader($value$this->build_params['head_charset']);
                }

                
$to $this->encodeHeader(implode(', '$recipients), $this->build_params['head_charset']);

                if (!empty(
$this->return_path)) {
                    
$result mail($to$subject$this->outputimplode(RMAIL_CRLF$headers), '-f' $this->return_path);
                } else {
                    
$result mail($to$subject$this->outputimplode(RMAIL_CRLF$headers));
                }

                
// Reset the subject in case mail is resent
                
if ($subject !== '') {
                    
$this->headers['Subject'] = $subject;
                }


                
// Return
                
return $result;
                break;

            case 
'sendmail':
                
// Get flat representation of headers
                
foreach ($this->headers as $name => $value) {
                    
$headers[] = $name ': ' $this->encodeHeader($value$this->build_params['head_charset']);
                }

                
// Encode To:
                
$headers[] = 'To: ' $this->encodeHeader(implode(', '$recipients), $this->build_params['head_charset']);

                
// Get return path arg for sendmail command if necessary
                
$returnPath '';
                if (!empty(
$this->return_path)) {
                    
$returnPath '-f' $this->return_path;
                }

                
$pipe popen($this->sendmail_path " " $returnPath'w');
                    
$bytes fputs($pipeimplode(RMAIL_CRLF$headers) . RMAIL_CRLF RMAIL_CRLF $this->output);
                
$r pclose($pipe);

                return 
$r;
                break;

            case 
'smtp':
                require_once(
dirname(__FILE__) . '/smtp.php');
                require_once(
dirname(__FILE__) . '/RFC822.php');
                
$smtp = &smtp::connect($this->smtp_params);
                
                
// Parse recipients argument for internet addresses
                
foreach ($recipients as $recipient) {
                    
$addresses Mail_RFC822::parseAddressList($recipient$this->smtp_params['helo'], nullfalse);
                    foreach (
$addresses as $address) {
                        
$smtp_recipients[] = sprintf('%s@%s'$address->mailbox$address->host);
                    }
                }
                unset(
$addresses); // These are reused
                
unset($address);   // These are reused

                // Get flat representation of headers, parsing
                // Cc and Bcc as we go
                
foreach ($this->headers as $name => $value) {
                    if (
$name == 'Cc' OR $name == 'Bcc') {
                        
$addresses Mail_RFC822::parseAddressList($value$this->smtp_params['helo'], nullfalse);
                        foreach (
$addresses as $address) {
                            
$smtp_recipients[] = sprintf('%s@%s'$address->mailbox$address->host);
                        }
                    }
                    if (
$name == 'Bcc') {
                        continue;
                    }
                    
$headers[] = $name ': ' $this->encodeHeader($value$this->build_params['head_charset']);
                }
                
// Add To header based on $recipients argument
                
$headers[] = 'To: ' $this->encodeHeader(implode(', '$recipients), $this->build_params['head_charset']);

                
// Add headers to send_params
                
$send_params['headers']    = $headers;
                
$send_params['recipients'] = array_values(array_unique($smtp_recipients));
                
$send_params['body']       = $this->output;

                
// Setup return path
                
if (isset($this->return_path)) {
                    
$send_params['from'] = $this->return_path;
                } elseif (!empty(
$this->headers['From'])) {
                    
$from Mail_RFC822::parseAddressList($this->headers['From']);
                    
$send_params['from'] = sprintf('%s@%s'$from[0]->mailbox$from[0]->host);
                } else {
                    
$send_params['from'] = 'postmaster@' $this->smtp_params['helo'];
                }

                
// Send it
                
if (!$smtp->send($send_params)) {
                    
$this->errors $smtp->getErrors();
                    return 
false;
                }
                return 
true;
                break;
        }
    }

    
/**
    * Use this method to return the email
    * in message/rfc822 format. Useful for
    * adding an email to another email as
    * an attachment.
    * 
    * @param array  $recipients Array of recipients 
    * @param string $type       Method to be used to send the mail.
    *                           Used to determine the line ending type.
    */
    
public function getRFC822($recipients$type 'mail')
    {
        
// Make up the date header as according to RFC822
        
$this->setHeader('Date'date('D, d M Y H:i:s O'));

        if (!
defined('RMAIL_CRLF')) {
            
$this->setCRLF($type == 'mail' "\n" "\r\n");
        }

        
$this->build();

        
// Return path ?
        
if (isset($this->return_path)) {
            
$headers[] = 'Return-Path: ' $this->return_path;
        }

        
// Get flat representation of headers
        
foreach ($this->headers as $name => $value) {
            
$headers[] = $name ': ' $value;
        }
        
$headers[] = 'To: ' implode(', '$recipients);

        return 
implode(RMAIL_CRLF$headers) . RMAIL_CRLF RMAIL_CRLF $this->output;
    }
// End of class.


/**
* Attachment classes
*/
class attachment
{
    
/**
    * Data of attachment
    * @var string
    */
    
public $data;
    
    
/**
    * Name of attachment (filename)
    * @var string
    */
    
public $name;
    
    
/**
    * Content type of attachment
    * @var string
    */
    
public $contentType;
    
    
/**
    * Encoding type of attachment
    * @var object
    */
    
public $encoding;
    
    
/**
    * Constructor
    * 
    * @param string $data        File data
    * @param string $name        Name of attachment (filename)
    * @param string $contentType Content type of attachment
    * @param object $encoding    Encoding type to use
    */
    
public function __construct($data$name$contentTypeiEncoding $encoding)
    {
        
$this->data        $data;
        
$this->name        $name;
        
$this->contentType $contentType;
        
$this->encoding    $encoding;
    }
}


/**
* File based attachment class
*/
class fileAttachment extends attachment
{
    
/**
    * Constructor
    * 
    * @param string $filename    Name of file
    * @param string $contentType Content type of file
    * @param string $encoding    What encoding to use
    */
    
public function __construct($filename$contentType 'application/octet-stream'$encoding null)
    {
        
$encoding is_null($encoding) ? new Base64Encoding() : $encoding;

        
parent::__construct(file_get_contents($filename), basename($filename), $contentType$encoding);
    }
}


/**
* Attachment class to handle attachments which are contained
* in a variable.
*/
class stringAttachment extends attachment
{
    
/**
    * Constructor
    * 
    * @param string $data        File data
    * @param string $name        Name of attachment (filename)
    * @param string $contentType Content type of file
    * @param string $encoding    What encoding to use
    */
    
public function __construct($data$name ''$contentType 'application/octet-stream'$encoding null)
    {
        
$encoding is_null($encoding) ? new Base64Encoding() : $encoding;
        
        
parent::__construct($data$name$contentType$encoding);
    }
}


/**
* File based embedded image class
*/
class fileEmbeddedImage extends fileAttachment
{
}


/**
* String based embedded image class
*/
class stringEmbeddedImage extends stringAttachment
{
}


/**

*/
/**
* Encoding interface
*/
interface iEncoding
{
    public function 
encode($input);
    public function 
getType();
}


/**
* Base64 Encoding class
*/
class Base64Encoding implements iEncoding
{
    
/*
    * Function to encode data using
    * base64 encoding.
    * 
    * @param string $input Data to encode
    */
    
public function encode($input)
    {
        return 
rtrim(chunk_split(base64_encode($input), 76defined('MAIL_MIME_PART_CRLF') ? MAIL_MIME_PART_CRLF "\r\n"));
    }
    
    
/**
    * Returns type
    */
    
public function getType()
    {
        return 
'base64';
    }
}


/**
* Quoted Printable Encoding class
*/
class QPrintEncoding implements iEncoding
{
    
/*
    * Function to encode data using
    * quoted-printable encoding.
    * 
    * @param string $input Data to encode
    */
    
public function encode($input)
    {
        
// Replace non printables
        
$input    preg_replace('/([^\x20\x21-\x3C\x3E-\x7E\x0A\x0D])/e''sprintf("=%02X", ord("\1"))'$input);
        
$inputLen strlen($input);
        
$outLines = array();
        
$output   '';

        
$lines preg_split('/\r?\n/'$input);
        
        
// Walk through each line
        
for ($i=0$i<count($lines); $i++) {
            
// Is line too long ?
            
if (strlen($lines[$i]) > $lineMax) {
                
$outLines[] = substr($lines[$i], 0$lineMax 1) . "="// \r\n Gets added when lines are imploded
                
$lines[$i] = substr($lines[$i], $lineMax 1);
                
$i--; // Ensure this line gets redone as we just changed it
            
} else {
                
$outLines[] = $lines[$i];
            }
        }
        
        
// Convert trailing whitespace        
        
$output preg_replace('/(\x20+)$/me''str_replace(" ", "=20", "\1")'$outLines);

        return 
implode("\r\n"$output);
    }
    
    
/**
    * Returns type
    */
    
public function getType()
    {
        return 
'quoted-printable';
    }
}


/**
* 7Bit Encoding class
*/
class SevenBitEncoding implements iEncoding
{
    
/*
    * Function to "encode" data using
    * 7bit encoding.
    * 
    * @param string $input Data to encode
    */
    
public function encode($input)
    {
        return 
$input;
    }
    
    
/**
    * Returns type
    */
    
public function getType()
    {
        return 
'7bit';
    }
}


/**
* 8Bit Encoding class
*/
class EightBitEncoding implements iEncoding
{
    
/*
    * Function to "encode" data using
    * 8bit encoding.
    * 
    * @param string $input Data to encode
    */
    
public function encode($input)
    {
        return 
$input;
    }
    
    
/**
    * Returns type
    */
    
public function getType()
    {
        return 
'8bit';
    }
}
?>