. */ /* Message Object: ******************************************************* stdClass object => ( date => (string) date format "Y-m-d H:i:s" Date => (string) date mime format "Day, d m yyyy hh:ii:ss +Timezone" subject => (string) mime decoded / UTF8 encoded Subject => (string) mime encoded in_reply_to => (string) message_id => (string) message_id without "<" and ">" (suitable for path and names) references => (string) toaddress => (string) full address "Account name " to => Array ( [i] => email address object ) fromaddress from => Array ( [i] => email address object ) reply_toaddress reply_to => Array ( [i] => email address object ) senderaddress => string sender => Array ( [i] => email address object ) Recent Unseen Flagged Answered Deleted Draft Msgno => (string) Number of message in box (local identifier) MailDate Size udate fromname => (string) copy of "from[0]->personal" frommailbox => (string) concatenation of "from[0]->mailbox" + "@" + "from[0]->host" body => Array ( [plain] => plain part object [html] => html part object [pdf] => generated pdf part object ) attachment => Array ( [i] => attachment part object ) ) Email address Object: ******************************************************* stdClass Object ( personal => (string) Account name mailbox => (string) Mailbox name host => (string) Mailbox domain ) Part Object: ******************************************************* stdClass Object ( parameterName => (string) Parameter value (charset, mimetype, format, filename, name...) data => (string) Content pdf => part object ) */ class mailcapture { const MIME_TYPE_TEXT = 0; const MIME_TYPE_MULTIPART = 1; const MIME_TYPE_MESSAGE = 2; const MIME_TYPE_APPLICATION = 3; const MIME_TYPE_AUDIO = 4; const MIME_TYPE_IMAGE = 5; const MIME_TYPE_VIDEO = 6; const MIME_TYPE_OTHER = 7; private $mailbox; /** * Management of e-mails on the server * @param $mailbox string * @param $login string * @param $password string * @return $savedirpath * @return $from_regex * @return $destination_directory */ function captureMessages($mailbox, $login,$password, $from_regex) { $this->openStream( $mailbox, $login, $password ); writeLog("Listing messages..."); $messages = $this->listMessages($from_regex); $messageCount = count($messages); writeLog("$messageCount messages found in mailbox."); for($i=0; $i<$messageCount; $i++) { writeLog("Processing message $i..."); $message = $messages[$i]; if ($message->Deleted <> "D") { $message = $this->captureMessage($message); if ($_ENV["delete_mail"] == "true"){ writeLog("Deleting message ".$message->Msgno); imap_delete($this->mailbox, $message->Msgno); } } else { //echo "deleted\r\n"; } } writeLog("Returning parsed messages."); return $messages; } function openStream($mailbox,$login,$password) { writeLog( "Connecting to imap mailbox $mailbox using login $login..." ); $this->mailbox = imap_open( $mailbox, $login, $password ); if (!$this->mailbox) { writeLog("Failed to connect to $mailbox : " . imap_last_error()); die("Failed to connect to $mailbox : " . imap_last_error()); } writeLog("Connected to $mailbox!"); return true; } // Liste les messages de la boite mail spécifiée function listMessages($from_regex) { $messages = array(); $messageCount = imap_num_msg($this->mailbox); writeLog("Imap returned $messageCount messages"); for ($i=1; $i<=$messageCount; $i++) { $imap_header = imap_headerinfo( $this->mailbox, $i ); $message = $this->decode_mime($imap_header); $message->date = date("Y-m-d H:i:s", strtotime($message->date)); $message->Msgno = trim($message->Msgno); $message->fromname = $message->from[0]->personal; $message->frommailbox = $message->from[0]->mailbox . "@" . $message->from[0]->host; $message->message_id = substr( $message->message_id, 1, strlen($message->message_id) - 2 ); if (!$this->isFromAddressAuthorized( $message->fromaddress, $from_regex) ) { writeLog("Messages from " . $mail->fromaddress ." are excluded - Skipping message"); continue; } //writeLog("Message header info: " . print_r($message,true)); $messages[] = $message; } return($messages); } function isFromAddressAuthorized($fromAddress, $from_regex) { if ($from_regex <> '') return preg_match($from_regex, $fromAddress); else return $fromAddress; } function decode_mime($data, $encoding='UTF-8') { if (is_object($data)) { foreach($data as $propertyName => $propertyValue) { $data->$propertyName = $this->decode_mime($propertyValue); } } elseif (is_array($data)) { foreach($data as $propertyName => $propertyValue) { $data[$propertyName] = $this->decode_mime($propertyValue); } } else { $data = iconv_mime_decode($data, 2); } return $data; } private function captureMessage($message) { writeLog("Processing message " . $message->message_id); writeLog("Create message temp directory..."); if (is_dir($_ENV['tmp_directory'] . $message->message_id)) { emptydir($_ENV['tmp_directory'] . $message->message_id); } else { mkdir($_ENV['tmp_directory'] . $message->message_id); } writeLog("Retrieving message structure..."); $imap_structure = imap_fetchstructure( $this->mailbox, $message->Msgno ); $structure = $this->decode_mime($imap_structure); //writeLog("Message structure:" . print_r($imap_structure, true)); writeLog("Reading message parts..."); $message = $this->readPart($structure, array(), $message); //writeLog("Parsed message:" . print_r($message, true)); $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . 'message.txt', "w"); fputs($fp, print_r($message,true)); fclose($fp); if (isset($message->body['html'])) { writeLog("Generating HTML..."); $message = $this->createHtml($message); } //writeLog("Generating PDF..."); //$message = $this->createPdfWithDomPdf($message); /* $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . 'message.txt', "w"); fputs($fp, print_r($message,true)); fclose($fp); */ writeLog("Message processed, clearing temp files..."); if ($_ENV["debug_extract_files"] == 'false') { emptydir($_ENV['tmp_directory'] . $message->message_id); rmdir($_ENV['tmp_directory'] . $message->message_id); } return $message; } function readPart($part, $partAdr = array(), $message) { // part address //************************************************************** $partAdrString = implode('.', $partAdr); if (!$partAdrString) $partAdrString = '1'; writeLog("Reading part " . $partAdrString); // Type //************************************************************** switch((integer)$part->type) { case 0: $type = 'text'; break; case 1: $type = 'multipart'; break; case 2: $type = 'message'; break; case 3: $type = 'application'; break; case 4: $type = 'audio'; break; case 5: $type = 'image'; break; case 6: $type = 'video'; break; case 7: $type = 'other'; break; } writeLog("Part type is '$type'"); // Subtype //************************************************************** if ($part->ifsubtype) { writeLog("Part subtype: " . $part->subtype); $subtype = strtolower($part->subtype); } else { writeLog("Part default subtype: text"); $subtype = 'text'; } // Disposition //************************************************************** if ($part->ifdisposition) { writeLog("Part disposition: " . $part->disposition); $disposition = strtolower($part->disposition); } else { writeLog("Part default disposition: body"); $disposition = 'body'; } if (!isset($message->$disposition)) $message->$disposition = array(); $currentDisposition = &$message->$disposition; // Dparameters //************************************************************** if ($part->ifdparameters) { writeLog("Part has dparameters"); foreach($part->dparameters as $i => $dparameter) { $dparameterName = strtolower($dparameter->attribute); $dparameterValue = strtolower($dparameter->value); writeLog("Part dparameter $dparameterName = $dparameterValue"); $part->$dparameterName = $dparameterValue; } } // Parameters //************************************************************** if ($part->ifparameters) { writeLog("Part has parameters"); foreach($part->parameters as $parameter) { $parameterName = strtolower($parameter->attribute); $parameterValue = strtolower($parameter->value); writeLog("Part parameter $parameterName = $parameterValue"); $part->$parameterName = $parameterValue; } } // CID //************************************************************** if ($part->ifid) { writeLog("Part has id"); $filename = substr($part->id, 1, strlen($part->id) -2); } elseif ($part->filename) { $filename = $part->filename; } elseif ($part->name) { $filename = $part->name; } else { $filename = $partAdrString; } // Get contents //************************************************************** $content = imap_fetchbody( $this->mailbox, $message->Msgno, $partAdrString ); //writeLog("the content" . $content); $part->mimetype = $type . '/' . $subtype; $part->format = strtolower($subtype); switch ($disposition) { case 'body': writeLog("Reading body part..."); switch($type) { case 'text': switch ($part->encoding) { case '0': //7BIT break; case '1': //8BIT $content = imap_8bit($content); break; case '2': //BINARY break; case '3': //BASE64 $content = imap_base64($content); break; case '4': //QUOTED-PRINTABLE break; case '5': //OTHER break; } writeLog("Addint text to body subtype..."); if ($part->charset != 'utf-8') { $content = utf8_encode($content); } $part->data = quoted_printable_decode($content); $currentDisposition[$subtype] = $part; if ($_ENV["debug_extract_files"] == 'true') { $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . 'body.' . $subtype, "w"); fputs($fp, $part->data); fclose($fp); } break; case 'multipart': writeLog("Reading body parts..."); $partCount = count($part->parts); for($i=0; $i<$partCount; $i++) { $subpart = $part->parts[$i]; writeLog("Processing subpart $i..."); $subpartAdr = $partAdr; $subpartAdr[] = $i+1; $message = $this->readPart( $subpart, $subpartAdr, $message ); } break; // MESSAGE case 'message': writeLog("No action..."); break; //APPLICATION case 'application': case 'audio': case 'image': case 'video': case 'other': writeLog("Extracting body mixed parts..."); $part->data = base64_decode($content); if ($_ENV["debug_extract_files"] == 'true') { $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . $filename, "w"); fputs($fp, $part->data); fclose($fp); } break; } break; case 'inline': case 'INLINE': $part->data = base64_decode($content); $currentDisposition[] = $part; if ($_ENV["debug_extract_files"] == 'true') { $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . $filename, "w"); fputs($fp, $part->data); fclose($fp); } break; case 'attachment': writeLog("Adding attachment with filename " . $filename ."..."); switch($type) { case 'text': $part->data = quoted_printable_decode($content); $part->format = end(explode('.', $filename)); $currentDisposition[] = $part; if ($_ENV["debug_extract_files"] == 'true') { $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . $filename, "w"); fputs($fp, $part->data); fclose($fp); } break; case 'multipart': //???? break; // MESSAGE case 'message': writeLog("No action..."); break; //APPLICATION case 'application': case 'audio': case 'image': case 'video': case 'other': $part->data = base64_decode($content); $currentDisposition[] = $part; if ($_ENV["debug_extract_files"] == 'true') { $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . $filename, "w"); fputs($fp, $part->data); fclose($fp); } break; } break; } return $message; } function createHtml($message) { $html = $message->body['html']->data; // Clean up qprint data and other particularities $html = str_replace("=3D", "=", $html); $html = str_replace(" ", " ", $html); $html = str_replace("’", "'", $html); //$html = str_replace("€", "E", $html); // Outlook namespace tags $html = str_replace('/i', ' ', $html); // Comments $html = preg_replace('//i', ' ', $html); // Replace cids with local tmp file preg_match_all('/cid:(.[^\s])*/', $html, $cids); $cidCount = count($cids[0]); for($i=0; $i<$cidCount; $i++) { $cid = $cids[0][$i]; $filePath = $_ENV['tmp_directory'] . $message->message_id . DIRECTORY_SEPARATOR . substr($cid, 4); //echo "################################\r\n"; //echo $filePath . "\r\n"; if (file_exists($filePath)) { //echo "exists\r\n"; $filename = str_replace( 'cid:', 'file:///' . $_ENV['tmp_directory'] . $message->message_id . DIRECTORY_SEPARATOR, $cid ); } else { //echo "not exists\r\n"; $filename = 'file:///' . $_ENV['script_directory'] . 'cross.png'; } $html = str_replace($cid, $filename, $html); } $message->body['html']->data = $html; if ($_ENV["debug_extract_files"] == 'true') { $fp = fopen($_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . 'body.html', "w"); fputs($fp, $html); fclose($fp); } return $message; } /* function createPdfWithDomPdf($message) { if ($message->body['html']->data) { $data = $message->body['html']->data; $message->charset = $message->body['html']->charset; writeLog("Generating PDF from html body."); } else { $data = str_replace( "\r\n", '
', $message->body['plain']->data ); $message->charset = $message->body['plain']->charset; writeLog("Generating PDF from plain body..."); } require_once('plugins/dompdf/dompdf_config.inc.php'); $dompdf = new DOMPDF(); try { if ($message->charset == 'utf-8') { $data = utf8_decode($data); } echo $message->message_id . " taille du mail " . strlen($data) ."\r\n"; if (strlen($data) < 50000) { $dompdf->load_html($data); $dompdf->render(); $pdfContent = $dompdf->output(); $filePath = $_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . 'body.pdf'; $inF = fopen($filePath,"a"); fwrite($inF, $pdfContent); fclose($inF); $message->body['pdf']->data = file_get_contents( $_ENV["tmp_directory"] . $message->message_id . DIRECTORY_SEPARATOR . 'body.pdf' ); } else { // } } catch (Error $e){ writeLog("PDF Generator Error :".$e->getMessage()); } return $message; } */ }