<?php
	/**
	 * This EmailServer (and its dependent EmailMessage class) allows the application to send
	 * messages via any accessible SMTP server.
	 * 
	 * The QEmailServer class, specifically, is an abstract class and is NOT meant to be instantiated.
	 * It has one public static method, Send, which takes in a QEmailMessage object.
	 */
	abstract class QEmailServer extends QBaseClass {
		/**
		 * Server Hostname or IP Address of the server running the SMTP service.
		 * Using an IP address is slightly faster, but using a Hostname is easier to manage.
		 * Defaults to "localhost".
		 *
		 * @var string SmtpServer
		 */
		public static $SmtpServer = 'localhost';

		/**
		 * Port of the SMTP Service on the SmtpServer, usually 25
		 *
		 * @var integer SmtpPort
		 */
		public static $SmtpPort = 25;

		/**
		 * IP Address of the Originating Server (e.g. the IP address of this server)
		 * used for the EHLO command in the SMTP protocol.  Defaults to the
		 * QApplication::$ServerAddress variable, which uses the PHP $_SERVER
		 * constants to determine the correct IP address.
		 *
		 * @var string OriginatingServerIp
		 */
		public static $OriginatingServerIp;

		/**
		 * Whether or not we are running in Test Mode.  Test Mode allows you
		 * to develop e-mail-based applications without actually having access to
		 * an SMTP server or the Internet.  Instead of messages being sent out,
		 * the messages and corresponding SMTP communication will be saved to disk.
		 *
		 * @var boolean $TestMode
		 */
		public static $TestMode = false;

		/**
		 * The directory where TestMode e-mail files will be saved to.  The process
		 * running the webserver *must* have write access to this directory.  Default
		 * is "/tmp", which makes sense in unix/linux/mac environments.  Windows users
		 * will likely need to set up their own temp directories.
		 *
		 * @var string $TestModeDirectory
		 */		
		public static $TestModeDirectory = __TMP__;

		/**
		 * Boolean flag signifying whether SMTP's AUTH PLAIN should be used
		 * 
		 * @var bool $AuthPlain
		 */
		public static $AuthPlain = false;

		/**
		 * Boolean flag signifying whether SMTP's AUTH LOGIN should be used
		 * 
		 * @var bool $AuthLogin
		 */
		public static $AuthLogin = false;

		/**
		 * SMTP Username to use for AUTH PLAIN or LOGIN
		 * 
		 * @var string $SmtpUsername
		 */
		public static $SmtpUsername = '';

		/**
		 * SMTP Password to use for AUTH PLAIN or LOGIN
		 * 
		 * @var string $SmtpPassword
		 */
		public static $SmtpPassword = '';

		/**
		 * Encoding Type (if null, will default to the QApplication::$EncodingType)
		 * 
		 * @var string $EncodingType
		 */
		public static $EncodingType = null;

		/**
		 * Uses regular expression matching to return an array of valid e-mail addresses
		 *
		 * @param string $strAddresses Single string containing e-mail addresses and anything else
		 * @return string[] An array of e-mail addresses only, or NULL if none
		 */
		public static function GetEmailAddresses($strAddresses) {
			$strAddressArray = null;

			// Address Lines cannot have any linebreaks
			if ((strpos($strAddresses, "\r") !== false) ||
				(strpos($strAddresses, "\n") !== false))
				return null;

			preg_match_all ("/[a-zA-Z0-9_.'%+-]+[@][\-a-zA-Z0-9_.]+/", $strAddresses, $strAddressArray);
			if ((is_array($strAddressArray)) &&
				(array_key_exists(0, $strAddressArray)) &&
				(is_array($strAddressArray[0])) &&
				(array_key_exists(0, $strAddressArray[0]))) {
				return $strAddressArray[0];
			}
			
			// If we're here, then no addresses were found in $strAddress
			// so return null
			return null;
		}

		/**
		 * This will check to see if an email address is considered "Valid" according to RFC 2822.
		 * It utilizes the GetEmailAddresses static method, which does the actual logic work of checking.
		 * @param string $strEmailAddress
		 * @return boolean
		 */
		public static function IsEmailValid($strEmailAddress) {
			$strEmailAddressArray = QEmailServer::GetEmailAddresses($strEmailAddress);
			return ((count($strEmailAddressArray) == 1) && ($strEmailAddressArray[0] == $strEmailAddress));  
		}

		/**
		 * Encodes given 8 bit string to a quoted-printable string,
		 * @param string $strString
		 * @param boolean $blnSubject
		 * @return encoded string
		 */
		private static function QuotedPrintableEncode($strString, $blnSubject = false) {
			if ( function_exists('quoted_printable_encode') )
				$strText = quoted_printable_encode($strString);
			else {
				$strText = preg_replace( '/[^\x21-\x3C\x3E-\x7E\x09\x20]/e', 'sprintf( "=%02X", ord ( "$0" ) ) ;', $strString );
				preg_match_all( '/.{1,73}([^=]{0,2})?/', $strText, $arrMatch );
				$strText = implode( '=' . "\r\n", $arrMatch[0] );
			}
            
			if ($blnSubject) {
				// Replace spaces with undercores, see RFC 1342
				$strText = str_replace("_", "=5F", $strText);
				$strText = str_replace(" ", "_", $strText);

				// Remove newlines
				$strText = str_replace("=\r\n", "", $strText);
			} else {
				// Escape leading dots with another dot
				$strText = str_replace("\n.", "\n..", $strText);
			}
            
			return $strText;
		}


		/**
		 * Sends a message out via SMTP according to the server, ip, etc. preferences
		 * as set up on the class.  Takes in a QEmailMessage object.
		 * Will throw a QEmailException exception on any error.
		 *
		 * @param QEmailMessage $objMessage Message to Send
		 *
		 * @throws QEmailException
		 * @return void
		 */
		public static function Send(QEmailMessage $objMessage) {
			$objResource = null;

			if (QEmailServer::$TestMode) {
				// Open up a File Resource to the TestModeDirectory
				$strArray = explode(' ', microtime());
				$strFileName = sprintf('%s/email_%s%s.txt', QEmailServer::$TestModeDirectory, $strArray[1], substr($strArray[0], 1));
				$objResource = fopen($strFileName, 'w');
				if (!$objResource)
					throw new QEmailException(sprintf('Unable to open Test SMTP connection to: %s', $strFileName));

				// Clear the Read Buffer
				if (!feof($objResource))
					fgets($objResource, 4096);

				// Write the Connection Command
				fwrite($objResource, sprintf("telnet %s %s\r\n", QEmailServer::$SmtpServer, QEmailServer::$SmtpPort));
			} else {
				$objResource = fsockopen(QEmailServer::$SmtpServer, QEmailServer::$SmtpPort);
				if (!$objResource)
					throw new QEmailException(sprintf('Unable to open SMTP connection to: %s %s', QEmailServer::$SmtpServer, QEmailServer::$SmtpPort));
			}

			// Connect
			$strResponse = null;
			if (!feof($objResource)) {
				$strResponse = fgets($objResource, 4096);

				// Iterate through all "220-" responses (stop at "220 ")
				while ((substr($strResponse, 0, 3) == "220") && (substr($strResponse, 0, 4) != "220 "))
					if (!feof($objResource))
						$strResponse = fgets($objResource, 4096);

				// Check for a "220" response
				if (!QEmailServer::$TestMode)
					if ((strpos($strResponse, "220") === false) || (strpos($strResponse, "220") != 0))
						throw new QEmailException(sprintf('Error Response on Connect: %s', $strResponse));
			}

			// Send: EHLO
			fwrite($objResource, sprintf("EHLO %s\r\n", QEmailServer::$OriginatingServerIp));
			if (!feof($objResource)) {
				$strResponse = fgets($objResource, 4096);

				// Iterate through all "250-" responses (stop at "250 ")
				while ((substr($strResponse, 0, 3) == "250") && (substr($strResponse, 0, 4) != "250 "))
					if (!feof($objResource))
						$strResponse = fgets($objResource, 4096);

				// Check for a "250" response
				if (!QEmailServer::$TestMode)
					if ((strpos($strResponse, "250") === false) || (strpos($strResponse, "250") != 0))
						throw new QEmailException(sprintf('Error Response on EHLO: %s', $strResponse));
			}

			// Send Authentication
			if (QEmailServer::$AuthPlain) {
				fwrite($objResource, "AUTH PLAIN " . base64_encode(QEmailServer::$SmtpUsername . "\0" . QEmailServer::$SmtpUsername . "\0" . QEmailServer::$SmtpPassword) . "\r\n");
				if (!feof($objResource)) {
					$strResponse = fgets($objResource, 4096);
					if ((strpos($strResponse, "235") === false) || (strpos($strResponse, "235") != 0))
						throw new QEmailException(sprintf('Error in response from AUTH PLAIN: %s', $strResponse));
				}
			}

			if (QEmailServer::$AuthLogin) {
				fwrite($objResource,"AUTH LOGIN\r\n");
				if (!feof($objResource)) {
					$strResponse = fgets($objResource, 4096);
					if (!QEmailServer::$TestMode)
						if ((strpos($strResponse, "334") === false) || (strpos($strResponse, "334") != 0))
							throw new QEmailException(sprintf('Error in response from AUTH LOGIN: %s', $strResponse));
				}

				fwrite($objResource, base64_encode(QEmailServer::$SmtpUsername) . "\r\n");
				if (!feof($objResource)) {
					$strResponse = fgets($objResource, 4096);
					if (!QEmailServer::$TestMode)
						if ((strpos($strResponse, "334") === false) || (strpos($strResponse, "334") != 0))
							throw new QEmailException(sprintf('Error in response from AUTH LOGIN: %s', $strResponse));
				}

				fwrite($objResource, base64_encode(QEmailServer::$SmtpPassword) . "\r\n");
				if (!feof($objResource)) {
 					$strResponse = fgets($objResource, 4096);
					if (!QEmailServer::$TestMode)
						if ((strpos($strResponse, "235") === false) || (strpos($strResponse, "235") != 0))
							throw new QEmailException(sprintf('Error in response from AUTH LOGIN: %s', $strResponse));
				}
			}

			// Setup MAIL FROM line
			$strAddressArray = QEmailServer::GetEmailAddresses($objMessage->From);
			if (count($strAddressArray) != 1)
				throw new QEmailException(sprintf('Not a valid From address: %s', $objMessage->From));

			// Send: MAIL FROM line
			fwrite($objResource, sprintf("MAIL FROM: <%s>\r\n", $strAddressArray[0]));			
			if (!feof($objResource)) {
				$strResponse = fgets($objResource, 4096);
				
				// Check for a "250" response
				if (!QEmailServer::$TestMode)
					if ((strpos($strResponse, "250") === false) || (strpos($strResponse, "250") != 0))
						throw new QEmailException(sprintf('Error Response on MAIL FROM: %s', $strResponse));
			}

			// Setup RCPT TO line(s)
			$strAddressToArray = QEmailServer::GetEmailAddresses($objMessage->To);
			if (!$strAddressToArray)
				throw new QEmailException(sprintf('Not a valid To address: %s', $objMessage->To));

			$strAddressCcArray = QEmailServer::GetEmailAddresses($objMessage->Cc);
			if (!$strAddressCcArray)
				$strAddressCcArray = array();

			$strAddressBccArray = QEmailServer::GetEmailAddresses($objMessage->Bcc);
			if (!$strAddressBccArray)
				$strAddressBccArray = array();

			$strAddressCcBccArray = array_merge($strAddressCcArray, $strAddressBccArray);
			$strAddressArray = array_merge($strAddressToArray, $strAddressCcBccArray);

			// Send: RCPT TO line(s)
			foreach ($strAddressArray as $strAddress) {
				fwrite($objResource, sprintf("RCPT TO: <%s>\r\n", $strAddress));
				if (!feof($objResource)) {
					$strResponse = fgets($objResource, 4096);
					
					// Check for a "250" response
					if (!QEmailServer::$TestMode)
						if ((strpos($strResponse, "250") === false) || (strpos($strResponse, "250") != 0))
							throw new QEmailException(sprintf('Error Response on RCPT TO: %s', $strResponse));
				}
			}

			// Send: DATA
			fwrite($objResource, "DATA\r\n");
			if (!feof($objResource)) {
				$strResponse = fgets($objResource, 4096);
				
				// Check for a "354" response
				if (!QEmailServer::$TestMode)
					if ((strpos($strResponse, "354") === false) || (strpos($strResponse, "354") != 0))
						throw new QEmailException(sprintf('Error Response on DATA: %s', $strResponse));
			}

			// Send: Required Headers
			fwrite($objResource, sprintf("Date: %s\r\n", QDateTime::NowToString(QDateTime::FormatRfc5322)));
			fwrite($objResource, sprintf("To: %s\r\n", $objMessage->To));
			fwrite($objResource, sprintf("From: %s\r\n", $objMessage->From));
			if($objMessage->ReplyTo) {
				fwrite($objResource, sprintf("Reply-To: %s\r\n", $objMessage->ReplyTo));
			}
			if($objMessage->Sender) {
				fwrite($objResource, sprintf("Sender: %s\r\n", $objMessage->Sender));
			}
			
			// Setup Encoding Type (use QEmailServer if specified, otherwise default to QApplication's)
			if (!($strEncodingType = QEmailServer::$EncodingType))
				$strEncodingType = QApplication::$EncodingType;

			// Send: Optional Headers
			if ($objMessage->Subject) {
				if ($objMessage->EncodeSubject) {
					fwrite($objResource, sprintf("Subject: =?%s?Q?%s?=\r\n", $strEncodingType, self::QuotedPrintableEncode($objMessage->Subject, true)));
				} else {
					fwrite($objResource, sprintf("Subject: %s\r\n", $objMessage->Subject));
				}
			}

			if ($objMessage->Cc)
				fwrite($objResource, sprintf("Cc: %s\r\n", $objMessage->Cc));

			// Send: Content-Type Header (if applicable)

			// First, setup boundaries (may be needed if multipart)
			$strBoundary = sprintf('qcubed_mixed_boundary_%s', md5(microtime()));
			$strAltBoundary = sprintf('qcubed_alt_boundary_%s', md5(microtime()));

			// Send: Other Headers (if any)
			foreach ($objArray = $objMessage->HeaderArray as $strKey => $strValue)
				fwrite($objResource, sprintf("%s: %s\r\n", $strKey, $strValue));			

			// if we are adding an html or files to the message we need these headers.
			if ($objMessage->HasFiles || $objMessage->HtmlBody)  {
				fwrite($objResource, "MIME-Version: 1.0\r\n");
				fwrite($objResource, sprintf("Content-Type: multipart/mixed;\r\n boundary=\"%s\"\r\n", $strBoundary));
				fwrite($objResource, sprintf("This is a multipart message in MIME format.\r\n\r\n", $strBoundary));
				fwrite($objResource, sprintf("--%s\r\n", $strBoundary));				
			}

			// Send: Body
			if ($objMessage->HtmlBody) {
				fwrite($objResource, sprintf("Content-Type: multipart/alternative;\r\n boundary=\"%s\"\r\n\r\n", $strAltBoundary));
				fwrite($objResource, sprintf("--%s\r\n", $strAltBoundary));
				fwrite($objResource, sprintf("Content-Type: text/plain; charset=\"%s\"\r\n", $strEncodingType));
				fwrite($objResource, sprintf("Content-Transfer-Encoding: quoted-printable\r\n\r\n"));

				fwrite($objResource, self::QuotedPrintableEncode($objMessage->Body));
				fwrite($objResource, "\r\n\r\n");

				fwrite($objResource, sprintf("--%s\r\n", $strAltBoundary));
				fwrite($objResource, sprintf("Content-Type: text/html; charset=\"%s\"\r\n", $strEncodingType));
				fwrite($objResource, sprintf("Content-Transfer-Encoding: quoted-printable\r\n\r\n"));								
		
				fwrite($objResource, self::QuotedPrintableEncode($objMessage->HtmlBody));
				fwrite($objResource, "\r\n\r\n");
				
				fwrite($objResource, sprintf("--%s--\r\n", $strAltBoundary));
			} else if($objMessage->HasFiles) {
				fwrite($objResource, sprintf("Content-Type: multipart/alternative;\r\n boundary=\"%s\"\r\n\r\n", $strAltBoundary));				
				fwrite($objResource, sprintf("--%s\r\n", $strAltBoundary));
				fwrite($objResource, sprintf("Content-Type: text/plain; charset=\"%s\"\r\n", $strEncodingType));
				fwrite($objResource, sprintf("Content-Transfer-Encoding: quoted-printable\r\n\r\n"));
				fwrite($objResource, self::QuotedPrintableEncode($objMessage->Body));
				fwrite($objResource, "\r\n\r\n");
				fwrite($objResource, sprintf("--%s--\r\n", $strAltBoundary));
			} else {
				fwrite($objResource, sprintf("Content-Type: text/plain; charset=\"%s\"\r\n", $strEncodingType));
				fwrite($objResource, sprintf("Content-Transfer-Encoding: quoted-printable\r\n\r\n"));
				fwrite($objResource, "\r\n" . self::QuotedPrintableEncode($objMessage->Body));
			}

			// Send: File Attachments
			if($objMessage->HasFiles) {
				foreach ($objArray = $objMessage->FileArray as $objFile) {
					fwrite($objResource, sprintf("--%s\r\n", $strBoundary));
					fwrite($objResource, sprintf("Content-Type: %s;\r\n", $objFile->MimeType ));
					fwrite($objResource, sprintf("	  name=\"%s\"\r\n", $objFile->FileName ));
					fwrite($objResource, "Content-Transfer-Encoding: base64\r\n");
					fwrite($objResource, sprintf("Content-Length: %s\r\n", strlen($objFile->EncodedFileData)));
					fwrite($objResource, "Content-Disposition: attachment;\r\n");
					fwrite($objResource, sprintf("	  filename=\"%s\"\r\n\r\n", $objFile->FileName));
					fwrite($objResource, $objFile->EncodedFileData);
//					foreach (explode("\r\n", $objFile->EncodedFileData) as $strLine) {
//						$strLine = trim($strLine);
//						fwrite($objResource, $strLine . "\r\n");
//					}
				}
			}

			// close a message with these boundaries if the message had files or had html
			if($objMessage->HasFiles || $objMessage->HtmlBody)
	   			fwrite($objResource, sprintf("\r\n\r\n--%s--\r\n", $strBoundary)); // send end of file attachments...

			// Send: Message End
			fwrite($objResource, "\r\n.\r\n");
			if (!feof($objResource)) {
				$strResponse = fgets($objResource, 4096);
				
				// Check for a "250" response
				if (!QEmailServer::$TestMode)
					if ((strpos($strResponse, "250") === false) || (strpos($strResponse, "250") != 0))
						throw new QEmailException(sprintf('Error Response on DATA finish: %s', $strResponse));
			}

			// Send: QUIT
			fwrite($objResource, "QUIT\r\n");
			if (!feof($objResource))
				$strResponse = fgets($objResource, 4096);
				
			// Close the Resource
			fclose($objResource);
			if (QEmailServer::$TestMode)
				chmod($strFileName, 0777);
		}
	}

	// PHP does not allow Static Class Variables to be set to non-constants.
	// So we set QEmailServer's OriginatingServerIp to QApplication's ServerAddress here.
	QEmailServer::$OriginatingServerIp = QApplication::$ServerAddress;

	class QEmailException extends QCallerException {}
	
	class QEmailAttachment extends QBaseClass {
		protected $strFilePath;
		protected $strMimeType;
		protected $strFileName;
		protected $strEncodedFileData;

		public function __construct($strFilePath, $strSpecifiedMimeType = null, $strSpecifiedFileName = null) {
			// Set File Path
			if (!is_file(realpath($strFilePath)))
				throw new QCallerException('File Not Found: ' . $strFilePath);
			$this->strFilePath = realpath($strFilePath);


			// Set the File MIME Type -- if Explicitly Set, use it
			if ($strSpecifiedMimeType)
				$this->strMimeType = $strSpecifiedMimeType;
			// otherwise, use QMimeType to determine
			else
				$this->strMimeType = QMimeType::GetMimeTypeForFile($this->strFilePath);


			// Set the File Name -- if explicitly set, use it
			if ($strSpecifiedFileName)
				$this->strFileName = $strSpecifiedFileName;
			// Otherwise, use basename() to determine
			else
				$this->strFileName = basename($this->strFilePath);


			// Read file into a Base64 Encoded Data Stream
			$strFileContents = file_get_contents($this->strFilePath, false);
			$this->strEncodedFileData = chunk_split(base64_encode($strFileContents));
		}

		public function __get($strName) {
			switch ($strName) {
				case 'FilePath': return $this->strFilePath;
				case 'MimeType': return $this->strMimeType; 
				case 'FileName': return $this->strFileName;
				case 'EncodedFileData': return $this->strEncodedFileData;
				default:
					try {
						return parent::__get($strName);
					} catch (QCallerException $objExc) {
						$objExc->IncrementOffset();
						throw $objExc;
					}
			}
		}
	}
	
	class QEmailStringAttachment extends QEmailAttachment {
		public function __construct($strContent, $strSpecifiedMimeType, $strSpecifiedFileName) {
			// Set the File MIME Type -- if Explicitly Set, use it
			if ($strSpecifiedMimeType) {
				$this->strMimeType = $strSpecifiedMimeType;
			}
			
			// Set the File Name -- if explicitly set, use it
			if ($strSpecifiedFileName) {
				$this->strFileName = $strSpecifiedFileName;
			}
			
			// Read file into a Base64 Encoded Data Stream
			$this->strEncodedFileData = chunk_split(base64_encode($strContent));
		}
	}

	/**
	 * An email message that you can send with QEmailServer
	 *
	 * @property string $From
	 * @property string $ReplyTo
	 * @property string $Sender
	 * @property string $To
	 * @property string $Cc
	 * @property string $Bcc
	 * @property string $Subject
	 * @property string $Body
	 * @property string $HtmlBody
	 * @property boolean $EncodeSubject  Whether to encode the subject of the email using UTF-8. Default is true. You might want to turn this off if sending to text message portals (i.e. 123-4567@sprint.message.com)
	 */
	class QEmailMessage extends QBaseClass {
		protected $strFrom;
		protected $strReplyTo;
		protected $strSender;
		protected $strTo;
		protected $strSubject;
		protected $strBody;
		protected $strHtmlBody;

		protected $strCc;
		protected $strBcc;
		protected $strHeaderArray = array();
		protected $objFileArray = array();

		protected $blnEncodeSubject = true;	// useful for sending to text message hubs, they don't like charset declaractions

		public function AddAttachment(QEmailAttachment $objFile) {						
			$this->objFileArray[$objFile->FileName] = $objFile;
		}

		public function Attach($strFilePath, $strSpecifiedMimeType = null, $strSpecifiedFileName = null) {
			$this->AddAttachment(new QEmailAttachment($strFilePath, $strSpecifiedMimeType, $strSpecifiedFileName));
		}

		public function RemoveAttachment($strName) {
			if (array_key_exists($strName, $this->objFileArray))
				unset($this->objFileArray[$strName]);
		}

		public function SetHeader($strName, $strValue) {
			$this->strHeaderArray[$strName] = $strValue;
		}

		public function GetHeader($strName) {
			if (array_key_exists($strName, $this->strHeaderArray))
				return $this->strHeaderArray[$strName];
			return null;
		}

		public function RemoveHeader($strName) {
			if (array_key_exists($strName, $this->strHeaderArray))
				unset($this->strHeaderArray[$strName]);
		}

		public function __construct($strFrom = null, $strTo = null, $strSubject = null, $strBody = null) {
			$this->strFrom = $strFrom;
			$this->strTo = $strTo;

			// We must cleanup the Subject and Body -- use the Property to set
			$this->Subject = $strSubject;
			$this->Body = $strBody;
		}

		public function __get($strName) {
			switch ($strName) {
				case 'From'		: return $this->strFrom;
				case 'ReplyTo'		: return $this->strReplyTo;
				case 'Sender'		: return $this->strSender;
				case 'To'		: return $this->strTo;
				case 'Subject': return $this->strSubject;
				case 'Body': return $this->strBody;
				case 'HtmlBody': return $this->strHtmlBody;

				case 'Cc': return $this->strCc;
				case 'Bcc': return $this->strBcc;

				case 'HeaderArray': return $this->strHeaderArray;
				case 'FileArray': return $this->objFileArray;
				case 'HasFiles': return (count($this->objFileArray) > 0) ? true : false;
				case 'EncodeSubject': return $this->blnEncodeSubject;

				default:
					try {
						return parent::__get($strName);
					} catch (QCallerException $objExc) {
						$objExc->IncrementOffset();
						throw $objExc;
					}
			}
		}

		public function __set($strName, $mixValue) {
			try {
				switch ($strName) {
					case 'From'	: return ($this->strFrom = QType::Cast($mixValue, QType::String));
					case 'ReplyTo'	: return ($this->strReplyTo = QType::Cast($mixValue, QType::String));
					case 'Sender'	: return ($this->strSender = QType::Cast($mixValue, QType::String));
					case 'To': return ($this->strTo = QType::Cast($mixValue, QType::String));
					case 'Subject':
						$strSubject = trim(QType::Cast($mixValue, QType::String));
						$strSubject = str_replace("\r", "", $strSubject);
						$strSubject = str_replace("\n", " ", $strSubject);
						return ($this->strSubject = $strSubject);
					case 'Body':
						$strBody = QType::Cast($mixValue, QType::String);
						$strBody = str_replace("\r", "", $strBody);
						$strBody = str_replace("\n", "\r\n", $strBody);
						$strBody = str_replace("\n.", "\n..", $strBody);
						return ($this->strBody = $strBody);
					case 'HtmlBody':
						$strHtmlBody = QType::Cast($mixValue, QType::String);
						$strHtmlBody = str_replace("\r", "", $strHtmlBody);
						$strHtmlBody = str_replace("\n", "\r\n", $strHtmlBody);
						$strHtmlBody = str_replace("\n.", "\n..", $strHtmlBody);
						return ($this->strHtmlBody = $strHtmlBody);

					case 'Cc': return ($this->strCc = QType::Cast($mixValue, QType::String));
					case 'Bcc': return ($this->strBcc = QType::Cast($mixValue, QType::String));
					case 'EncodeSubject': return ($this->blnEncodeSubject = QType::Cast($mixValue, QType::Boolean));

					default: return (parent::__set($strName, $mixValue));
				}
			} catch (QInvalidCastException $objExc) {
				$objExc->IncrementOffset();
				throw $objExc;
			}
		}
	}