/** * Handle the message. * * @param int $inh The file handle pointing to the message. * @param string $transport The name of the transport driver. * * @return mixed A PEAR_Error in case of an error, nothing otherwise. */ function _parse($inh, $transport) { global $conf; $result = $this->init(); if (is_a($result, 'PEAR_Error')) { return $result; } if (isset($conf['kolab']['filter']['verify_from_header'])) { $verify_from_header = $conf['kolab']['filter']['verify_from_header']; } else { $verify_from_header = false; } if (isset($conf['kolab']['filter']['allow_sender_header'])) { $allow_sender_header = $conf['kolab']['filter']['allow_sender_header']; } else { $allow_sender_header = false; } if (isset($conf['kolab']['filter']['allow_outlook_ical_forward'])) { $allow_outlook_ical_forward = $conf['kolab']['filter']['allow_outlook_ical_forward']; } else { $allow_outlook_ical_forward = true; } if (empty($transport)) { $transport = 'smtp'; } $ical = false; $from = false; $subject = false; $senderok = true; $rewrittenfrom = false; $state = RM_STATE_READING_HEADER; while (!feof($inh) && $state != RM_STATE_READING_BODY) { $buffer = fgets($inh, 8192); $line = rtrim($buffer, "\r\n"); if ($line == '') { /* Done with headers */ $state = RM_STATE_READING_BODY; if ($from && $verify_from_header) { $rc = $this->_verify_sender($this->_sasl_username, $this->_sender, $from, $this->_client_address); if (is_a($rc, 'PEAR_Error')) { return $rc; } else { if ($rc === true) { /* All OK, do nothing */ } else { if ($rc === false) { /* Reject! */ $senderok = false; } else { if (is_string($rc)) { /* Rewrite from */ if (strpos($from, $rc) === false) { Horde::log(sprintf("Rewriting '%s' to '%s'", $from, $rc), 'DEBUG'); $rewrittenfrom = "From: {$rc}\r\n"; } } } } } } } else { if ($line[0] != ' ' && $line[0] != "\t") { $state = RM_STATE_READING_HEADER; } switch ($state) { case RM_STATE_READING_HEADER: if ($allow_sender_header && preg_match('#^Sender: (.*)#i', $line, $regs)) { $from = $regs[1]; $state = RM_STATE_READING_SENDER; } else { if (!$from && preg_match('#^From: (.*)#i', $line, $regs)) { $from = $regs[1]; $state = RM_STATE_READING_FROM; } else { if (preg_match('#^Subject: (.*)#i', $line, $regs)) { $subject = $regs[1]; $state = RM_STATE_READING_SUBJECT; } else { if (preg_match('#^Content-Type: text/calendar#i', $line)) { Horde::log("Found iCal data in message", 'DEBUG'); $ical = true; } else { if (preg_match('#^Message-ID: (.*)#i', $line, $regs)) { $this->_id = $regs[1]; } } } } } break; case RM_STATE_READING_FROM: $from .= $line; break; case RM_STATE_READING_SENDER: $from .= $line; break; case RM_STATE_READING_SUBJECT: $subject .= $line; break; } } if (@fwrite($this->_tmpfh, $buffer) === false) { $msg = $php_errormsg; return PEAR::raiseError(sprintf("Error: Could not write to %s: %s", $this->_tmpfile, $msg), OUT_LOG | EX_IOERR); } } while (!feof($inh)) { $buffer = fread($inh, 8192); if (@fwrite($this->_tmpfh, $buffer) === false) { $msg = $php_errormsg; return PEAR::raiseError(sprintf("Error: Could not write to %s: %s", $this->_tmpfile, $msg), OUT_LOG | EX_IOERR); } } if (@fclose($this->_tmpfh) === false) { $msg = $php_errormsg; return PEAR::raiseError(sprintf("Error: Failed closing %s: %s", $this->_tmpfile, $msg), OUT_LOG | EX_IOERR); } if (!$senderok) { if ($ical && $allow_outlook_ical_forward) { require_once __DIR__ . '/Outlook.php'; $rc = Kolab_Filter_Outlook::embedICal($this->_fqhostname, $this->_sender, $this->_recipients, $from, $subject, $this->_tmpfile, $transport); if (is_a($rc, 'PEAR_Error')) { return $rc; } else { if ($rc === true) { return; } } } else { return PEAR::raiseError(sprintf("Invalid From: header. %s looks like a forged sender", $from), OUT_LOG | OUT_STDOUT | EX_NOPERM); } } $result = $this->_deliver($rewrittenfrom, $transport); if (is_a($result, 'PEAR_Error')) { return $result; } }
/** * Clean up iCal messages from Outlook. * * @param string $fqhostname The name of this host. * @param string $sender The mail address of the sender. * @param array $recipients The recipients of the message. * @param string $origfrom The mail address of the original sender. * @param string $subject The mail subject. * @param string $tmpfname Path to the temporary message store. * * @return boolena|PEAR_Error True if the message was successfully rewritten. */ function embedICal($fqhostname, $sender, $recipients, $origfrom, $subject, $tmpfname, $transport) { Horde::log(sprintf("Encapsulating iCal message forwarded by %s", $sender), 'DEBUG'); $forwardtext = "This is an invitation forwarded by outlook and\n" . "was rectified by the Kolab server.\n" . "The invitation was originally sent by\n%s.\n\n" . "Diese Einladung wurde von Outlook weitergeleitet\n" . "und vom Kolab-Server in gute Form gebracht.\n" . "Die Einladung wurde ursprünglich von\n%s geschickt.\n"; // Read in message text $requestText = ''; $handle = @fopen($tmpfname, "r"); if ($handle === false) { $msg = $php_errormsg; return PEAR::raiseError(sprintf("Error: Could not open %s for writing: %s", $tmpfname, $msg), OUT_LOG | EX_IOERR); } while (!feof($handle)) { $requestText .= fread($handle, 8192); } fclose($handle); // Parse existing message list($headers, $mime) = Kolab_Filter_Outlook::_mimeParse($requestText); $parts = $mime->contentTypeMap(); if (count($parts) != 1 || $parts[1] != 'text/calendar') { Horde::log("Message does not contain exactly one toplevel text/calendar part, passing through.", 'DEBUG'); return false; } $basepart = $mime->getBasePart(); // Construct new MIME message with original message attached $toppart = new MIME_Message(); $dorigfrom = Mail_mimeDecode::_decodeHeader($origfrom); $textpart = new MIME_Part('text/plain', sprintf($forwardtext, $dorigfrom, $dorigfrom), 'UTF-8'); $ical_txt = $basepart->transferDecode(); Kolab_Filter_Outlook::_addOrganizer($ical_txt, $dorigfrom); $msgpart = new MIME_Part($basepart->getType(), Kolab_Filter_Outlook::_recodeToAscii($ical_txt), $basepart->getCharset()); $toppart->addPart($textpart); $toppart->addPart($msgpart); // Build the reply headers. $msg_headers = new MIME_Headers(); Kolab_Filter_Outlook::_copyHeader('Received', $msg_headers, $headers); //$msg_headers->addReceivedHeader(); $msg_headers->addMessageIdHeader(); Kolab_Filter_Outlook::_copyHeader('Date', $msg_headers, $headers); Kolab_Filter_Outlook::_copyHeader('Resent-Date', $msg_headers, $headers); Kolab_Filter_Outlook::_copyHeader('Subject', $msg_headers, $headers); $msg_headers->addHeader('From', $sender); $msg_headers->addHeader('To', join(', ', $recipients)); $msg_headers->addHeader('X-Kolab-Forwarded', 'TRUE'); $msg_headers->addMIMEHeaders($toppart); Kolab_Filter_Outlook::_copyHeader('Content-Transfer-Encoding', $msg_headers, $headers); if (is_object($msg_headers)) { $headerArray = $toppart->encode($msg_headers->toArray(), $toppart->getCharset()); } else { $headerArray = $toppart->encode($msg_headers, $toppart->getCharset()); } return Kolab_Filter_Outlook::_inject($toppart, $recipients, $msg_headers, $sender, $transport); }