PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/tine20/Tinebase/Mail.php

https://gitlab.com/israel.correa/Expresso
PHP | 320 lines | 181 code | 52 blank | 87 comment | 28 complexity | 852e0920e998c5e91aa3cf2b2721e566 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-3.0, LGPL-2.1, LGPL-3.0, JSON, Apache-2.0
  1. <?php
  2. /**
  3. * Tine 2.0
  4. *
  5. * @package Tinebase
  6. * @subpackage Mail
  7. * @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
  8. * @copyright Copyright (c) 2008-2013 Metaways Infosystems GmbH (http://www.metaways.de)
  9. * @author Lars Kneschke <l.kneschke@metaways.de>
  10. */
  11. /**
  12. * This class extends the Zend_Mail class
  13. *
  14. * @package Tinebase
  15. * @subpackage Mail
  16. */
  17. class Tinebase_Mail extends Zend_Mail
  18. {
  19. /**
  20. * email address regexp
  21. */
  22. const EMAIL_ADDRESS_REGEXP = '/([a-z0-9_\+-\.]+@[a-z0-9-\.]{1,})/i';
  23. /**
  24. * Sender: address
  25. * @var string
  26. */
  27. protected $_sender = null;
  28. /**
  29. * create Tinebase_Mail from Zend_Mail_Message
  30. *
  31. * @param Zend_Mail_Message $_zmm
  32. * @param string $_replyBody
  33. * @return Tinebase_Mail
  34. */
  35. public static function createFromZMM(Zend_Mail_Message $_zmm, $_replyBody = null)
  36. {
  37. $contentStream = fopen("php://temp", 'r+');
  38. fputs($contentStream, $_zmm->getContent());
  39. rewind($contentStream);
  40. $mp = new Zend_Mime_Part($contentStream);
  41. if ($_zmm->headerExists('content-transfer-encoding')) {
  42. $mp->encoding = $_zmm->getHeader('content-transfer-encoding');
  43. $mp->decodeContent();
  44. } else {
  45. $mp->encoding = Zend_Mime::ENCODING_7BIT;
  46. }
  47. // append old body when no multipart/mixed
  48. if ($_replyBody !== null && $_zmm->headerExists('content-transfer-encoding')) {
  49. $mp = self::_appendReplyBody($mp, $_replyBody);
  50. $mp->encoding = $_zmm->getHeader('content-transfer-encoding');
  51. }
  52. if ($_zmm->headerExists('content-type')) {
  53. $contentTypeHeader = Zend_Mime_Decode::splitHeaderField($_zmm->getHeader('content-type'));
  54. $mp->type = $contentTypeHeader[0];
  55. if (isset($contentTypeHeader['boundary'])) {
  56. $mp->boundary = $contentTypeHeader['boundary'];
  57. }
  58. if (isset($contentTypeHeader['charset'])) {
  59. $mp->charset = $contentTypeHeader['charset'];
  60. }
  61. } else {
  62. $mp->type = Zend_Mime::TYPE_TEXT;
  63. }
  64. $result = new Tinebase_Mail('utf-8');
  65. $result->setBodyText($mp);
  66. foreach ($_zmm->getHeaders() as $header => $values) {
  67. foreach ((array)$values as $value) {
  68. switch ($header) {
  69. case 'content-transfer-encoding':
  70. // these are implicitly set by Zend_Mail_Transport_Abstract::_getHeaders()
  71. case 'content-type':
  72. case 'mime-version':
  73. // do nothing
  74. break;
  75. case 'bcc':
  76. $addresses = Tinebase_EmailUser_Factory::callStatic('Message','parseAdresslist',array($value));
  77. foreach ($addresses as $address) {
  78. $result->addBcc($address['address'], $address['name']);
  79. }
  80. break;
  81. case 'cc':
  82. $addresses = Tinebase_EmailUser_Factory::callStatic('Message','parseAdresslist',array($value));
  83. foreach ($addresses as $address) {
  84. $result->addCc($address['address'], $address['name']);
  85. }
  86. break;
  87. case 'date':
  88. try {
  89. $result->setDate($value);
  90. } catch (Zend_Mail_Exception $zme) {
  91. if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
  92. Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Could not set date: " . $value);
  93. if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE))
  94. Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " " . $zme);
  95. $result->setDate();
  96. }
  97. break;
  98. case 'from':
  99. $addresses = Tinebase_EmailUser_Factory::callStatic('Message','parseAdresslist',array($value));
  100. foreach ($addresses as $address) {
  101. $result->setFrom($address['address'], $address['name']);
  102. }
  103. break;
  104. case 'message-id':
  105. $result->setMessageId($value);
  106. break;
  107. case 'return-path':
  108. $result->setReturnPath($value);
  109. break;
  110. case 'subject':
  111. $result->setSubject($value);
  112. break;
  113. case 'to':
  114. $addresses = Tinebase_EmailUser_Factory::callStatic('Message','parseAdresslist',array($value));
  115. foreach ($addresses as $address) {
  116. $result->addTo($address['address'], $address['name']);
  117. }
  118. break;
  119. default:
  120. $result->addHeader($header, $value);
  121. break;
  122. }
  123. }
  124. }
  125. return $result;
  126. }
  127. /**
  128. * appends old body to mime part
  129. *
  130. * @param Zend_Mime_Part $mp
  131. * @param string $replyBody
  132. * @return Zend_Mime_Part
  133. */
  134. protected static function _appendReplyBody(Zend_Mime_Part $mp, $replyBody)
  135. {
  136. //if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) {
  137. // Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " reply body: " . $replyBody);
  138. // Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . " mp content: " . $mp->getContent());
  139. // rewind($mp->getRawStream());
  140. //}
  141. $contentStream = fopen("php://temp", 'r+');
  142. stream_copy_to_stream($mp->getRawStream(), $contentStream);
  143. // check if html message, append before </body></html>
  144. // @todo might check content-type, too
  145. rewind($mp->getRawStream());
  146. if (preg_match('/(<\/body>[\s\r\n]*<\/html>)/i', $mp->getContent(), $matches)) {
  147. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
  148. . ' Appending reply body to html body.');
  149. require_once 'StreamFilter/StringReplace.php';
  150. $filter = stream_filter_append($contentStream, 'str.replace', STREAM_FILTER_READ, array(
  151. 'search' => $matches[1],
  152. 'replace' => $replyBody . $matches[1]
  153. ));
  154. } else {
  155. if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
  156. . " Appending reply body to mime text part.");
  157. fputs($contentStream, $replyBody);
  158. }
  159. // create decoded stream
  160. rewind($contentStream);
  161. $mp = new Zend_Mime_Part($contentStream);
  162. return $mp;
  163. }
  164. /**
  165. * Sets the HTML body for the message
  166. *
  167. * @param string|Zend_Mime_Part $html
  168. * @param string $charset
  169. * @param string $encoding
  170. * @return Zend_Mail Provides fluent interface
  171. */
  172. public function setBodyHtml($html, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
  173. {
  174. if ($html instanceof Zend_Mime_Part) {
  175. $mp = $html;
  176. } else {
  177. if ($charset === null) {
  178. $charset = $this->_charset;
  179. }
  180. $mp = new Zend_Mime_Part($html);
  181. $mp->encoding = $encoding;
  182. $mp->type = Zend_Mime::TYPE_HTML;
  183. $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
  184. $mp->charset = $charset;
  185. }
  186. $this->_bodyHtml = $mp;
  187. return $this;
  188. }
  189. /**
  190. * Sets the text body for the message.
  191. *
  192. * @param string|Zend_Mime_Part $txt
  193. * @param string $charset
  194. * @param string $encoding
  195. * @return Zend_Mail Provides fluent interface
  196. */
  197. public function setBodyText($txt, $charset = null, $encoding = Zend_Mime::ENCODING_QUOTEDPRINTABLE)
  198. {
  199. if ($txt instanceof Zend_Mime_Part) {
  200. $mp = $txt;
  201. } else {
  202. if ($charset === null) {
  203. $charset = $this->_charset;
  204. }
  205. $mp = new Zend_Mime_Part($txt);
  206. $mp->encoding = $encoding;
  207. $mp->type = Zend_Mime::TYPE_TEXT;
  208. $mp->disposition = Zend_Mime::DISPOSITION_INLINE;
  209. $mp->charset = $charset;
  210. }
  211. $this->_bodyText = $mp;
  212. return $this;
  213. }
  214. /**
  215. * Sets Sender-header and sender of the message
  216. *
  217. * @param string $email
  218. * @param string $name
  219. * @return Zend_Mail Provides fluent interface
  220. * @throws Zend_Mail_Exception if called subsequent times
  221. */
  222. public function setSender($email, $name = '')
  223. {
  224. if ($this->_sender === null) {
  225. $email = strtr($email,"\r\n\t",'???');
  226. $this->_from = $email;
  227. $this->_storeHeader('Sender', $this->_encodeHeader('"'.$name.'"').' <'.$email.'>', true);
  228. } else {
  229. throw new Zend_Mail_Exception('Sender Header set twice');
  230. }
  231. return $this;
  232. }
  233. /**
  234. * Formats e-mail address
  235. *
  236. * NOTE: we always add quotes to the name as this caused problems when name is encoded
  237. * @see Zend_Mail::_formatAddress
  238. *
  239. * @param string $email
  240. * @param string $name
  241. * @return string
  242. */
  243. protected function _formatAddress($email, $name)
  244. {
  245. if ($name === '' || $name === null || $name === $email) {
  246. return $email;
  247. } else {
  248. $encodedName = $this->_encodeHeader($name);
  249. $format = '"%s" <%s>';
  250. return sprintf($format, $encodedName, $email);
  251. }
  252. }
  253. /**
  254. * check if Zend_Mail_Message is/contains calendar iMIP message
  255. *
  256. * @param Zend_Mail_Message $zmm
  257. * @return boolean
  258. */
  259. public static function isiMIPMail(Zend_Mail_Message $zmm)
  260. {
  261. foreach ($zmm as $part) {
  262. if (preg_match('/text\/calendar/', $part->contentType)) {
  263. return TRUE;
  264. }
  265. }
  266. return FALSE;
  267. }
  268. }