function SaveMail(&$content, MailAccount $account, $uidl, $state = 0, $imap_folder_name = '') { if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("UID: {$uidl}"); } if (!mysql_ping(DB::connection()->getLink())) { DB::connection()->reconnect(); Logger::log("*** Connection Lost -> Reconnected ***"); } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 1) " . format_filesize(memory_get_usage())); } if (strpos($content, '+OK ') > 0) { $content = substr($content, strpos($content, '+OK ')); } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 2) " . format_filesize(memory_get_usage())); } self::parseMail($content, $decoded, $parsedMail, $warnings); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 3) " . format_filesize(memory_get_usage())); } $encoding = array_var($parsedMail, 'Encoding', 'UTF-8'); $enc_conv = EncodingConverter::instance(); $to_addresses = self::getAddresses(array_var($parsedMail, "To")); $from = self::getAddresses(array_var($parsedMail, "From")); $message_id = self::getHeaderValueFromContent($content, "Message-ID"); $in_reply_to_id = self::getHeaderValueFromContent($content, "In-Reply-To"); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 4) " . format_filesize(memory_get_usage())); } $uid = trim($uidl); if (str_starts_with($uid, '<') && str_ends_with($uid, '>')) { $uid = utf8_substr($uid, 1, utf8_strlen($uid, $encoding) - 2, $encoding); } if ($uid == '') { $uid = trim($message_id); if ($uid == '') { $uid = array_var($parsedMail, 'Subject', 'MISSING UID'); } if (str_starts_with($uid, '<') && str_ends_with($uid, '>')) { $uid = utf8_substr($uid, 1, utf8_strlen($uid, $encoding) - 2, $encoding); } if (MailContents::mailRecordExists($account->getId(), $uid, $imap_folder_name == '' ? null : $imap_folder_name)) { return; } } if (!$from) { $parsedMail["From"] = self::getFromAddressFromContent($content); $from = array_var($parsedMail["From"][0], 'address', ''); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 4.1) " . format_filesize(memory_get_usage())); } } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 5) " . format_filesize(memory_get_usage())); } if (defined('EMAIL_MESSAGEID_CONTROL') && EMAIL_MESSAGEID_CONTROL) { if (trim($message_id) != "") { $id_condition = " AND `message_id`='" . trim($message_id) . "'"; } else { $id_condition = " AND `subject`='" . trim(array_var($parsedMail, 'Subject')) . "' AND `from`='{$from}'"; if (array_var($parsedMail, 'Date')) { $sent_date_dt = new DateTimeValue(strtotime(array_var($parsedMail, 'Date'))); $sent_date_str = $sent_date_dt->toMySQL(); $id_condition .= " AND `sent_date`='" . $sent_date_str . "'"; } } $same = MailContents::findOne(array('conditions' => "`account_id`=" . $account->getId() . $id_condition, 'include_trashed' => true)); if ($same instanceof MailContent) { return; } } if ($state == 0) { if ($from == $account->getEmailAddress()) { if (strpos($to_addresses, $from) !== FALSE) { $state = 5; } else { $state = 1; } //Show only in sent folder } } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 6) " . format_filesize(memory_get_usage())); self::log_connection_status(); } $from_spam_junk_folder = strpos(strtolower($imap_folder_name), 'spam') !== FALSE || strpos(strtolower($imap_folder_name), 'junk') !== FALSE || strpos(strtolower($imap_folder_name), 'trash') !== FALSE; $user_id = logged_user() instanceof User ? logged_user()->getId() : $account->getUserId(); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); } $max_spam_level = user_config_option('max_spam_level', null, $user_id); if ($max_spam_level < 0) { $max_spam_level = 0; } $mail_spam_level = strlen(trim(array_var($decoded[0]['Headers'], 'x-spam-level:', ''))); // if max_spam_level >= 10 then nothing goes to junk folder $spam_in_subject = false; if (config_option('check_spam_in_subject')) { $spam_in_subject = strpos_utf(strtoupper(array_var($parsedMail, 'Subject')), "**SPAM**") !== false; } if ($max_spam_level < 10 && ($mail_spam_level > $max_spam_level || $from_spam_junk_folder) || $spam_in_subject) { $state = 4; // send to Junk folder } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem 7) " . format_filesize(memory_get_usage())); self::log_connection_status(); } if (!isset($parsedMail['Subject'])) { $parsedMail['Subject'] = ''; } $mail = new MailContent(); $mail->setAccountId($account->getId()); $mail->setState($state); $mail->setImapFolderName($imap_folder_name); $mail->setFrom($from); $cc = trim(self::getAddresses(array_var($parsedMail, "Cc"))); if ($cc == '' && array_var($decoded, 0) && array_var($decoded[0], 'Headers')) { $cc = array_var($decoded[0]['Headers'], 'cc:', ''); } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("mem 8) " . format_filesize(memory_get_usage())); } $mail->setCc($cc); $from_name = trim(array_var(array_var(array_var($parsedMail, 'From'), 0), 'name')); $from_encoding = detect_encoding($from_name); if ($from_name == '') { $from_name = $from; } else { if (strtoupper($encoding) == 'KOI8-R' || strtoupper($encoding) == 'CP866' || $from_encoding != 'UTF-8' || !$enc_conv->isUtf8RegExp($from_name)) { //KOI8-R and CP866 are Russian encodings which PHP does not detect $utf8_from = $enc_conv->convert($encoding, 'UTF-8', $from_name); if ($enc_conv->hasError()) { $utf8_from = utf8_encode($from_name); } $utf8_from = utf8_safe($utf8_from); $mail->setFromName($utf8_from); } else { $mail->setFromName($from_name); } } $subject_aux = $parsedMail['Subject']; $subject_encoding = detect_encoding($subject_aux); if (strtoupper($encoding) == 'KOI8-R' || strtoupper($encoding) == 'CP866' || $subject_encoding != 'UTF-8' || !$enc_conv->isUtf8RegExp($subject_aux)) { //KOI8-R and CP866 are Russian encodings which PHP does not detect $utf8_subject = $enc_conv->convert($encoding, 'UTF-8', $subject_aux); if ($enc_conv->hasError()) { $utf8_subject = utf8_encode($subject_aux); } $utf8_subject = utf8_safe($utf8_subject); $mail->setSubject($utf8_subject); } else { $utf8_subject = utf8_safe($subject_aux); $mail->setSubject($utf8_subject); } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("mem 9) " . format_filesize(memory_get_usage())); } $mail->setTo($to_addresses); $sent_timestamp = false; if (array_key_exists("Date", $parsedMail)) { $sent_timestamp = strtotime($parsedMail["Date"]); } if ($sent_timestamp === false || $sent_timestamp === -1 || $sent_timestamp === 0) { $mail->setSentDate(DateTimeValueLib::now()); } else { $mail->setSentDate(new DateTimeValue($sent_timestamp)); } // if this constant is defined, mails older than this date will not be fetched if (defined('FIRST_MAIL_DATE')) { $first_mail_date = DateTimeValueLib::makeFromString(FIRST_MAIL_DATE); if ($mail->getSentDate()->getTimestamp() < $first_mail_date->getTimestamp()) { // return true to stop getting older mails from the server return true; } } $received_timestamp = false; if (array_key_exists("Received", $parsedMail) && $parsedMail["Received"]) { $received_timestamp = strtotime($parsedMail["Received"]); } if ($received_timestamp === false || $received_timestamp === -1 || $received_timestamp === 0) { $mail->setReceivedDate($mail->getSentDate()); } else { $mail->setReceivedDate(new DateTimeValue($received_timestamp)); if ($state == 5 && $mail->getSentDate()->getTimestamp() > $received_timestamp) { $mail->setReceivedDate($mail->getSentDate()); } } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("mem 10) " . format_filesize(memory_get_usage())); } $mail->setSize(strlen($content)); $mail->setHasAttachments(!empty($parsedMail["Attachments"])); $mail->setCreatedOn(new DateTimeValue(time())); $mail->setCreatedById($account->getUserId()); $mail->setAccountEmail($account->getEmail()); $mail->setMessageId($message_id); $mail->setInReplyToId($in_reply_to_id); $mail->setUid($uid); $type = array_var($parsedMail, 'Type', 'text'); switch ($type) { case 'html': $utf8_body = $enc_conv->convert($encoding, 'UTF-8', array_var($parsedMail, 'Data', '')); if ($enc_conv->hasError()) { $utf8_body = utf8_encode(array_var($parsedMail, 'Data', '')); } $utf8_body = utf8_safe($utf8_body); $mail->setBodyHtml($utf8_body); break; case 'text': $utf8_body = $enc_conv->convert($encoding, 'UTF-8', array_var($parsedMail, 'Data', '')); if ($enc_conv->hasError()) { $utf8_body = utf8_encode(array_var($parsedMail, 'Data', '')); } $utf8_body = utf8_safe($utf8_body); $mail->setBodyPlain($utf8_body); break; case 'delivery-status': $utf8_body = $enc_conv->convert($encoding, 'UTF-8', array_var($parsedMail, 'Response', '')); if ($enc_conv->hasError()) { $utf8_body = utf8_encode(array_var($parsedMail, 'Response', '')); } $utf8_body = utf8_safe($utf8_body); $mail->setBodyPlain($utf8_body); break; default: break; } if (isset($parsedMail['Alternative'])) { foreach ($parsedMail['Alternative'] as $alt) { if ($alt['Type'] == 'html' || $alt['Type'] == 'text') { $body = $enc_conv->convert(array_var($alt, 'Encoding', 'UTF-8'), 'UTF-8', array_var($alt, 'Data', '')); if ($enc_conv->hasError()) { $body = utf8_encode(array_var($alt, 'Data', '')); } // remove large white spaces $exploded = preg_split("/[\\s]+/", $body, -1, PREG_SPLIT_NO_EMPTY); $body = implode(" ", $exploded); // remove html comments $body = preg_replace('/<!--.*-->/i', '', $body); } $body = utf8_safe($body); if ($alt['Type'] == 'html') { $mail->setBodyHtml($body); } else { if ($alt['Type'] == 'text') { $plain = html_to_text(html_entity_decode($utf8_body, null, "UTF-8")); $mail->setBodyPlain($plain); } } // other alternative parts (like images) are not saved in database. } } $repository_id = self::SaveContentToFilesystem($mail->getUid(), $content); $mail->setContentFileId($repository_id); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("mem 11) " . format_filesize(memory_get_usage())); } try { if ($in_reply_to_id != "") { if ($message_id != "") { $conv_mail = MailContents::findOne(array("conditions" => "`account_id`=" . $account->getId() . " AND `in_reply_to_id` = '{$message_id}'")); if (!$conv_mail) { $conv_mail = MailContents::findOne(array("conditions" => "`account_id`=" . $account->getId() . " AND `message_id` = '{$in_reply_to_id}'")); } else { // Search for other discontinued conversation part to link it $other_conv_emails = MailContents::findAll(array("conditions" => "`account_id`=" . $account->getId() . " AND `message_id` = '{$in_reply_to_id}' AND `conversation_id`<>" . $conv_mail->getConversationId())); } } else { $conv_mail = MailContents::findOne(array("conditions" => "`account_id`=" . $account->getId() . " AND `message_id` = '{$in_reply_to_id}'")); } if ($conv_mail instanceof MailContent) { // Remove "Re: ", "Fwd: ", etc to compare the subjects $conv_original_subject = strtolower($conv_mail->getSubject()); if (($pos = strrpos($conv_original_subject, ":")) !== false) { $conv_original_subject = trim(substr($conv_original_subject, $pos + 1)); } } if ($conv_mail instanceof MailContent && strpos(strtolower($mail->getSubject()), strtolower($conv_original_subject)) !== false) { $mail->setConversationId($conv_mail->getConversationId()); if (isset($other_conv_emails) && is_array($other_conv_emails)) { foreach ($other_conv_emails as $ocm) { $ocm->setConversationId($conv_mail->getConversationId()); $ocm->save(); } } } else { $conv_id = MailContents::getNextConversationId($account->getId()); $mail->setConversationId($conv_id); } } else { $conv_id = MailContents::getNextConversationId($account->getId()); $mail->setConversationId($conv_id); } if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("mem 12) " . format_filesize(memory_get_usage())); } $mail->save(); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { self::log_connection_status(); Logger::log("mem 13) " . format_filesize(memory_get_usage())); } // CLASSIFY RECEIVED MAIL WITH THE CONVERSATION if (user_config_option('classify_mail_with_conversation', null, $account->getUserId()) && isset($conv_mail) && $conv_mail instanceof MailContent) { $wss = $conv_mail->getWorkspaces(); foreach ($wss as $ws) { $acc_user = Users::findById($account->getUserId()); if ($acc_user instanceof User && $acc_user->hasProjectPermission($ws, ProjectUsers::CAN_READ_MAILS)) { $mail->addToWorkspace($ws); } } } // CLASSIFY MAILS IF THE ACCOUNT HAS A WORKSPACE if ($account->getColumnValue('workspace', 0) != 0) { $workspace = Projects::findById($account->getColumnValue('workspace', 0)); if ($workspace && $workspace instanceof Project && !$mail->hasWorkspace($workspace)) { $mail->addToWorkspace($workspace); } } //END CLASSIFY $user = Users::findById($account->getUserId()); if ($user instanceof User) { $mail->subscribeUser($user); } } catch (Exception $e) { FileRepository::deleteFile($repository_id); if (strpos($e->getMessage(), "Query failed with message 'Got a packet bigger than 'max_allowed_packet' bytes'") === false) { throw $e; } } unset($parsedMail); if (defined('DEBUG_EMAIL_RETRIEVAL') && DEBUG_EMAIL_RETRIEVAL) { Logger::log("mem fin) " . format_filesize(memory_get_usage())); self::log_connection_status(); } return false; }