/** * Read messages from server and save returned emails into DB * * @param resource $mbox created by dre_connect() (by reference) * @param integer the number of messages to process * @param boolean TRUE if script is executed by cron * @return boolean true on success */ function dre_process_messages(&$mbox, $limit, $cron = false) { global $Settings, $debug; global $dre_messages, $dre_emails, $email_cntr, $del_cntr, $is_cron_mode; // This may take a very long time if there are many messages; No execution time limit: set_max_execution_time(0); if ($Settings->get('repath_ignore_read')) { // Read status info of all messages in order to know which have already been read: $msg_statuses = imap_fetch_overview($mbox, '1:' . $limit); } $email_cntr = 0; $del_cntr = 0; for ($index = 1; $index <= $limit; $index++) { // Repeat for as many messages as allowed... dre_msg('<hr /><h3>' . sprintf(T_('Processing message %s:'), '#' . $index) . '</h3>', $cron); if ($Settings->get('repath_ignore_read')) { // Check if we can read this message or we should skip this: if (isset($msg_statuses[$index - 1]) && $msg_statuses[$index - 1]->seen == 1) { // Skip this message because it has already been read: dre_msg(T_('Ignoring this message because it has aleady been read.'), $cron); continue; } else { // Mark this message as "Seen" in order to don't read it twice: imap_setflag_full($mbox, $index, '\\Seen'); } } $html_body = ''; $strbody = ''; $hasAttachment = false; $hasRelated = false; // Save email to a temporary file on hard drive, otherwise BIG attachments may take a lot of RAM: if (!($tmpMIME = tempnam(sys_get_temp_dir(), 'b2evoMail'))) { dre_msg(T_('Could not create temporary file.'), $cron); continue; } // Save the whole body of a specific message from the mailbox: imap_savebody($mbox, $tmpMIME, $index); // fp> TODO: soemwhere here we should skip messages that already have the "seen" flag. This should be optional but should be the default. // This will allow to keep the emails in the INBOX without reprocessing them but to easily try them again my marking them unread. // Create random temp directory for message parts: $tmpDirMIME = dre_tempdir(sys_get_temp_dir(), 'b2evo_'); // Instanciate mime_parser.php library: $mimeParser = new mime_parser_class(); $mimeParser->mbox = 0; // Set to 0 for parsing a *single* RFC 2822 message $mimeParser->decode_headers = 1; // Set to 1 if it is necessary to decode message headers that may have non-ASCII characters and use other character set encodings $mimeParser->ignore_syntax_errors = 1; // ignore syntax errors in malformed messages. $mimeParser->extract_addresses = 0; // Associative array to specify parameters for the messagedata parsing and decoding operation. $MIMEparameters = array('File' => $tmpMIME, 'SaveBody' => $tmpDirMIME, 'SkipBody' => 1); // STEP 1: Parse and decode message data and retrieve its structure: if (!$mimeParser->Decode($MIMEparameters, $decodedMIME)) { // error: dre_msg(sprintf(T_('MIME message decoding error: %s at position %d.'), $mimeParser->error, $mimeParser->error_position), $cron); rmdir_r($tmpDirMIME); unlink($tmpMIME); continue; } else { // the specified message data was parsed successfully: dre_msg(T_('MIME message decoding successful'), $cron); // STEP 2: Analyze (the first) parsed message to describe its contents: if (!$mimeParser->Analyze($decodedMIME[0], $parsedMIME)) { // error: dre_msg(sprintf(T_('MIME message analyze error: %s'), $mimeParser->error), $cron); rmdir_r($tmpDirMIME); unlink($tmpMIME); continue; } // Get message $subject and $post_date from headers (by reference) if (!dre_process_header($parsedMIME, $subject, $post_date, $cron)) { // Couldn't process message headers: rmdir_r($tmpDirMIME); unlink($tmpMIME); continue; } // TODO: handle type == "message" recursively // fp> where is type == "message" ??? // yura> I don't find the type == 'message' in dump of $decodedMIME and $parsedMIME // sam2kb> For some reason imap_qprint() demages HTML text... needs more testing // yura> I replaced imap_qprint() with quoted_printable_decode() to avoid notices about invalid quoted-printable sequence // yura> imap_qprint() and quoted_printable_decode() do empty the message text, thus they were deleted. dre_msg(T_('Email Type') . ': ' . $parsedMIME['Type'], $cron); if ($parsedMIME['Type'] == 'html') { // Mail is HTML: if ($debug) { // Display this info only in debug mode: dre_msg(sprintf(T_('HTML message part saved as %s'), $parsedMIME['DataFile']), $cron); } $html_body = file_get_contents($parsedMIME['DataFile']); if (empty($html_body)) { // Try to get a body text from alternative parts if main html body is empty: foreach ($parsedMIME['Alternative'] as $alternative) { // First try to get HTML alternative (when possible) if ($alternative['Type'] == 'html') { // HTML text if ($debug) { // Display this info only in debug mode: dre_msg(sprintf(T_('HTML alternative message part saved as %s'), $alternative['DataFile']), $cron); } $strbody = file_get_contents($alternative['DataFile']); break; // stop after first alternative } elseif ($alternative['Type'] == 'text') { // Plain text if ($debug) { // Display this info only in debug mode: dre_msg(sprintf(T_('Text alternative message part saved as %s'), $alternative['DataFile']), $cron); } $strbody = file_get_contents($alternative['DataFile']); break; // stop after first alternative } } } } elseif ($parsedMIME['Type'] == 'text') { // Mail is plain text: if ($debug) { // Display this info only in debug mode: dre_msg(sprintf(T_('Plain-text message part saved as %s'), $parsedMIME['DataFile']), $cron); } $strbody = file_get_contents($parsedMIME['DataFile']); } elseif ($parsedMIME['Type'] == 'delivery-status') { // Mail is delivery-status: $strbody = $parsedMIME['Response']; } if (count($mimeParser->warnings) > 0) { // Record potential warnings: dre_msg('<h4>' . sprintf(T_('%d warnings during decode:'), count($mimeParser->warnings)) . '</h4>', $cron); foreach ($mimeParser->warnings as $k => $v) { dre_msg(sprintf(T_('Warning: %s at position %s'), $v, $k), $cron); } } } unlink($tmpMIME); if (empty($html_body)) { // Plain-text message dre_msg(sprintf(T_('Message type: %s'), 'TEXT'), $cron); // Process body. First fix different line-endings (dos, mac, unix), remove double newlines $content = str_replace(array("\r", "\n\n"), "\n", trim($strbody)); dre_msg(sprintf(T_('Message body: %s'), '<pre style="font-size:10px">' . htmlspecialchars($strbody) . '</pre>'), $cron); } else { // HTML message dre_msg(sprintf(T_('Message type: %s'), 'HTML'), $cron); dre_msg(sprintf(T_('Message body (original): %s'), '<pre style="font-size:10px">' . htmlspecialchars($html_body) . '</pre>', $cron)); // Prepare html message body text: $content = dre_prepare_html_message($html_body); dre_msg(sprintf(T_('Message body (processed): %s'), '<pre style="font-size:10px">' . htmlspecialchars($content) . '</pre>', $cron)); } dre_msg('<b class="green">' . T_('MIME Decoding Successful') . '</b>', $cron); $message_text = $content; // Remove content after terminators $content = dre_limit_by_terminators($content); global $Messages; if ($Messages->has_errors()) { // Make it easier for user to find and correct the errors dre_msg("\n" . sprintf(T_('Processing message: %s'), $post_title), $cron); dre_msg($Messages->get_string(T_('Cannot post, please correct these errors:'), 'error'), $cron); $Messages->clear(); rmdir_r($tmpDirMIME); continue; } global $dre_emails, $DB, $localtimenow; dre_msg('<h4>' . T_('Saving the returned email in the database') . '</h4>', $cron); // Get Headers from Decoded MIME Data: $email_headers = dre_get_headers($decodedMIME); // Get data of the returned email: $email_data = dre_get_email_data($content, $message_text, $email_headers); dre_msg(T_('Email Address') . ': ' . $email_data['address'], $cron); dre_msg(T_('Error Type') . ': ' . dre_decode_error_type($email_data['errtype']), $cron); dre_msg(T_('Error Message') . ': ' . $email_data['errormsg'], $cron); // Insert a returned email's data into DB if (dre_insert_returned_email($email_data)) { ++$email_cntr; } // Delete temporary directory: rmdir_r($tmpDirMIME); // Mark message to be deleted: if ($Settings->get('repath_delete_emails')) { dre_msg(sprintf(T_('Marking message for deletion from inbox: %s'), $index), $cron); imap_delete($mbox, $index); ++$del_cntr; } } // Expunge messages marked for deletion imap_expunge($mbox); return true; }
/** * Read messages from server and save returned emails into DB * * @param resource $mbox created by dre_connect() (by reference) * @param integer the number of messages to process * @return boolean true on success */ function dre_process_messages(&$mbox, $limit) { //return; // Exit, in development... global $Settings; global $dre_messages, $dre_emails, $email_cntr, $del_cntr, $is_cron_mode; // No execution time limit set_max_execution_time(0); $email_cntr = 0; $del_cntr = 0; for ($index = 1; $index <= $limit; $index++) { dre_msg('<hr /><h3>Processing message #' . $index . ':</h3>'); $strbody = ''; $hasAttachment = false; $hasRelated = false; // Save email to hard drive, otherwise attachments may take a lot of RAM if (!($tmpMIME = tempnam(sys_get_temp_dir(), 'b2evoMail'))) { dre_msg(T_('Could not create temporary file.'), true); continue; } imap_savebody($mbox, $tmpMIME, $index); // Create random temp directory for message parts $tmpDirMIME = dre_tempdir(sys_get_temp_dir(), 'b2evo_'); $mimeParser = new mime_parser_class(); $mimeParser->mbox = 0; // Set to 0 for parsing a single message file $mimeParser->decode_headers = 1; $mimeParser->ignore_syntax_errors = 1; $mimeParser->extract_addresses = 0; $MIMEparameters = array('File' => $tmpMIME, 'SaveBody' => $tmpDirMIME, 'SkipBody' => 1); if (!$mimeParser->Decode($MIMEparameters, $decodedMIME)) { dre_msg(sprintf('MIME message decoding error: %s at position %d.', $mimeParser->error, $mimeParser->error_position), true); rmdir_r($tmpDirMIME); unlink($tmpMIME); continue; } else { dre_msg('MIME message decoding successful'); if (!$mimeParser->Analyze($decodedMIME[0], $parsedMIME)) { dre_msg(sprintf('MIME message analyse error: %s', $mimeParser->error), true); rmdir_r($tmpDirMIME); unlink($tmpMIME); continue; } // Get message $subject and $post_date from headers (by reference) if (!dre_process_header($parsedMIME, $subject, $post_date)) { // Couldn't process message headers rmdir_r($tmpDirMIME); unlink($tmpMIME); continue; } // TODO: handle type == "message" recursively // sam2kb> For some reason imap_qprint() demages HTML text... needs more testing if ($parsedMIME['Type'] == 'html') { // Mail is HTML dre_msg('HTML message part saved as ' . $parsedMIME['DataFile']); $html_body = file_get_contents($parsedMIME['DataFile']); foreach ($parsedMIME['Alternative'] as $alternative) { // First try to get HTML alternative (when possible) if ($alternative['Type'] == 'html') { // HTML text dre_msg('HTML alternative message part saved as ' . $alternative['DataFile']); // sam2kb> TODO: we may need to use $html_body here instead $strbody = file_get_contents($alternative['DataFile']); break; // stop after first alternative } elseif ($alternative['Type'] == 'text') { // Plain text dre_msg('Text alternative message part saved as ' . $alternative['DataFile']); $strbody = imap_qprint(file_get_contents($alternative['DataFile'])); break; // stop after first alternative } } } elseif ($parsedMIME['Type'] == 'text') { // Mail is plain text dre_msg('Plain-text message part saved as ' . $parsedMIME['DataFile']); $strbody = imap_qprint(file_get_contents($parsedMIME['DataFile'])); } elseif ($parsedMIME['Type'] == 'delivery-status') { // Mail is delivery-status $strbody = ''; foreach ($decodedMIME[0]['Parts'] as $part) { $strbody .= imap_qprint(file_get_contents($part['BodyFile'])); } } if (count($mimeParser->warnings) > 0) { dre_msg(sprintf('<h4>%d warnings during decode:</h4>', count($mimeParser->warnings))); foreach ($mimeParser->warnings as $k => $v) { dre_msg('Warning: ' . $v . ' at position ' . $k); } } } unlink($tmpMIME); if (empty($html_body)) { // Plain text message dre_msg('Message type: TEXT'); dre_msg('Message body: <pre style="font-size:10px">' . htmlspecialchars($strbody) . '</pre>'); // Process body. First fix different line-endings (dos, mac, unix), remove double newlines $content = str_replace(array("\r", "\n\n"), "\n", trim($strbody)); } else { // HTML message dre_msg('Message type: HTML'); if (($parsed_message = dre_prepare_html_message($html_body)) === false) { // No 'auth' tag provided, skip to the next message rmdir_r($tmpDirMIME); continue; } list($auth, $content) = $parsed_message; } dre_msg('<b class="green">Success</b>'); $message_text = $content; // Remove content after terminators $content = dre_limit_by_terminators($content); global $Messages; if ($Messages->has_errors()) { // Make it easier for user to find and correct the errors dre_msg("\n" . sprintf(T_('Processing message: %s'), $post_title), true); dre_msg($Messages->get_string(T_('Cannot post, please correct these errors:'), 'error'), true); $Messages->clear(); rmdir_r($tmpDirMIME); continue; } global $dre_emails, $DB, $localtimenow; dre_msg(sprintf('<h4>Saving the returned email in the database</h4>')); // Insert a returned email's data into DB if ($returned_email = dre_insert_returned_email($content, $message_text, dre_get_headers($decodedMIME))) { dre_msg('Error Type: ' . dre_decode_error_type($returned_email['errtype'])); dre_msg('Error Message: ' . $returned_email['errormsg']); ++$email_cntr; } // Delete temporary directory rmdir_r($tmpDirMIME); if ($Settings->get('repath_delete_emails')) { dre_msg('Marking message for deletion from inbox: ' . $index); imap_delete($mbox, $index); ++$del_cntr; } } // Expunge messages market for deletion imap_expunge($mbox); return true; }