mirror of
https://github.com/roundcube/roundcubemail.git
synced 2026-02-26 12:31:19 +01:00
230 lines
7.7 KiB
PHP
230 lines
7.7 KiB
PHP
<?php
|
|
|
|
/*
|
|
+-----------------------------------------------------------------------+
|
|
| This file is part of the Roundcube Webmail client |
|
|
| |
|
|
| Copyright (C) The Roundcube Dev Team |
|
|
| |
|
|
| Licensed under the GNU General Public License version 3 or |
|
|
| any later version with exceptions for skins & plugins. |
|
|
| See the README file for a full license statement. |
|
|
| |
|
|
| PURPOSE: |
|
|
| Save the uploaded file(s) as messages to the current IMAP folder |
|
|
+-----------------------------------------------------------------------+
|
|
| Author: Thomas Bruederli <roundcube@gmail.com> |
|
|
| Author: Aleksander Machniak <alec@alec.pl> |
|
|
+-----------------------------------------------------------------------+
|
|
*/
|
|
|
|
class rcmail_action_mail_import extends rcmail_action
|
|
{
|
|
// only process ajax requests
|
|
protected static $mode = self::MODE_AJAX;
|
|
|
|
/**
|
|
* Request handler.
|
|
*
|
|
* @param array $args Arguments from the previous step(s)
|
|
*/
|
|
#[Override]
|
|
public function run($args = [])
|
|
{
|
|
$rcmail = rcmail::get_instance();
|
|
|
|
// clear all stored output properties (like scripts and env vars)
|
|
$rcmail->output->reset();
|
|
|
|
if (!empty($_FILES['_file']) && is_array($_FILES['_file'])) {
|
|
$imported = 0;
|
|
$folder = $rcmail->storage->get_folder();
|
|
|
|
foreach ((array) $_FILES['_file']['tmp_name'] as $i => $filepath) {
|
|
// Process uploaded file if there is no error
|
|
$err = $_FILES['_file']['error'][$i];
|
|
|
|
if (!$err) {
|
|
// check file content type first
|
|
$ctype = rcube_mime::file_content_type($filepath, $_FILES['_file']['name'][$i], $_FILES['_file']['type'][$i]);
|
|
[$mtype_primary, $mtype_secondary] = explode('/', $ctype);
|
|
|
|
if (in_array($ctype, ['application/zip', 'application/x-zip'])) {
|
|
$filepath = self::zip_extract($filepath);
|
|
if (empty($filepath)) {
|
|
continue;
|
|
}
|
|
} elseif (!in_array($mtype_primary, ['text', 'message'])) {
|
|
continue;
|
|
}
|
|
|
|
foreach ((array) $filepath as $file) {
|
|
$imported += self::import_file($file, $folder);
|
|
|
|
// remove temp files extracted from zip
|
|
if (is_array($filepath)) {
|
|
unlink($file);
|
|
}
|
|
}
|
|
} else {
|
|
self::upload_error($err);
|
|
}
|
|
}
|
|
|
|
if ($imported) {
|
|
$rcmail->output->show_message($rcmail->gettext(['name' => 'importmessagesuccess', 'nr' => $imported, 'vars' => ['nr' => $imported]]), 'confirmation');
|
|
$rcmail->output->command('command', 'list');
|
|
} else {
|
|
$rcmail->output->show_message('importmessageerror', 'error');
|
|
}
|
|
} else {
|
|
self::upload_failure();
|
|
}
|
|
|
|
// send html page with JS calls as response
|
|
$rcmail->output->send('iframe');
|
|
}
|
|
|
|
/**
|
|
* Extract files from a zip archive
|
|
*
|
|
* @param string $path ZIP file location
|
|
*
|
|
* @return array List of extracted files
|
|
*/
|
|
public static function zip_extract($path)
|
|
{
|
|
if (!class_exists('ZipArchive', false)) {
|
|
return [];
|
|
}
|
|
|
|
$zip = new ZipArchive();
|
|
$files = [];
|
|
|
|
if ($zip->open($path)) {
|
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
$entry = $zip->getNameIndex($i);
|
|
$tmpfname = rcube_utils::temp_filename('zipimport');
|
|
|
|
if (copy("zip://{$path}#{$entry}", $tmpfname)) {
|
|
$ctype = rcube_mime::file_content_type($tmpfname, $entry);
|
|
[$mtype_primary] = explode('/', $ctype);
|
|
|
|
if (in_array($mtype_primary, ['text', 'message'])) {
|
|
$files[] = $tmpfname;
|
|
} else {
|
|
unlink($tmpfname);
|
|
}
|
|
}
|
|
}
|
|
|
|
$zip->close();
|
|
}
|
|
|
|
return $files;
|
|
}
|
|
|
|
/**
|
|
* Parse input file in mbox or eml format, save email messages
|
|
*
|
|
* @param string $file Filename
|
|
* @param string $folder IMAP folder
|
|
*
|
|
* @return int Number of imported messages
|
|
*/
|
|
public static function import_file($file, $folder)
|
|
{
|
|
$fp = fopen($file, 'r');
|
|
|
|
// read the first few lines to detect header-like structure
|
|
do {
|
|
$line = fgets($fp);
|
|
} while ($line !== false && trim($line) == '');
|
|
|
|
$format = null;
|
|
if (strncmp($line, 'From ', 5) === 0) {
|
|
$format = 'mbox';
|
|
} elseif (preg_match('/^[a-z-_]+:\s+.+/i', $line)) {
|
|
$format = 'eml';
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
$imported = 0;
|
|
$message = '';
|
|
|
|
fseek($fp, 0);
|
|
|
|
while (($line = fgets($fp)) !== false) {
|
|
// importing mbox file, split by From - lines
|
|
if ($format == 'mbox' && strncmp($line, 'From ', 5) === 0 && strlen($line) > 5) {
|
|
if (strlen($message)) {
|
|
$imported += (int) self::save_message($folder, $message, $format);
|
|
}
|
|
|
|
$message = $line;
|
|
$lastline = '';
|
|
continue;
|
|
}
|
|
|
|
$message .= $line;
|
|
}
|
|
|
|
if (strlen($message)) {
|
|
$imported += (int) self::save_message($folder, $message, $format);
|
|
}
|
|
|
|
fclose($fp);
|
|
|
|
return $imported;
|
|
}
|
|
|
|
/**
|
|
* Append the message to an IMAP folder
|
|
*/
|
|
public static function save_message($folder, &$message, $format = 'mbox')
|
|
{
|
|
$date = null;
|
|
|
|
if ($format == 'mbox') {
|
|
// Extract the mbox from_line
|
|
$pos = strpos($message, "\n");
|
|
$from = substr($message, 0, $pos);
|
|
$message = substr($message, $pos + 1);
|
|
|
|
// Read the received date, support only known date formats
|
|
|
|
// RFC4155: "Sat Jan 3 01:05:34 1996"
|
|
$mboxdate_rx = '/^([a-z]{3} [a-z]{3} [0-9 ][0-9] [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9]{4})/i';
|
|
// Roundcube/Zipdownload: "12-Dec-2016 10:56:33 +0100"
|
|
$imapdate_rx = '/^([0-9]{1,2}-[a-z]{3}-[0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2} [0-9+-]{5})/i';
|
|
|
|
if (
|
|
($pos = strpos($from, ' ', 6))
|
|
&& ($dt_str = substr($from, $pos + 1))
|
|
&& (preg_match($mboxdate_rx, $dt_str, $m) || preg_match($imapdate_rx, $dt_str, $m))
|
|
) {
|
|
try {
|
|
$date = new DateTime($m[0], new DateTimeZone('UTC'));
|
|
} catch (Exception $e) {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
// unquote ">From " lines in message body
|
|
$message = preg_replace('/\n>([>]*)From /', "\n\\1From ", $message);
|
|
}
|
|
|
|
$message = rtrim($message);
|
|
$rcmail = rcmail::get_instance();
|
|
|
|
if ($rcmail->storage->save_message($folder, $message, '', false, [], $date)) {
|
|
return true;
|
|
}
|
|
|
|
rcube::raise_error("Failed to import message to {$folder}", true, false);
|
|
|
|
return false;
|
|
}
|
|
}
|