entityManager = $entityManager; } protected function getEntityManager() { return $this->entityManager; } public function checkMessageAttribute($message, $attribute) { $zendMessage = $message->getZendMessage(); return isset($zendMessage->$attribute); } public function getMessageAttribute($message, $attribute) { $zendMessage = $message->getZendMessage(); if (!isset($zendMessage->$attribute)) return null; return $zendMessage->$attribute; } public function getMessageMessageId($message) { $zendMessage = $message->getZendMessage(); if (!isset($zendMessage->messageId)) return null; $messageId = $zendMessage->messageId; $messageId = str_replace('<<', '<', $messageId); $messageId = str_replace('>>', '>', $messageId); return $messageId; } public function getAddressNameMap($message) { $map = (object) []; $zendMessage = $message->getZendMessage(); foreach (['from', 'to', 'cc', 'reply-To'] as $type) { if (isset($zendMessage->$type)) { $list = $this->normilizeHeader($zendMessage->getHeader($type))->getAddressList(); foreach ($list as $item) { $name = $item->getName(); $address = $item->getEmail(); if ($name && $address && $name !== $address) { $map->$address = $name; } } } } return $map; } public function getAddressDataFromMessage($message, $type) { $zendMessage = $message->getZendMessage(); $addressList = array(); if (isset($zendMessage->$type)) { $list = $this->normilizeHeader($zendMessage->getHeader($type))->getAddressList(); foreach ($list as $address) { return [ 'address' => $address->getEmail(), 'name' => $address->getName() ]; } } return null; } public function getAddressListFromMessage($message, $type) { $zendMessage = $message->getZendMessage(); $addressList = array(); if (isset($zendMessage->$type)) { $list = $this->normilizeHeader($zendMessage->getHeader($type))->getAddressList(); foreach ($list as $address) { $addressList[] = $address->getEmail(); } } return $addressList; } public function fetchContentParts(\Espo\Entities\Email $email, $message, &$inlineAttachmentList = []) { $zendMessage = $message->getZendMessage(); $inlineIds = array(); if ($zendMessage->isMultipart()) { foreach (new \RecursiveIteratorIterator($zendMessage) as $part) { $this->importPartDataToEmail($email, $part, $inlineIds, null, $inlineAttachmentList); } } else { $this->importPartDataToEmail($email, $zendMessage, $inlineIds, 'text/plain', $inlineAttachmentList); } if (!$email->get('body') && $email->hasBodyPlain()) { $email->set('body', $email->get('bodyPlain')); } $body = $email->get('body'); if (!empty($body)) { foreach ($inlineIds as $cid => $attachmentId) { if (strpos($body, 'cid:' . $cid) !== false) { $body = str_replace('cid:' . $cid, '?entryPoint=attachment&id=' . $attachmentId, $body); } else { $email->addLinkMultipleId('attachments', $attachmentId); } } $email->set('body', $body); } } protected function importPartDataToEmail(\Espo\Entities\Email $email, $part, &$inlineIds = array(), $defaultContentType = null, &$inlineAttachmentList = []) { try { $type = null; if ($part->getHeaders() && isset($part->contentType)) { $type = strtok($part->contentType, ';'); } $contentDisposition = false; if (isset($part->ContentDisposition)) { if (strpos(strtolower($part->ContentDisposition), 'attachment') === 0) { $contentDisposition = 'attachment'; } else if (strpos(strtolower($part->ContentDisposition), 'inline') === 0) { $contentDisposition = 'inline'; } } else if (isset($part->contentID)) { $contentDisposition = 'inline'; } if (empty($type)) { if (!empty($defaultContentType)) { $type = $defaultContentType; } else { return; } } $encoding = null; $isAttachment = true; if ($type == 'text/plain' || $type == 'text/html') { if ($contentDisposition !== 'attachment') { $isAttachment = false; $content = $this->getContentFromPart($part); if ($type == 'text/plain') { $bodyPlain = ''; if ($email->hasBodyPlain()) { $bodyPlain .= $email->get('bodyPlain') . "\n"; } $bodyPlain .= $content; $email->set('bodyPlain', $bodyPlain); } else if ($type == 'text/html') { $body = ''; if ($email->get('body')) { $body .= $email->get('body') . "
"; } $body .= $content; $email->set('isHtml', true); $email->set('body', $body); } } } if ($isAttachment) { $content = $part->getContent(); $disposition = null; $fileName = null; $contentId = null; if ($contentDisposition) { if ($contentDisposition === 'attachment') { $fileName = $this->fetchFileNameFromContentDisposition($part->ContentDisposition); if ($fileName) { $disposition = 'attachment'; } } else if ($contentDisposition === 'inline') { if (isset($part->contentID)) { $contentId = trim($part->contentID, '<>'); $fileName = $contentId; $disposition = 'inline'; } else { // for iOS attachments if (empty($fileName)) { $fileName = $this->fetchFileNameFromContentDisposition($part->ContentDisposition); if ($fileName) { $disposition = 'attachment'; } } } } } if (isset($part->contentTransferEncoding)) { $encoding = strtolower($this->normilizeHeader($part->getHeader('Content-Transfer-Encoding'))->getTransferEncoding()); } $attachment = $this->getEntityManager()->getEntity('Attachment'); $attachment->set('name', $fileName); $attachment->set('type', $type); if ($disposition == 'inline') { $attachment->set('role', 'Inline Attachment'); } else { $attachment->set('role', 'Attachment'); } if ($encoding == 'base64') { $content = base64_decode($content); } $attachment->set('contents', $content); $this->getEntityManager()->saveEntity($attachment); if ($disposition == 'attachment') { $attachmentsIds = $email->get('attachmentsIds'); $attachmentsIds[] = $attachment->id; $email->set('attachmentsIds', $attachmentsIds); if (isset($part->contentID)) { $contentId = trim($part->contentID, '<>'); if ($contentId) { $inlineIds[$contentId] = $attachment->id; } } } else if ($disposition == 'inline') { $inlineIds[$contentId] = $attachment->id; $inlineAttachmentList[] = $attachment; } } } catch (\Exception $e) {} } protected function getContentFromPart($part) { if ($part instanceof \Zend\Mime\Part) { $content = $part->getRawContent(); if (strtolower($part->charset) != 'utf-8') { $content = mb_convert_encoding($content, 'UTF-8', $part->charset); } } else { $content = $part->getContent(); $encoding = null; if (isset($part->contentTransferEncoding)) { $cteHeader = $this->normilizeHeader($part->getHeader('Content-Transfer-Encoding')); $encoding = strtolower($cteHeader->getTransferEncoding()); } if ($encoding == 'base64') { $content = base64_decode($content); } $charset = 'UTF-8'; if (isset($part->contentType)) { $ctHeader = $this->normilizeHeader($part->getHeader('Content-Type')); $charsetParamValue = $ctHeader->getParameter('charset'); if (!empty($charsetParamValue)) { $charset = strtoupper($charsetParamValue); } } if (isset($part->contentTransferEncoding)) { $cteHeader = $this->normilizeHeader($part->getHeader('Content-Transfer-Encoding')); if ($cteHeader->getTransferEncoding() == 'quoted-printable') { $content = quoted_printable_decode($content); } } if ($charset !== 'UTF-8') { $content = mb_convert_encoding($content, 'UTF-8', $charset); } } return $content; } protected function normilizeHeader($header) { if (is_a($header, 'ArrayIterator')) { return $header->current(); } else { return $header; } } protected function fetchFileNameFromContentDisposition($contentDisposition) { $contentDisposition = preg_replace('/\\\\"/', "{{_!Q!U!O!T!E!_}}", $contentDisposition); $fileName = false; $m = array(); if (preg_match('/filename="([^"]+)";?/i', $contentDisposition, $m)) { $fileName = $m[1]; } else if (preg_match('/filename=([^";]+);?/i', $contentDisposition, $m)) { $fileName = $m[1]; } else if (preg_match('/filename\*="([^"]+)";?/i', $contentDisposition, $m)) { $fileName = $m[1]; $fileName = $this->decodeAttachmentFileName($fileName); } else if (preg_match('/filename\*=([^";]+);?/i', $contentDisposition, $m)) { $fileName = $m[1]; $fileName = $this->decodeAttachmentFileName($fileName); } else { $fileName = ''; foreach (['0', '1'] as $i) { if (preg_match('/filename\*'.$i.'[\*]?="([^"]+)";?/i', $contentDisposition, $m)) { $part = $m[1]; $fileName .= $part; } else if (preg_match('/filename\*'.$i.'[\*]?=([^";]+);?/i', $contentDisposition, $m)) { $part = $m[1]; $fileName .= $part; } } if ($fileName === '') { $fileName = null; } else { $fileName = $this->decodeAttachmentFileName($fileName); } } if ($fileName) { $fileName = str_replace('{{_!Q!U!O!T!E!_}}', '"', $fileName); } return $fileName; } protected function decodeAttachmentFileName($fileName) { if ($fileName && stripos($fileName, "''") !== false) { list($encoding, $fileName) = explode("''", $fileName); $fileName = rawurldecode($fileName); if (strtoupper($encoding) !== 'UTF-8') { if ($encoding) { $fileName = mb_convert_encoding($fileName, 'UTF-8', $encoding); } } } return $fileName; } }