diff --git a/include/class.mailparse.php b/include/class.mailparse.php index b9ab3c33ff34fd44496a92affbc38a276fc418b9..b02f2448a98a370cc0901231b11b435288d3c599 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -199,18 +199,60 @@ 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) $part=$this->getStruct(); - if($part && $part->disposition - && (!strcasecmp($part->disposition,'attachment') - || !strcasecmp($part->disposition,'inline') - || !strcasecmp($part->ctype_primary,'image'))){ - - if(!($filename=$part->d_parameters['filename']) && $part->d_parameters['filename*']) - $filename=$part->d_parameters['filename*']; //Do we need to decode? + /* Consider this part as an attachment if + * * It has a Content-Disposition header + * * AND it is specified as either 'attachment' or 'inline' + * * The Content-Type header specifies + * * type is image/* or application/* + * * has a name parameter + */ + if($part && ( + ($part->disposition + && (!strcasecmp($part->disposition,'attachment') + || !strcasecmp($part->disposition,'inline')) + ) + || (!strcasecmp($part->ctype_primary,'image') + || !strcasecmp($part->ctype_primary,'application')))) { + + if (isset($part->d_parameters['filename'])) + $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( + $part->d_parameters['filename*']); + + // Support attachments that do not specify a content-disposition + // but do specify a "name" parameter in the content-type header. + elseif (isset($part->ctype_parameters['name'])) + $filename=$part->ctype_parameters['name']; + elseif (isset($part->ctype_parameters['name*'])) + $filename = self::decodeRfc5987( + $part->ctype_parameters['name*']); + else + // Not an attachment? + return false; $file=array( 'name' => $filename,