Skip to content
Snippets Groups Projects
Commit b28e8ff0 authored by Jared Hancock's avatar Jared Hancock
Browse files

Implement RFC5987 for fetched attachments

Previously, filenames specified in email headers fetched using the PHP imap
extension were not decoded properly. Specifically, if RFC5987 was used to
encode the filenames, no decoding was performed at all.

This patch properly detects the filename attribute, using a decoding scheme
for RFC5987 if the attribute was encoded properly.

References:
http://osticket.com/forums/showthread.php?t=6129
parent 1cbc6f69
Branches
Tags
No related merge requests found
......@@ -86,6 +86,23 @@ class Format {
return $text;
}
/**
* Decodes filenames given in the content-disposition header according
* to RFC5987, such as filename*=utf-8''filename.png. Note that the
* language sub-component is defined in RFC5646, and that the filename
* is URL encoded (in the charset specified)
*/
function decodeRfc5987($filename) {
$match = array();
if (preg_match("/([\w!#$%&+^_`{}~-]+)'([\w-]*)'(.*)$/",
$filename, $match))
// XXX: Currently we don't care about the language component.
// The encoding hint is sufficient.
return self::utf8encode(urldecode($match[3]), $match[1]);
else
return $filename;
}
function phone($phone) {
$stripped= preg_replace("/[^0-9]/", "", $phone);
......
......@@ -308,6 +308,31 @@ class MailFetcher {
return $text;
}
/**
* Searches the attribute list for a possible filename attribute. If
* found, the attribute value is returned. If the attribute uses rfc5987
* to encode the attribute value, the value is returned properly decoded
* if possible
*
* Attribute Search Preference:
* filename
* filename*
* name
* name*
*/
function findFilename($attributes) {
foreach (array('filename', 'name') as $pref) {
foreach ($attributes as $a) {
if (strtolower($a->attribute) == $pref)
return $a->value;
// Allow the RFC5987 specification of the filename
elseif (strtolower($a->attribute) == $pref.'*')
return Format::decodeRfc5987($a->value);
}
}
return false;
}
/*
getAttachments
......@@ -319,23 +344,16 @@ class MailFetcher {
if($part && !$part->parts) {
//Check if the part is an attachment.
$filename = '';
if($part->ifdisposition && in_array(strtolower($part->disposition), array('attachment', 'inline'))) {
$filename = $part->dparameters[0]->value;
//Some inline attachments have multiple parameters.
if(count($part->dparameters)>1) {
foreach($part->dparameters as $dparameter) {
if(!in_array(strtoupper($dparameter->attribute), array('FILENAME', 'NAME'))) continue;
$filename = $dparameter->value;
break;
}
}
} elseif($part->ifparameters && $part->parameters && $part->type > 0) { //inline attachments without disposition.
foreach($part->parameters as $parameter) {
if(!in_array(strtoupper($parameter->attribute), array('FILENAME', 'NAME'))) continue;
$filename = $parameter->value;
break;
}
$filename = false;
if ($part->ifdisposition
&& in_array(strtolower($part->disposition),
array('attachment', 'inline'))) {
$filename = $this->findFilename($part->dparameters);
}
// Inline attachments without disposition.
if (!$filename && $part->ifparameters && $part->parameters
&& $part->type > 0) {
$filename = $this->findFilename($part->parameters);
}
if($filename) {
......
......@@ -199,23 +199,6 @@ class Mail_Parse {
return Format::encode($text, $charset, $encoding);
}
/**
* Decodes filenames given in the content-disposition header according
* to RFC5987, such as filename*=utf-8''filename.png. Note that the
* language sub-component is defined in RFC5646, and that the filename
* is URL encoded (in the charset specified)
*/
function decodeRfc5987($filename) {
$match = array();
if (preg_match("/([\w!#$%&+^_`{}~-]+)'([\w-]*)'(.*)$/",
$filename, $match))
// XXX: Currently we don't care about the language component.
// The encoding hint is sufficient.
return self::mime_encode(urldecode($match[3]), $match[1]);
else
return $filename;
}
function getAttachments($part=null){
if($part==null)
......@@ -240,7 +223,7 @@ class Mail_Parse {
$filename = $part->d_parameters['filename'];
elseif (isset($part->d_parameters['filename*']))
// Support RFC 6266, section 4.3 and RFC, and RFC 5987
$filename = self::decodeRfc5987(
$filename = Format::decodeRfc5987(
$part->d_parameters['filename*']);
// Support attachments that do not specify a content-disposition
......@@ -248,7 +231,7 @@ class Mail_Parse {
elseif (isset($part->ctype_parameters['name']))
$filename=$part->ctype_parameters['name'];
elseif (isset($part->ctype_parameters['name*']))
$filename = self::decodeRfc5987(
$filename = Format::decodeRfc5987(
$part->ctype_parameters['name*']);
else
// Not an attachment?
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment