| 1 |
<?php |
<?php |
| 2 |
/* $Id: mmb.module,v 1.5.2.9.2.1 2009/07/13 06:40:56 sanduhrs Exp $ */ |
/* $Id: mmb.module,v 1.5.2.9.2.2 2009/07/13 06:43:06 sanduhrs Exp $ */ |
| 3 |
|
|
| 4 |
/** |
/** |
| 5 |
* @file |
* @file |
| 8 |
* @author |
* @author |
| 9 |
* Stefan Auditor <stefan.auditor@erdfisch.de> |
* Stefan Auditor <stefan.auditor@erdfisch.de> |
| 10 |
* for erdfisch http://erdfisch.de |
* for erdfisch http://erdfisch.de |
|
* |
|
|
* TODO: |
|
|
* - Setting to attach images using image_attach.module |
|
|
* - Setting to create nodes instead of attachments if applicable (image,audio,video) |
|
|
* - Patch inline.module to display filetypes other than image inline ;) |
|
|
* (this seems to be a bigger problem than I thought by now http://drupal.org/node/35709) |
|
| 11 |
*/ |
*/ |
| 12 |
|
|
| 13 |
/** |
/** |
| 14 |
* Implementation of hook_mailhandler(). |
* Implementation of hook_mailhandler(). |
| 15 |
*/ |
*/ |
| 16 |
function mmb_mailhandler($node, $result, $i, $header, $mailbox) { |
function mmb_mailhandler($node, $result, $i, $header, $mailbox) { |
| 17 |
global $user; |
mmb_save_mimeparts($node); |
|
|
|
|
//Check if user is allowed to upload files |
|
|
if (!user_access('upload files')) { |
|
|
watchdog('error', t("The user '%u' may not upload files.", array('%u' => $user->name ? $user->name : variable_get('anonymous', t('Anonymous'))))); |
|
|
return $node; |
|
|
} |
|
|
|
|
|
//Get e-mail attachments |
|
|
$files = array(); |
|
|
mmb_get_parts($files, $result, $i, $structure = false, $part_number = false); |
|
|
|
|
|
//Attach them to the node |
|
|
$node->files = $files; |
|
|
|
|
|
//Save the attachments |
|
|
_mmb_validate($node); |
|
|
|
|
| 18 |
return $node; |
return $node; |
| 19 |
} |
} |
| 20 |
|
|
| 21 |
/** |
/** |
| 22 |
* Helper function to save a file temporarily |
* Attach the files to the node |
| 23 |
*/ |
* |
| 24 |
function mmb_save_part($data) { |
* @param $node |
|
$tmp_file = tempnam(file_directory_temp(), 'mmb_'); |
|
|
$file = file_save_data($data, $tmp_file); |
|
|
|
|
|
return $file; |
|
|
} |
|
|
|
|
|
/** |
|
|
* Get all parts of the e-mail an save the attachments |
|
| 25 |
*/ |
*/ |
| 26 |
function mmb_get_parts(&$files, $stream, $msg_number, $mime_type, $structure = false, $part_number = false) { |
function mmb_save_mimeparts(&$node) { |
| 27 |
$mimetypes = array('text', 'multipart', 'message', 'application', 'audio', 'image', 'video', 'other'); |
if (is_array($node->mimeparts)) { |
| 28 |
|
foreach ($node->mimeparts as $key => $part) { |
| 29 |
if (!$structure) { |
if ($file = mmb_file_save($part)) { |
| 30 |
$structure = imap_fetchstructure($stream, $msg_number); |
$node->files[$file->fid] = $file; |
|
} |
|
|
if ($structure) { |
|
|
foreach ($structure->parameters as $parameter) { |
|
|
|
|
|
if (strtoupper($parameter->attribute) == 'CHARSET') { |
|
|
$encoding = $parameter->value; |
|
|
} |
|
|
} |
|
|
|
|
|
if (!$part_number) { |
|
|
$part_number = '1'; |
|
|
} |
|
|
|
|
|
$index = explode('.', $part_number); |
|
|
$data = imap_fetchbody($stream, $msg_number, $index[1]); |
|
|
|
|
|
if ($structure->encoding == 3) { |
|
|
$data = base64_decode($data); |
|
|
} |
|
|
else if ($structure->encoding == 4) { |
|
|
$data = quoted_printable_decode($data); |
|
|
} |
|
|
else { |
|
|
$data = $data; |
|
|
} |
|
|
|
|
|
if (strtolower($structure->dparameters[0]->attribute) == 'filename' AND $structure->dparameters[0]->value != '') { |
|
|
$key = 'upload_'. (count($files)+1); |
|
|
$files[$key]['fid'] = $key; |
|
|
$files[$key]['source'] = $key; |
|
|
$files[$key]['filename'] = strtolower(imap_utf8($structure->dparameters[0]->value)); |
|
|
$files[$key]['filepath'] = mmb_save_part($data); |
|
|
$files[$key]['filemime'] = $mimetypes[strtolower($structure->type)] .'/'. strtolower($structure->subtype); |
|
|
$files[$key]['filesize'] = strlen($data); |
|
|
$files[$key]['list'] = variable_get('upload_list_default', 1); |
|
|
} |
|
|
|
|
|
if ($structure->type == 1) { /* multipart */ |
|
|
while (list($index, $sub_structure) = each ($structure->parts)) { |
|
|
if ($part_number) { |
|
|
$prefix = $part_number .'.'; |
|
|
} |
|
|
mmb_get_parts($files, $stream, $msg_number, $mime_type, $sub_structure, $prefix . ($index + 1)); |
|
| 31 |
} |
} |
| 32 |
} |
} |
| 33 |
} |
} |
|
|
|
|
return; |
|
| 34 |
} |
} |
| 35 |
|
|
| 36 |
/** |
/** |
| 37 |
* From upload.module |
* Validate and save file |
| 38 |
* Changed from form_set_error- to watchdog-messages |
* |
| 39 |
|
* @param $part |
| 40 |
|
* @param $validators |
| 41 |
|
* @return unknown_type |
| 42 |
*/ |
*/ |
| 43 |
function _mmb_validate(&$node) { |
function mmb_file_save($part) { |
| 44 |
// Accumulator for disk space quotas. |
global $user; |
| 45 |
$filesize = 0; |
|
| 46 |
|
// Build the list of non-munged extensions. |
| 47 |
// Check if node->files exists, and if it contains something. |
$extensions = ''; |
| 48 |
if (is_array($node->files)) { |
foreach ($user->roles as $rid => $name) { |
| 49 |
// Update existing files with form data. |
$extensions .= ' '. variable_get("upload_extensions_$rid", |
| 50 |
foreach ($node->files as $fid => $file) { |
variable_get('upload_extensions_default', 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp')); |
|
// Convert file to object for compatibility |
|
|
$file = (object)$file; |
|
|
|
|
|
// Validate new uploads. |
|
|
if (strpos($fid, 'upload') !== false && !$file->remove) { |
|
|
global $user; |
|
|
|
|
|
// Bypass validation for uid = 1. |
|
|
if ($user->uid != 1) { |
|
|
// Update filesize accumulator. |
|
|
$filesize += $file->filesize; |
|
|
|
|
|
// Validate file against all users roles. |
|
|
// Only denies an upload when all roles prevent it. |
|
|
|
|
|
$total_usersize = upload_space_used($user->uid) + $filesize; |
|
|
$error = array(); |
|
|
foreach ($user->roles as $rid => $name) { |
|
|
$extensions = variable_get("upload_extensions_$rid", 'jpg jpeg gif png txt html doc xls pdf ppt pps odt ods odp'); |
|
|
$uploadsize = variable_get("upload_uploadsize_$rid", 1) * 1024 * 1024; |
|
|
$usersize = variable_get("upload_usersize_$rid", 10) * 1024 * 1024; |
|
|
|
|
|
$regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i'; |
|
|
|
|
|
if (!preg_match($regex, $file->filename)) { |
|
|
$error['extension']++; |
|
|
} |
|
|
|
|
|
if ($uploadsize && $file->filesize > $uploadsize) { |
|
|
$error['uploadsize']++; |
|
|
} |
|
|
|
|
|
if ($usersize && $total_usersize + $file->filesize > $usersize) { |
|
|
$error['usersize']++; |
|
|
} |
|
|
} |
|
|
|
|
|
$user_roles = count($user->roles); |
|
|
$valid = TRUE; |
|
|
if ($error['extension'] == $user_roles) { |
|
|
// form_set_error('upload', t('The selected file %name can not be attached to this post, because it is only possible to attach files with the following extensions: %files-allowed.', array('%name' => $file->filename, '%files-allowed' => $extensions))); |
|
|
watchdog('mmb', 'The selected file %name can not be attached to this post, because it is only possible to attach files with the following extensions: %files-allowed.', array('%name' => $file->filename, '%files-allowed' => $extensions)); |
|
|
$valid = FALSE; |
|
|
} |
|
|
elseif ($error['uploadsize'] == $user_roles) { |
|
|
// form_set_error('upload', t('The selected file %name can not be attached to this post, because it exceeded the maximum filesize of %maxsize.', array('%name' => $file->filename, '%maxsize' => format_size($uploadsize)))); |
|
|
watchdog('mmb', 'The selected file %name can not be attached to this post, because it exceeded the maximum filesize of %maxsize.', array('%name' => $file->filename, '%maxsize' => format_size($uploadsize))); |
|
|
$valid = FALSE; |
|
|
} |
|
|
elseif ($error['usersize'] == $user_roles) { |
|
|
// form_set_error('upload', t('The selected file %name can not be attached to this post, because the disk quota of %quota has been reached.', array('%name' => $file->filename, '%quota' => format_size($usersize)))); |
|
|
watchdog('mmb', 'The selected file %name can not be attached to this post, because the disk quota of %quota has been reached.', array('%name' => $file->filename, '%quota' => format_size($usersize))); |
|
|
$valid = FALSE; |
|
|
} |
|
|
elseif (strlen($file->filename) > 255) { |
|
|
// form_set_error('upload', t('The selected file %name can not be attached to this post, because the filename is too long.', array('%name' => $file->filename))); |
|
|
watchdog('mmb', 'The selected file %name can not be attached to this post, because the filename is too long.', array('%name' => $file->filename)); |
|
|
$valid = FALSE; |
|
|
} |
|
|
|
|
|
if (!$valid) { |
|
|
unset($node->files[$fid], $_SESSION['file_previews'][$fid]); |
|
|
file_delete($file->filepath); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
| 51 |
} |
} |
|
} |
|
| 52 |
|
|
| 53 |
|
// Begin building file object. |
| 54 |
|
$file = new stdClass(); |
| 55 |
|
$file->new = TRUE; |
| 56 |
|
$file->list = 1; |
| 57 |
|
|
| 58 |
|
if ($part->filename == 'unnamed_attachment') { |
| 59 |
|
$part->filename = $part->filename .'.txt'; |
| 60 |
|
$file->list = 0; |
| 61 |
|
} |
| 62 |
|
|
| 63 |
|
$file->filename = truncate_utf8(file_munge_filename(trim($part->filename, '.'), $extensions, FALSE), 255); |
| 64 |
|
$file->filepath = file_destination(file_create_path(file_directory_path() .'/'. $file->filename), FILE_EXISTS_RENAME); |
| 65 |
|
$file->filemime = $part->filemime; |
| 66 |
|
$file->filesize = strlen($part->data); |
| 67 |
|
|
| 68 |
|
// Rename potentially executable files, to help prevent exploits. |
| 69 |
|
if (preg_match('/\.(php|pl|py|cgi|asp|js)$/i', $file->filename) && (substr($file->filename, -4) != '.txt')) { |
| 70 |
|
$file->filemime = 'text/plain'; |
| 71 |
|
$file->filepath .= '.txt'; |
| 72 |
|
$file->filename .= '.txt'; |
| 73 |
|
} |
| 74 |
|
|
| 75 |
|
// If we made it this far it's safe to record this file in the database. |
| 76 |
|
$file->uid = $user->uid; |
| 77 |
|
$file->status = FILE_STATUS_PERMANENT; |
| 78 |
|
$file->timestamp = time(); |
| 79 |
|
if ($file->filepath = file_save_data($part->data, $file->filepath)) { |
| 80 |
|
drupal_write_record('files', $file); |
| 81 |
|
return $file; |
| 82 |
|
} |
| 83 |
|
|
| 84 |
|
return FALSE; |
| 85 |
|
} |