v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT Template.php000064400000022601152101620500007021 0ustar00setFlags(self::ARRAY_AS_PROPS); $this->setArray(array( 'site_title' => Am_Di::getInstance()->config->get('site_title'), 'root_url' => ROOT_URL, 'admin_email' => Am_Di::getInstance()->config->get('admin_email'), )); } public function __call($name, $arguments) { if (strpos($name, 'set')===0) { $var = lcfirst(substr($name, 3)); $this[$var] = $arguments[0]; return $this; } trigger_error("Method [$name] does not exists in " . __CLASS__, E_USER_ERROR); } public function setArray(array $vars) { foreach ($vars as $k => $v) $this->$k = $v; return $this; } function setBcc($bcc) { $this->bcc = $bcc; } function setTemplate($format, $subject, $bodyText, $bodyHtml, $attachments, $id, $name, $layout = null) { // switch bodyText/bodyHtml based on format if (($format == 'text') && empty($bodyText)) { $bodyText = $bodyHtml; $bodyHtml = null; } elseif (($format == 'html') && empty($bodyHtml)) { $bodyHtml = $bodyText; $bodyText = null; } $this->template = array( 'format' => $format, 'subject' => $subject, 'bodyText' => $bodyText, 'bodyHtml' => $bodyHtml, 'attachments' => $attachments, 'id' => $id, 'name' => $name, 'layout' => $layout ); } /** @return Am_Mail */ function getMail() { if (!$this->mail) $this->mail = Am_Di::getInstance()->mail;; return $this->mail; } public function addTo($email, $name) { $this->getMail()->addTo($email, $name); } function parse() { Am_Di::getInstance()->hook->call(Am_Event::MAIL_TEMPLATE_BEFORE_PARSE, array( 'template' => $this, 'body' => !empty($this->template['bodyText']) ? $this->template['bodyText'] : $this->template['bodyHtml'], 'subject' => $this->template['subject'], 'mail' => $this->getMail() )); if($this->getMailPeriodic() == Am_Mail::REGULAR) $this->getMail()->addUnsubscribeLink(Am_Mail::LINK_USER); $this->subject = $this->_parse($this->template['subject']); $layout = $this->template['layout']; if ($_text = $this->template['bodyText']) { $this->text = $this->_parse($_text, $layout); } if ($_html = $this->template['bodyHtml']) { $html = $this->_parse($_html, $layout); $this->text = strip_tags($this->_parse($_html)); $this->html = strpos($html, '{$this->subject}$html" : $html; } $this->parseAttachments(); } protected function parseAttachments() { if(in_array($this->template['name'],array(EmailTemplate::AUTORESPONDER, EmailTemplate::EXPIRE, EmailTemplate::PRODUCTWELCOME, EmailTemplate::PAYMENT))) $upload = new Am_Upload(Am_Di::getInstance(), EmailTemplate::ATTACHMENT_AUTORESPONDER_EXPIRE_FILE_PREFIX); elseif(in_array($this->template['name'],array(EmailTemplate::PENDING_TO_ADMIN, EmailTemplate::PENDING_TO_USER))) $upload = new Am_Upload(Am_Di::getInstance(), EmailTemplate::ATTACHMENT_PENDING_FILE_PREFIX); else $upload = new Am_Upload(Am_Di::getInstance(), EmailTemplate::ATTACHMENT_FILE_PREFIX); $upload->unserialize($this->template['attachments']); foreach ($upload->getUploads() as $file) { $f = @fopen($file->getFullPath(), 'r'); if (!$f) { trigger_error("Could not open attachment [" . $file->getName() . "] for EmailTemplate#{$this->email_template_id}", E_USER_WARNING); continue; } $this->getMail()->createAttachment($f, $file->getType(), Zend_Mime::DISPOSITION_ATTACHMENT, Zend_Mime::ENCODING_BASE64, $file->getName()); } } protected function _parse($text, $layout = null) { $tpl = new Am_SimpleTemplate(); $tpl->assignStdVars(); $tpl->assign($this->getArrayCopy()); $tpl->assign(get_object_vars($this)); $text = $tpl->render($text); if ($layout) { $tpl->assign('content', $text); $text = $tpl->render($layout); } return $text; } function send($recepient, $transport = null) { try { $this->_send($recepient, $transport); } catch (Exception $e) { // Catch all exceptions here. If there is an issue with template, // other parts of the script should not be affected. Am_Di::getInstance()->errorLogTable->log($e); trigger_error("Could not send message - error happened: " . $e->getMessage(), E_USER_WARNING); } } protected function _send($recepient, $transport = null) { if (!$this->template) throw new Am_Exception_InternalError("Template was not set in " . __METHOD__); $this->getMail()->clearRecipients(); if ($this->bcc) { $this->getMail()->addBcc($this->bcc); } if ($recepient instanceof User) { $this->getMail()->addTo($email = $recepient->email, $recepient->getName()); } elseif ($recepient instanceof Admin) { $this->getMail()->addTo($email = $recepient->email, $recepient->getName()); } elseif ($recepient===self::TO_ADMIN) { $name = Am_Di::getInstance()->config->get('site_title') . ' Admin'; if($this->admins) { if(in_array(-1, $this->admins)) $this->addTo(Am_Di::getInstance()->config->get('admin_email'), Am_Di::getInstance()->config->get('site_title') . ' Admin'); foreach (Am_Di::getInstance()->adminTable->loadIds($this->admins) as $admin) $this->getMail()->addTo($admin->email, $admin->getName()); if ($copyAdmin = Am_Di::getInstance()->config->get('copy_admin_email')) foreach (preg_split("/[,;]/", $copyAdmin) as $copy) if ($copy) $this->getMail()->addBcc($copy); } else { $this->getMail()->toAdmin(); } } else { $this->getMail()->addTo($email = $recepient); } if (!$this->is_parsed) { $this->is_parsed = true; $this->parse(); $this->getMail()->setSubject($this->subject); } $this->getMail()->setBodyText($this->text); if ($this->html) { $this->getMail()->setBodyHtml($this->html); } $this->getMail()->setPeriodic($this->getMailPeriodic()); $this->getMail()->send($transport); } /** * Shortcut to email subscribed admins */ function sendAdmin() { $this->send(self::TO_ADMIN); } function getMailPeriodic() { return $this->_mailPeriodic; } function setMailPeriodic($periodic) { $this->_mailPeriodic = $periodic; } /** * @return Am_Mail_Template|null null if no template found */ static function load($id, $lang = null, $throwException = false) { $di = Am_Di::getInstance(); if(is_null($lang)) $lang = $di->locale->getLanguage(); list($lang,) = explode('_', $lang); $et = $di->emailTemplateTable->findFirstExact($id, $lang); if ($et) { return self::createFromEmailTemplate($et); } elseif ($throwException) throw new Am_Exception_Configuration("No e-mail template found for [$id,$lang]"); } /** @return Am_Mail_Template */ static function createFromEmailTemplate(EmailTemplate $et) { $t = new self; $t->setTemplate( $et->format, $et->subject, $et->plain_txt, $et->txt, $et->attachments, $et->email_template_id . '-' . $et->name . '-' . $et->lang, $et->name, $et->getLayout() ); $t->admins = array_filter(explode(',', $et->recipient_admins)); $rec = Am_Mail_TemplateTypes::getInstance()->find($et->name); if ($rec) $t->setMailPeriodic($rec['mailPeriodic']); $bcc = $et->bcc ? array_map('trim', explode (',', $et->bcc)) : array(); $t->setBcc($bcc); if ($et->reply_to && ($admin = $et->getDi()->adminTable->load($et->reply_to, false))) { $t->getMail()->setReplyTo($admin->email, $admin->getName()); } return $t; } function getConfig() { return $this->template; } } TemplateTypes.php000064400000033414152101620500010052 0ustar00offsetExists($id) ? $this->offsetGet($id) : null; } /** @return Am_Mail_TemplateTypes */ static function createInstance() { $o = new self; $o->tagSets = array( 'admin' => array( '%admin.name_f%' => ___('Admin First Name'), '%admin.name_l%' => ___('Admin Last Name'), '%admin.login%' => ___('Admin Username'), '%admin.email%' => ___('Admin E-Mail') ), 'user' => array( '%user.name_f%' => ___('User First Name'), '%user.name_l%' => ___('User Last Name'), '%user.login%' => ___('Username'), '%user.email%' => ___('E-Mail'), '%user.user_id%' => ___('User Internal ID#'), '%user.street%' => ___('User Street'), '%user.street2%' => ___('User Street (Second Line)'), '%user.city%' => ___('User City'), '%user.state%' => ___('User State'), '%user.zip%' => ___('User ZIP'), '%user.country%' => ___('User Country'), '%user.phone%' => ___('User Phone'), '%user.status%' => ___('User Status (0-pending, 1-active, 2-expired)') ), 'invoice' => array( '%invoice.invoice_id%' => ___('Invoice Internal ID#'), '%invoice.public_id%' => ___('Invoice Public ID#'), '%invoice.first_total%' => ___('Invoice First Total'), '%invoice.second_total%' => ___('Invoice Second Total'), ), 'payment' => array( '%payment.amount%' => ___('Payment Amount'), '%payment.currency%' => ___('Payment Currency'), '%payment.receipt_id%' => ___('Payment Receipt Id'), ) ); $table = Am_Di::getInstance()->userTable; $fields = $table->customFields()->getAll(); uksort($fields, array($table, 'sortCustomFields')); foreach ($fields as $field) { if (@$field->sql && @$field->from_config) { $o->tagSets['user']['%user.' . $field->name . '%'] = ___('User %s', $field->title); } } $o->tagSets['user']['%user.unsubscribe_link%'] = ___('User Unsubscribe Link'); $event = new Am_Event(Am_Event::EMAIL_TEMPLATE_TAG_SETS); $event->setReturn($o->tagSets); Am_Di::getInstance()->hook->call($event); $o->tagSets = $event->getReturn(); $event = new Am_Event(Am_Event::SETUP_EMAIL_TEMPLATE_TYPES); Am_Di::getInstance()->hook->call($event); $res = $event->getReturn(); $o->exchangeArray(array_merge(array( 'bruteforce_notify' => array( 'id' => 'bruteforce_notify', 'title' => ___('Bruteforce Notification'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'isAdmin' => true, 'vars' => array('ip' => ___('IP Address'), 'login' => ___('Last Used Login')) ), 'profile_changed' => array( 'id' => 'profile_changed', 'title' => ___('Profile Changed'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => array('user', 'changes' => ___('Changes in User Profile')) ), 'registration_mail' => array( 'id' => 'registration_mail', 'title' => 'Registration E-Mail', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user', 'password' => ___('Plain-Text Password')), ), 'registration_mail_admin' => array( 'id' => 'registration_mail_admin', 'title' => 'Registration E-Mail to Admin', 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'isAdmin' => true, 'vars' => array('user', 'password' => ___('Plain-Text Password')), ), 'changepass_mail' => array( 'id' => 'changepass_mail', 'title' => ___('Password Change E-Mail'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user', 'password' => 'Plain-Text Password'), ), 'send_signup_mail' => array( 'id' => 'send_signup_mail', 'title' => ___('Send Signup Mail'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user'), ), 'mail_payment_admin' => array( 'id' => 'mail_payment_admin', 'title' => ___('Mail Payment Admin'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user'), ), 'send_payment_mail' => array( 'id' => 'send_payment_mail', 'title' => ___('Send Payment Mail'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user','invoice','product_title'=> ___('Product(s) Title')), ), 'send_payment_admin' => array( 'id' => 'send_payment_admin', 'title' => ___('Send Payment Admin'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => array('user','invoice','product_title'=> ___('Product(s) Title')), ), 'manually_approve' => array( 'id' => 'manually_approve', 'title' => ___('Manually Approve'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'vars' => array('user'), ), 'manually_approve_admin' => array( 'id' => 'manually_approve_admin', 'title' => ___('Manually Approve Admin'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'isAdmin' => true, 'vars' => array('user'), ), 'invoice_approval_wait_user' => array( 'id' => 'invoice_approval_wait_user', 'title' => ___('Manually Approve Invoice'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'vars' => array('user','invoice'), ), 'invoice_pay_link' => array( 'id' => 'invoice_pay_link', 'title' => 'Payment Link for Invoice', 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'vars' => array( 'invoice_text' => ___('Invoice Text'), 'product_title' => ___('Product Title'), 'url' => ___('Payment Link'), 'message' => ___('Your Message'), 'user', 'invoice'), ), 'invoice_approval_wait_admin' => array( 'id' => 'invoice_approval_wait_admin', 'title' => ___('Manually Approve Invoice Admin'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'isAdmin' => true, 'vars' => array('user', 'invoice'), ), 'invoice_approved_user' => array( 'id' => 'invoice_approved_user', 'title' => ___('Invoice Approved'), 'mailPeriodic' => Am_Mail::ADMIN_REQUESTED, 'vars' => array('user', 'invoice'), ), 'card_expires' => array( 'id' => 'card_expires', 'title' => ___('Card Expires'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user'), ), 'send_security_code' => array( 'id' => 'send_security_code', 'title' => ___('Send Security Code'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user', 'code' => ___('Security Code'), 'url' => ___('Click Url')), ), 'verify_email_signup' => array( 'id' => 'verify_email_signup', 'title' => ___('Verify Email Signup'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user', 'url' => ___('Email Confirmation URL')), ), 'verify_email_profile' => array( 'id' => 'verify_email_profile', 'title' => ___('Verify Email Profile'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user', 'url' => ___('Email Confirmation URL')), ), 'autoresponder' => array( 'id' => 'autoresponder', 'title' => ___('Auto-Responder'), 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array('user', 'last_product_title' => ___('Product Title of the Latest Purchased Product')), ), 'productwelcome' => array( 'id' => 'productwelcome', 'title' => ___('Product Welcome E-mail'), 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array('user', 'invoice', 'payment', 'last_product_title' => ___('Product Title of the Latest Purchased Product')), ), 'payment' => array( 'id' => 'payment', 'title' => ___('Payment E-mail'), 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array('user', 'invoice', 'payment'), ), 'expire' => array( 'id' => 'expire', 'title' => ___('Expiration E-Mail'), 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array('user', 'expires' => ___('Expiration Date'), 'product_title' => ___('Expire Product Title')), ), 'pending_to_user' => array( 'id' => 'pending_to_user', 'title' => ___('Pending Invoice Notifications to User'), 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array('user', 'invoice', 'invoice_text' => ___('Invoice Text'), 'day'=> ___('Day of Notification Sending'), 'product_title'=> ___('Product(s) Title'), 'paylink' => ___('Payment Link to Complete Pending Invoice') ), ), 'pending_to_admin' => array( 'id' => 'pending_to_admin', 'title' => ___('Pending Invoice Notifications to Admin'), 'mailPeriodic' => Am_Mail::REGULAR, 'isAdmin' => true, 'vars' => array('user', 'invoice', 'invoice_text' => ___('Invoice Text'), 'day'=>___('Day of Notification Sending'), 'product_title'=>___('Product(s) Title')), ), 'max_ip_actions_admin' => array( 'id' => 'max_ip_actions_admin', 'title' => ___('Email admin regarding account sharing'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => array('user'), ), 'max_ip_actions_user' => array( 'id' => 'max_ip_actions_user', 'title' => ___('Email user regarding account sharing'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user'), ), 'mail_cancel_member' => array( 'id' => 'mail_cancel_member', 'title' => ___('Send Cancel Notifications to User'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array('user', 'invoice'), ), 'mail_cancel_admin' => array( 'id' => 'mail_cancel_admin', 'title' => ___('Send Cancel Notifications to Admin'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => array('user', 'invoice'), ), 'send_free_payment_admin' => array( 'id' => 'send_free_payment_admin', 'title' => ___('Send Free Payment Admin'), 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => array('user','invoice'), ), ), $res)); return $o; } /** * Return array - key => value of available options for template with given $id * @param type $id * @return array */ public function getTagsOptions($id) { $record = @$this[$id]; $ret = array( '%site_title%' => ___('Site Title'), '%root_url%' => ___('aMember Root URL'), '%admin_email%' => ___('Admin E-Mail Address'), ); if (!$record || empty($record['vars'])) return $ret; foreach ($record['vars'] as $k => $v) { if (is_int($k)) // tag set $ret = array_merge($ret, $this->tagSets[$v]); else // single variable $ret['%'.$k.'%'] = $v; } $event = new Am_Event(Am_Event::EMAIL_TEMPLATE_TAG_OPTIONS, array('templateName' => $id)); $event->setReturn($ret); Am_Di::getInstance()->hook->call($event); $ret = $event->getReturn(); return $ret; } public function add($id, $title, $mailPeriodic, array $vars) { $this[$id] = array('id' => $id, 'title' => $title, 'mailPeriodic' => $mailPeriodic, 'vars' => $vars); } } Part.php000064400000036571152101624100006167 0ustar00 value) or string, if a content part is found it's used as toplines * - noToplines ignore content found after headers in param 'headers' * - content content as string * * @param array $params full message with or without headers * @throws Zend_Mail_Exception */ public function __construct(array $params) { if (isset($params['handler'])) { if (!$params['handler'] instanceof Zend_Mail_Storage_Abstract) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('handler is not a valid mail handler'); } if (!isset($params['id'])) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('need a message id with a handler'); } $this->_mail = $params['handler']; $this->_messageNum = $params['id']; } if (isset($params['partclass'])) { $this->setPartClass($params['partclass']); } if (isset($params['raw'])) { Zend_Mime_Decode::splitMessage($params['raw'], $this->_headers, $this->_content); } else if (isset($params['headers'])) { if (is_array($params['headers'])) { $this->_headers = $params['headers']; } else { if (!empty($params['noToplines'])) { Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $null); } else { Zend_Mime_Decode::splitMessage($params['headers'], $this->_headers, $this->_topLines); } } if (isset($params['content'])) { $this->_content = $params['content']; } } } /** * Set name pf class used to encapsulate message parts * @param string $class * @return Zend_Mail_Part */ public function setPartClass($class) { if ( !class_exists($class) ) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception("Class '{$class}' does not exist"); } if ( !is_subclass_of($class, 'Zend_Mail_Part_Interface') ) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception("Class '{$class}' must implement Zend_Mail_Part_Interface"); } $this->_partClass = $class; return $this; } /** * Retrieve the class name used to encapsulate message parts * @return string */ public function getPartClass() { if ( !$this->_partClass ) { $this->_partClass = __CLASS__; } return $this->_partClass; } /** * Check if part is a multipart message * * @return bool if part is multipart */ public function isMultipart() { try { return stripos($this->contentType, 'multipart/') === 0; } catch(Zend_Mail_Exception $e) { return false; } } /** * Body of part * * If part is multipart the raw content of this part with all sub parts is returned * * @return string body * @throws Zend_Mail_Exception */ public function getContent() { if ($this->_content !== null) { return $this->_content; } if ($this->_mail) { return $this->_mail->getRawContent($this->_messageNum); } else { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('no content'); } } /** * Return size of part * * Quite simple implemented currently (not decoding). Handle with care. * * @return int size */ public function getSize() { return strlen($this->getContent()); } /** * Cache content and split in parts if multipart * * @return null * @throws Zend_Mail_Exception */ protected function _cacheContent() { // caching content if we can't fetch parts if ($this->_content === null && $this->_mail) { $this->_content = $this->_mail->getRawContent($this->_messageNum); } if (!$this->isMultipart()) { return; } // split content in parts $boundary = $this->getHeaderField('content-type', 'boundary'); if (!$boundary) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('no boundary found in content type to split message'); } $parts = Zend_Mime_Decode::splitMessageStruct($this->_content, $boundary); if ($parts === null) { return; } $partClass = $this->getPartClass(); $counter = 1; foreach ($parts as $part) { $this->_parts[$counter++] = new $partClass(array('headers' => $part['header'], 'content' => $part['body'])); } } /** * Get part of multipart message * * @param int $num number of part starting with 1 for first part * @return Zend_Mail_Part wanted part * @throws Zend_Mail_Exception */ public function getPart($num) { if (isset($this->_parts[$num])) { return $this->_parts[$num]; } if (!$this->_mail && $this->_content === null) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('part not found'); } if ($this->_mail && $this->_mail->hasFetchPart) { // TODO: fetch part // return } $this->_cacheContent(); if (!isset($this->_parts[$num])) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('part not found'); } return $this->_parts[$num]; } /** * Count parts of a multipart part * * @return int number of sub-parts */ public function countParts() { if ($this->_countParts) { return $this->_countParts; } $this->_countParts = count($this->_parts); if ($this->_countParts) { return $this->_countParts; } if ($this->_mail && $this->_mail->hasFetchPart) { // TODO: fetch part // return } $this->_cacheContent(); $this->_countParts = count($this->_parts); return $this->_countParts; } /** * Get all headers * * The returned headers are as saved internally. All names are lowercased. The value is a string or an array * if a header with the same name occurs more than once. * * @return array headers as array(name => value) */ public function getHeaders() { if ($this->_headers === null) { if (!$this->_mail) { $this->_headers = array(); } else { $part = $this->_mail->getRawHeader($this->_messageNum); Zend_Mime_Decode::splitMessage($part, $this->_headers, $null); } } return $this->_headers; } /** * Get a header in specificed format * * Internally headers that occur more than once are saved as array, all other as string. If $format * is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim). * * @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes * @param string $format change type of return value to 'string' or 'array' * @return string|array value of header in wanted or internal format * @throws Zend_Mail_Exception */ public function getHeader($name, $format = null) { if ($this->_headers === null) { $this->getHeaders(); } $lowerName = strtolower($name); if ($this->headerExists($name) == false) { $lowerName = strtolower(preg_replace('%([a-z])([A-Z])%', '\1-\2', $name)); if($this->headerExists($lowerName) == false) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception("no Header with Name $name or $lowerName found"); } } $name = $lowerName; $header = $this->_headers[$name]; switch ($format) { case 'string': if (is_array($header)) { $header = implode(Zend_Mime::LINEEND, $header); } break; case 'array': $header = (array)$header; default: // do nothing } return $header; } /** * Check wheater the Mail part has a specific header. * * @param string $name * @return boolean */ public function headerExists($name) { $name = strtolower($name); if(isset($this->_headers[$name])) { return true; } else { return false; } } /** * Get a specific field from a header like content type or all fields as array * * If the header occurs more than once, only the value from the first header * is returned. * * Throws a Zend_Mail_Exception if the requested header does not exist. If * the specific header field does not exist, returns null. * * @param string $name name of header, like in getHeader() * @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned * @param string $firstName key name for the first part * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value) * @throws Zend_Exception, Zend_Mail_Exception */ public function getHeaderField($name, $wantedPart = 0, $firstName = 0) { return Zend_Mime_Decode::splitHeaderField(current($this->getHeader($name, 'array')), $wantedPart, $firstName); } /** * Getter for mail headers - name is matched in lowercase * * This getter is short for Zend_Mail_Part::getHeader($name, 'string') * * @see Zend_Mail_Part::getHeader() * * @param string $name header name * @return string value of header * @throws Zend_Mail_Exception */ public function __get($name) { return $this->getHeader($name, 'string'); } /** * Isset magic method proxy to hasHeader * * This method is short syntax for Zend_Mail_Part::hasHeader($name); * * @see Zend_Mail_Part::hasHeader * * @param string * @return boolean */ public function __isset($name) { return $this->headerExists($name); } /** * magic method to get content of part * * @return string content */ public function __toString() { return $this->getContent(); } /** * implements RecursiveIterator::hasChildren() * * @return bool current element has children/is multipart */ public function hasChildren() { $current = $this->current(); return $current && $current instanceof Zend_Mail_Part && $current->isMultipart(); } /** * implements RecursiveIterator::getChildren() * * @return Zend_Mail_Part same as self::current() */ public function getChildren() { return $this->current(); } /** * implements Iterator::valid() * * @return bool check if there's a current element */ public function valid() { if ($this->_countParts === null) { $this->countParts(); } return $this->_iterationPos && $this->_iterationPos <= $this->_countParts; } /** * implements Iterator::next() * * @return null */ public function next() { ++$this->_iterationPos; } /** * implements Iterator::key() * * @return string key/number of current part */ public function key() { return $this->_iterationPos; } /** * implements Iterator::current() * * @return Zend_Mail_Part current part */ public function current() { return $this->getPart($this->_iterationPos); } /** * implements Iterator::rewind() * * @return null */ public function rewind() { $this->countParts(); $this->_iterationPos = 1; } } Part/Interface.php000064400000010114152101624100010050 0ustar00 value) */ public function getHeaders(); /** * Get a header in specificed format * * Internally headers that occur more than once are saved as array, all other as string. If $format * is set to string implode is used to concat the values (with Zend_Mime::LINEEND as delim). * * @param string $name name of header, matches case-insensitive, but camel-case is replaced with dashes * @param string $format change type of return value to 'string' or 'array' * @return string|array value of header in wanted or internal format * @throws Zend_Mail_Exception */ public function getHeader($name, $format = null); /** * Get a specific field from a header like content type or all fields as array * * If the header occurs more than once, only the value from the first header * is returned. * * Throws a Zend_Mail_Exception if the requested header does not exist. If * the specific header field does not exist, returns null. * * @param string $name name of header, like in getHeader() * @param string $wantedPart the wanted part, default is first, if null an array with all parts is returned * @param string $firstName key name for the first part * @return string|array wanted part or all parts as array($firstName => firstPart, partname => value) * @throws Zend_Exception, Zend_Mail_Exception */ public function getHeaderField($name, $wantedPart = 0, $firstName = 0); /** * Getter for mail headers - name is matched in lowercase * * This getter is short for Zend_Mail_Part::getHeader($name, 'string') * * @see Zend_Mail_Part::getHeader() * * @param string $name header name * @return string value of header * @throws Zend_Mail_Exception */ public function __get($name); /** * magic method to get content of part * * @return string content */ public function __toString(); } Part/File.php000064400000013774152101624100007046 0ustar00_fh = fopen($params['file'], 'r'); } else { $this->_fh = $params['file']; } if (!$this->_fh) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('could not open file'); } if (isset($params['startPos'])) { fseek($this->_fh, $params['startPos']); } $header = ''; $endPos = isset($params['endPos']) ? $params['endPos'] : null; while (($endPos === null || ftell($this->_fh) < $endPos) && trim($line = fgets($this->_fh))) { $header .= $line; } Zend_Mime_Decode::splitMessage($header, $this->_headers, $null); $this->_contentPos[0] = ftell($this->_fh); if ($endPos !== null) { $this->_contentPos[1] = $endPos; } else { fseek($this->_fh, 0, SEEK_END); $this->_contentPos[1] = ftell($this->_fh); } if (!$this->isMultipart()) { return; } $boundary = $this->getHeaderField('content-type', 'boundary'); if (!$boundary) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('no boundary found in content type to split message'); } $part = array(); $pos = $this->_contentPos[0]; fseek($this->_fh, $pos); while (!feof($this->_fh) && ($endPos === null || $pos < $endPos)) { $line = fgets($this->_fh); if ($line === false) { if (feof($this->_fh)) { break; } /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('error reading file'); } $lastPos = $pos; $pos = ftell($this->_fh); $line = trim($line); if ($line == '--' . $boundary) { if ($part) { // not first part $part[1] = $lastPos; $this->_partPos[] = $part; } $part = array($pos); } else if ($line == '--' . $boundary . '--') { $part[1] = $lastPos; $this->_partPos[] = $part; break; } } $this->_countParts = count($this->_partPos); } /** * Body of part * * If part is multipart the raw content of this part with all sub parts is returned * * @return string body * @throws Zend_Mail_Exception */ public function getContent($stream = null) { fseek($this->_fh, $this->_contentPos[0]); if ($stream !== null) { return stream_copy_to_stream($this->_fh, $stream, $this->_contentPos[1] - $this->_contentPos[0]); } $length = $this->_contentPos[1] - $this->_contentPos[0]; return $length < 1 ? '' : fread($this->_fh, $length); } /** * Return size of part * * Quite simple implemented currently (not decoding). Handle with care. * * @return int size */ public function getSize() { return $this->_contentPos[1] - $this->_contentPos[0]; } /** * Get part of multipart message * * @param int $num number of part starting with 1 for first part * @return Zend_Mail_Part wanted part * @throws Zend_Mail_Exception */ public function getPart($num) { --$num; if (!isset($this->_partPos[$num])) { /** * @see Zend_Mail_Exception */ //--//require_once 'Zend/Mail/Exception.php'; throw new Zend_Mail_Exception('part not found'); } return new self(array('file' => $this->_fh, 'startPos' => $this->_partPos[$num][0], 'endPos' => $this->_partPos[$num][1])); } } Message/Interface.php000064400000002763152101624100010541 0ustar00_flags = array_combine($params['flags'], $params['flags']); } parent::__construct($params); } /** * return toplines as found after headers * * @return string toplines */ public function getTopLines() { return $this->_topLines; } /** * check if flag is set * * @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage * @return bool true if set, otherwise false */ public function hasFlag($flag) { return isset($this->_flags[$flag]); } /** * get all set flags * * @return array array with flags, key and value are the same for easy lookup */ public function getFlags() { return $this->_flags; } } Protocol/Abstract.php000064400000025765152101624100010630 0ustar00_validHost = new Am_Util_Dummy_Zend_Validate(); //$this->_validHost->addValidator(new Zend_Validate_Hostname(Zend_Validate_Hostname::ALLOW_ALL)); if (!$this->_validHost->isValid($host)) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages())); } $this->_host = $host; $this->_port = $port; } /** * Class destructor to cleanup open resources * * @return void */ public function __destruct() { $this->_disconnect(); } /** * Set the maximum log size * * @param integer $maximumLog Maximum log size * @return void */ public function setMaximumLog($maximumLog) { $this->_maximumLog = (int) $maximumLog; } /** * Get the maximum log size * * @return int the maximum log size */ public function getMaximumLog() { return $this->_maximumLog; } /** * Create a connection to the remote host * * Concrete adapters for this class will implement their own unique connect scripts, using the _connect() method to create the socket resource. */ abstract public function connect(); /** * Retrieve the last client request * * @return string */ public function getRequest() { return $this->_request; } /** * Retrieve the last server response * * @return array */ public function getResponse() { return $this->_response; } /** * Retrieve the transaction log * * @return string */ public function getLog() { return implode('', $this->_log); } /** * Reset the transaction log * * @return void */ public function resetLog() { $this->_log = array(); } /** * Add the transaction log * * @param string new transaction * @return void */ protected function _addLog($value) { if ($this->_maximumLog >= 0 && count($this->_log) >= $this->_maximumLog) { array_shift($this->_log); } $this->_log[] = $value; } /** * Connect to the server using the supplied transport and target * * An example $remote string may be 'tcp://mail.example.com:25' or 'ssh://hostname.com:2222' * * @param string $remote Remote * @throws Zend_Mail_Protocol_Exception * @return boolean */ protected function _connect($remote) { $errorNum = 0; $errorStr = ''; // open connection $this->_socket = @stream_socket_client($remote, $errorNum, $errorStr, self::TIMEOUT_CONNECTION); if ($this->_socket === false) { if ($errorNum == 0) { $errorStr = 'Could not open socket'; } /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception($errorStr); } if (($result = $this->_setStreamTimeout(self::TIMEOUT_CONNECTION)) === false) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('Could not set stream timeout'); } return $result; } /** * Disconnect from remote host and free resource * * @return void */ protected function _disconnect() { if (is_resource($this->_socket)) { fclose($this->_socket); } } /** * Send the given request followed by a LINEEND to the server. * * @param string $request * @throws Zend_Mail_Protocol_Exception * @return integer|boolean Number of bytes written to remote host */ protected function _send($request) { if (!is_resource($this->_socket)) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host); } $this->_request = $request; $result = fwrite($this->_socket, $request . self::EOL); // Save request to internal log $this->_addLog($request . self::EOL); if ($result === false) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('Could not send request to ' . $this->_host); } return $result; } /** * Get a line from the stream. * * @var integer $timeout Per-request timeout value if applicable * @throws Zend_Mail_Protocol_Exception * @return string */ protected function _receive($timeout = null) { if (!is_resource($this->_socket)) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('No connection has been established to ' . $this->_host); } // Adapters may wish to supply per-commend timeouts according to appropriate RFC if ($timeout !== null) { $this->_setStreamTimeout($timeout); } // Retrieve response $reponse = fgets($this->_socket, 1024); // Save request to internal log $this->_addLog($reponse); // Check meta data to ensure connection is still valid $info = stream_get_meta_data($this->_socket); if (!empty($info['timed_out'])) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception($this->_host . ' has timed out'); } if ($reponse === false) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('Could not read from ' . $this->_host); } return $reponse; } /** * Parse server response for successful codes * * Read the response from the stream and check for expected return code. * Throws a Zend_Mail_Protocol_Exception if an unexpected code is returned. * * @param string|array $code One or more codes that indicate a successful response * @throws Zend_Mail_Protocol_Exception * @return string Last line of response string */ protected function _expect($code, $timeout = null) { $this->_response = array(); $cmd = ''; $more = ''; $msg = ''; $errMsg = ''; if (!is_array($code)) { $code = array($code); } do { $this->_response[] = $result = $this->_receive($timeout); list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE); if ($errMsg !== '') { $errMsg .= ' ' . $msg; } elseif ($cmd === null || !in_array($cmd, $code)) { $errMsg = $msg; } } while (strpos($more, '-') === 0); // The '-' message prefix indicates an information string instead of a response string. if ($errMsg !== '') { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception($errMsg, $cmd); } return $msg; } /** * Set stream timeout * * @param integer $timeout * @return boolean */ protected function _setStreamTimeout($timeout) { return stream_set_timeout($this->_socket, $timeout); } } Protocol/Smtp/Auth/Plain.php000064400000004575152101624100011750 0ustar00_username = $config['username']; } if (isset($config['password'])) { $this->_password = $config['password']; } } parent::__construct($host, $port, $config); } /** * Perform PLAIN authentication with supplied credentials * * @return void */ public function auth() { // Ensure AUTH has not already been initiated. parent::auth(); $this->_send('AUTH PLAIN'); $this->_expect(334); $this->_send(base64_encode("\0" . $this->_username . "\0" . $this->_password)); $this->_expect(235); $this->_auth = true; } } Protocol/Smtp/Auth/Login.php000064400000004660152101624100011750 0ustar00_username = $config['username']; } if (isset($config['password'])) { $this->_password = $config['password']; } } parent::__construct($host, $port, $config); } /** * Perform LOGIN authentication with supplied credentials * * @return void */ public function auth() { // Ensure AUTH has not already been initiated. parent::auth(); $this->_send('AUTH LOGIN'); $this->_expect(334); $this->_send(base64_encode($this->_username)); $this->_expect(334); $this->_send(base64_encode($this->_password)); $this->_expect(235); $this->_auth = true; } } Protocol/Smtp/Auth/Crammd5.php000064400000006057152101624100012172 0ustar00_username = $config['username']; } if (isset($config['password'])) { $this->_password = $config['password']; } } parent::__construct($host, $port, $config); } /** * @todo Perform CRAM-MD5 authentication with supplied credentials * * @return void */ public function auth() { // Ensure AUTH has not already been initiated. parent::auth(); $this->_send('AUTH CRAM-MD5'); $challenge = $this->_expect(334); $challenge = base64_decode($challenge); $digest = $this->_hmacMd5($this->_password, $challenge); $this->_send(base64_encode($this->_username . ' ' . $digest)); $this->_expect(235); $this->_auth = true; } /** * Prepare CRAM-MD5 response to server's ticket * * @param string $key Challenge key (usually password) * @param string $data Challenge data * @param string $block Length of blocks * @return string */ protected function _hmacMd5($key, $data, $block = 64) { if (strlen($key) > 64) { $key = pack('H32', md5($key)); } elseif (strlen($key) < 64) { $key = str_pad($key, $block, "\0"); } $k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64); $k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64); $inner = pack('H32', md5($k_ipad . $data)); $digest = md5($k_opad . $inner); return $digest; } } Protocol/Smtp.php000064400000027150152101624100007776 0ustar00_secure = 'tls'; break; case 'ssl': $this->_transport = 'ssl'; $this->_secure = 'ssl'; if ($port == null) { $port = 465; } break; default: /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception($config['ssl'] . ' is unsupported SSL type'); break; } } // If no port has been specified then check the master PHP ini file. Defaults to 25 if the ini setting is null. if ($port == null) { if (($port = ini_get('smtp_port')) == '') { $port = 25; } } parent::__construct($host, $port); } /** * Connect to the server with the parameters given in the constructor. * * @return boolean */ public function connect() { return $this->_connect($this->_transport . '://' . $this->_host . ':'. $this->_port); } /** * Initiate HELO/EHLO sequence and set flag to indicate valid smtp session * * @param string $host The client hostname or IP address (default: 127.0.0.1) * @throws Zend_Mail_Protocol_Exception * @return void */ public function helo($host = '127.0.0.1') { // Respect RFC 2821 and disallow HELO attempts if session is already initiated. if ($this->_sess === true) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('Cannot issue HELO to existing session'); } // Validate client hostname if (!$this->_validHost->isValid($host)) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception(join(', ', $this->_validHost->getMessages())); } // Initiate helo sequence $this->_expect(220, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 $this->_ehlo($host); // If a TLS session is required, commence negotiation if ($this->_secure == 'tls') { $this->_send('STARTTLS'); $this->_expect(220, 180); if (!stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('Unable to connect via TLS'); } $this->_ehlo($host); } $this->_startSession(); $this->auth(); } /** * Send EHLO or HELO depending on capabilities of smtp host * * @param string $host The client hostname or IP address (default: 127.0.0.1) * @throws Zend_Mail_Protocol_Exception * @return void */ protected function _ehlo($host) { // Support for older, less-compliant remote servers. Tries multiple attempts of EHLO or HELO. try { $this->_send('EHLO ' . $host); $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 } catch (Zend_Mail_Protocol_Exception $e) { $this->_send('HELO ' . $host); $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 } catch (Zend_Mail_Protocol_Exception $e) { throw $e; } } /** * Issues MAIL command * * @param string $from Sender mailbox * @throws Zend_Mail_Protocol_Exception * @return void */ public function mail($from) { if ($this->_sess !== true) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('A valid session has not been started'); } $this->_send('MAIL FROM:<' . $from . '>'); $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 // Set mail to true, clear recipients and any existing data flags as per 4.1.1.2 of RFC 2821 $this->_mail = true; $this->_rcpt = false; $this->_data = false; } /** * Issues RCPT command * * @param string $to Receiver(s) mailbox * @throws Zend_Mail_Protocol_Exception * @return void */ public function rcpt($to) { if ($this->_mail !== true) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('No sender reverse path has been supplied'); } // Set rcpt to true, as per 4.1.1.3 of RFC 2821 $this->_send('RCPT TO:<' . $to . '>'); $this->_expect(array(250, 251), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 $this->_rcpt = true; } /** * Issues DATA command * * @param string $data * @throws Zend_Mail_Protocol_Exception * @return void */ public function data($data) { // Ensure recipients have been set if ($this->_rcpt !== true) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('No recipient forward path has been supplied'); } $this->_send('DATA'); $this->_expect(354, 120); // Timeout set for 2 minutes as per RFC 2821 4.5.3.2 foreach (explode(Zend_Mime::LINEEND, $data) as $line) { if (strpos($line, '.') === 0) { // Escape lines prefixed with a '.' $line = '.' . $line; } $this->_send($line); } $this->_send('.'); $this->_expect(250, 600); // Timeout set for 10 minutes as per RFC 2821 4.5.3.2 $this->_data = true; } /** * Issues the RSET command and validates answer * * Can be used to restore a clean smtp communication state when a transaction has been cancelled or commencing a new transaction. * * @return void */ public function rset() { $this->_send('RSET'); // MS ESMTP doesn't follow RFC, see [ZF-1377] $this->_expect(array(250, 220)); $this->_mail = false; $this->_rcpt = false; $this->_data = false; } /** * Issues the NOOP command and validates answer * * Not used by Zend_Mail, could be used to keep a connection alive or check if it is still open. * * @return void */ public function noop() { $this->_send('NOOP'); $this->_expect(250, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 } /** * Issues the VRFY command and validates answer * * Not used by Zend_Mail. * * @param string $user User Name or eMail to verify * @return void */ public function vrfy($user) { $this->_send('VRFY ' . $user); $this->_expect(array(250, 251, 252), 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 } /** * Issues the QUIT command and clears the current session * * @return void */ public function quit() { if ($this->_sess) { $this->_send('QUIT'); $this->_expect(221, 300); // Timeout set for 5 minutes as per RFC 2821 4.5.3.2 $this->_stopSession(); } } /** * Default authentication method * * This default method is implemented by AUTH adapters to properly authenticate to a remote host. * * @throws Zend_Mail_Protocol_Exception * @return void */ public function auth() { if ($this->_auth === true) { /** * @see Zend_Mail_Protocol_Exception */ //--//require_once 'Zend/Mail/Protocol/Exception.php'; throw new Zend_Mail_Protocol_Exception('Already authenticated for this session'); } } /** * Closes connection * * @return void */ public function disconnect() { $this->_disconnect(); } /** * Start mail session * * @return void */ protected function _startSession() { $this->_sess = true; } /** * Stop mail session * * @return void */ protected function _stopSession() { $this->_sess = false; } } Protocol/Exception.php000064400000002127152101624100011006 0ustar00toArray(); } if (is_array($parameters)) { $parameters = implode(' ', $parameters); } $this->parameters = $parameters; } /** * Send mail using PHP native mail() * * @access public * @return void * @throws Zend_Mail_Transport_Exception if parameters is set * but not a string * @throws Zend_Mail_Transport_Exception on mail() failure */ public function _sendMail() { if ($this->parameters === null) { set_error_handler(array($this, '_handleMailErrors')); $result = mail( $this->recipients, $this->_mail->getSubject(), $this->body, $this->header); restore_error_handler(); } else { if(!is_string($this->parameters)) { /** * @see Zend_Mail_Transport_Exception * * Exception is thrown here because * $parameters is a public property */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception( 'Parameters were set but are not a string' ); } set_error_handler(array($this, '_handleMailErrors')); $result = mail( $this->recipients, $this->_mail->getSubject(), $this->body, $this->header, $this->parameters); restore_error_handler(); } if ($this->_errstr !== null || !$result) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('Unable to send mail. ' . $this->_errstr); } } /** * Format and fix headers * * mail() uses its $to and $subject arguments to set the To: and Subject: * headers, respectively. This method strips those out as a sanity check to * prevent duplicate header entries. * * @access protected * @param array $headers * @return void * @throws Zend_Mail_Transport_Exception */ protected function _prepareHeaders($headers) { if (!$this->_mail) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object'); } // mail() uses its $to parameter to set the To: header, and the $subject // parameter to set the Subject: header. We need to strip them out. if (0 === strpos(PHP_OS, 'WIN')) { // If the current recipients list is empty, throw an error if (empty($this->recipients)) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('Missing To addresses'); } } else { // All others, simply grab the recipients and unset the To: header if (!isset($headers['To'])) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('Missing To header'); } unset($headers['To']['append']); $this->recipients = implode(',', $headers['To']); } // Remove recipient header unset($headers['To']); // Remove subject header, if present if (isset($headers['Subject'])) { unset($headers['Subject']); } // Prepare headers parent::_prepareHeaders($headers); // Fix issue with empty blank line ontop when using Sendmail Trnasport $this->header = rtrim($this->header); } /** * Temporary error handler for PHP native mail(). * * @param int $errno * @param string $errstr * @param string $errfile * @param string $errline * @param array $errcontext * @return true */ public function _handleMailErrors($errno, $errstr, $errfile = null, $errline = null, array $errcontext = null) { $this->_errstr = $errstr; return true; } } Transport/Abstract.php000064400000024211152101624100011004 0ustar00_mail->getType(); if (!$type) { if ($this->_mail->hasAttachments) { $type = Zend_Mime::MULTIPART_MIXED; } elseif ($this->_mail->getBodyText() && $this->_mail->getBodyHtml()) { $type = Zend_Mime::MULTIPART_ALTERNATIVE; } else { $type = Zend_Mime::MULTIPART_MIXED; } } $this->_headers['Content-Type'] = array( $type . ';' . $this->EOL . " " . 'boundary="' . $boundary . '"' ); $this->boundary = $boundary; } $this->_headers['MIME-Version'] = array('1.0'); return $this->_headers; } /** * Prepend header name to header value * * @param string $item * @param string $key * @param string $prefix * @static * @access protected * @return void */ protected static function _formatHeader(&$item, $key, $prefix) { $item = $prefix . ': ' . $item; } /** * Prepare header string for use in transport * * Prepares and generates {@link $header} based on the headers provided. * * @param mixed $headers * @access protected * @return void * @throws Zend_Mail_Transport_Exception if any header lines exceed 998 * characters */ protected function _prepareHeaders($headers) { if (!$this->_mail) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('Missing Zend_Mail object in _mail property'); } $this->header = ''; foreach ($headers as $header => $content) { if (isset($content['append'])) { unset($content['append']); $value = implode(',' . $this->EOL . ' ', $content); $this->header .= $header . ': ' . $value . $this->EOL; } else { array_walk($content, array(get_class($this), '_formatHeader'), $header); $this->header .= implode($this->EOL, $content) . $this->EOL; } } // Sanity check on headers -- should not be > 998 characters $sane = true; foreach (explode($this->EOL, $this->header) as $line) { if (strlen(trim($line)) > 998) { $sane = false; break; } } if (!$sane) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Exception('At least one mail header line is too long'); } } /** * Generate MIME compliant message from the current configuration * * If both a text and HTML body are present, generates a * multipart/alternative Zend_Mime_Part containing the headers and contents * of each. Otherwise, uses whichever of the text or HTML parts present. * * The content part is then prepended to the list of Zend_Mime_Parts for * this message. * * @return void */ protected function _buildBody() { if (($text = $this->_mail->getBodyText()) && ($html = $this->_mail->getBodyHtml())) { // Generate unique boundary for multipart/alternative $mime = new Zend_Mime(null); $boundaryLine = $mime->boundaryLine($this->EOL); $boundaryEnd = $mime->mimeEnd($this->EOL); $text->disposition = false; $html->disposition = false; $body = $boundaryLine . $text->getHeaders($this->EOL) . $this->EOL . $text->getContent($this->EOL) . $this->EOL . $boundaryLine . $html->getHeaders($this->EOL) . $this->EOL . $html->getContent($this->EOL) . $this->EOL . $boundaryEnd; $mp = new Zend_Mime_Part($body); $mp->type = Zend_Mime::MULTIPART_ALTERNATIVE; $mp->boundary = $mime->boundary(); $this->_isMultipart = true; // Ensure first part contains text alternatives array_unshift($this->_parts, $mp); // Get headers $this->_headers = $this->_mail->getHeaders(); return; } // If not multipart, then get the body if (false !== ($body = $this->_mail->getBodyHtml())) { array_unshift($this->_parts, $body); } elseif (false !== ($body = $this->_mail->getBodyText())) { array_unshift($this->_parts, $body); } if (!$body) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('No body specified'); } // Get headers $this->_headers = $this->_mail->getHeaders(); $headers = $body->getHeadersArray($this->EOL); foreach ($headers as $header) { // Headers in Zend_Mime_Part are kept as arrays with two elements, a // key and a value $this->_headers[$header[0]] = array($header[1]); } } /** * Send a mail using this transport * * @param Zend_Mail $mail * @access public * @return void * @throws Zend_Mail_Transport_Exception if mail is empty */ public function send(Zend_Mail $mail) { $this->_isMultipart = false; $this->_mail = $mail; $this->_parts = $mail->getParts(); $mime = $mail->getMime(); // Build body content $this->_buildBody(); // Determine number of parts and boundary $count = count($this->_parts); $boundary = null; if ($count < 1) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('Empty mail cannot be sent'); } if ($count > 1) { // Multipart message; create new MIME object and boundary $mime = new Zend_Mime($this->_mail->getMimeBoundary()); $boundary = $mime->boundary(); } elseif ($this->_isMultipart) { // multipart/alternative -- grab boundary $boundary = $this->_parts[0]->boundary; } // Determine recipients, and prepare headers $this->recipients = implode(',', $mail->getRecipients()); $this->_prepareHeaders($this->_getHeaders($boundary)); // Create message body // This is done so that the same Zend_Mail object can be used in // multiple transports $message = new Zend_Mime_Message(); $message->setParts($this->_parts); $message->setMime($mime); $this->body = $message->generateMessage($this->EOL); // Send to transport! $this->_sendMail(); } } Transport/Smtp.php000064400000014506152101624100010172 0ustar00_name = $config['name']; } if (isset($config['port'])) { $this->_port = $config['port']; } if (isset($config['auth'])) { $this->_auth = $config['auth']; } $this->_host = $host; $this->_config = $config; } /** * Class destructor to ensure all open connections are closed * * @return void */ public function __destruct() { if ($this->_connection instanceof Zend_Mail_Protocol_Smtp) { try { $this->_connection->quit(); } catch (Zend_Mail_Protocol_Exception $e) { // ignore } $this->_connection->disconnect(); } } /** * Sets the connection protocol instance * * @param Zend_Mail_Protocol_Abstract $client * * @return void */ public function setConnection(Zend_Mail_Protocol_Abstract $connection) { $this->_connection = $connection; } /** * Gets the connection protocol instance * * @return Zend_Mail_Protocol|null */ public function getConnection() { return $this->_connection; } /** * Send an email via the SMTP connection protocol * * The connection via the protocol adapter is made just-in-time to allow a * developer to add a custom adapter if required before mail is sent. * * @return void * @todo Rename this to sendMail, it's a public method... */ public function _sendMail() { if($this->_connection instanceof Zend_Mail_Protocol_Smtp) { try{ $this->_connection->rset(); }catch(Zend_Mail_Protocol_Exception $e){ // We got an exception. This is impossible to reset connection. // Let's use new one; $this->_connection = null; } } // If sending multiple messages per session use existing adapter if (!($this->_connection instanceof Zend_Mail_Protocol_Smtp)) { // Check if authentication is required and determine required class $connectionClass = 'Zend_Mail_Protocol_Smtp'; if ($this->_auth) { $connectionClass .= '_Auth_' . ucwords($this->_auth); } if (!class_exists($connectionClass)) { //--//require_once 'Zend/Loader.php'; Zend_Loader::loadClass($connectionClass); } $this->setConnection(new $connectionClass($this->_host, $this->_port, $this->_config)); $this->_connection->connect(); $this->_connection->helo($this->_name); } // Set sender email address $this->_connection->mail($this->_mail->getReturnPath()); // Set recipient forward paths foreach ($this->_mail->getRecipients() as $recipient) { $this->_connection->rcpt($recipient); } // Issue DATA command to client $this->_connection->data($this->header . Zend_Mime::LINEEND . $this->body); } /** * Format and fix headers * * Some SMTP servers do not strip BCC headers. Most clients do it themselves as do we. * * @access protected * @param array $headers * @return void * @throws Zend_Transport_Exception */ protected function _prepareHeaders($headers) { if (!$this->_mail) { /** * @see Zend_Mail_Transport_Exception */ //--//require_once 'Zend/Mail/Transport/Exception.php'; throw new Zend_Mail_Transport_Exception('_prepareHeaders requires a registered Zend_Mail object'); } unset($headers['Bcc']); // Prepare headers parent::_prepareHeaders($headers); } } Transport/Exception.php000064400000002137152101624100011202 0ustar00_flags = array_merge($this->_flags, array_combine($params['flags'],$params['flags'])); } parent::__construct($params); } /** * return toplines as found after headers * * @return string toplines */ public function getTopLines() { return $this->_topLines; } /** * check if flag is set * * @param mixed $flag a flag name, use constants defined in Zend_Mail_Storage * @return bool true if set, otherwise false */ public function hasFlag($flag) { return isset($this->_flags[$flag]); } /** * get all set flags * * @return array array with flags, key and value are the same for easy lookup */ public function getFlags() { return $this->_flags; } }