* Mail: Resolve ms-tnef attachments if possible, and required backend functionality is assumed to be available

This commit is contained in:
Klaus Leithoff 2014-09-30 14:06:11 +00:00
parent 932c78bc6d
commit 50ea60a01c

View File

@ -1486,6 +1486,36 @@ class emailadmin_imapbase
$headerObject['ATTACHMENTS'][$mime_id]['cid'] = $cid; $headerObject['ATTACHMENTS'][$mime_id]['cid'] = $cid;
$headerObject['ATTACHMENTS'][$mime_id]['partID']=$mime_id; $headerObject['ATTACHMENTS'][$mime_id]['partID']=$mime_id;
if (!isset($headerObject['ATTACHMENTS'][$mime_id]['name']))$headerObject['ATTACHMENTS'][$mime_id]['name']=$part->getName(); if (!isset($headerObject['ATTACHMENTS'][$mime_id]['name']))$headerObject['ATTACHMENTS'][$mime_id]['name']=$part->getName();
if ($headerObject['ATTACHMENTS'][$mime_id]['name']=='winmail.dat' &&
($headerObject['ATTACHMENTS'][$mime_id]['mimeType']=='application/octet-stream' ||
$headerObject['ATTACHMENTS'][$mime_id]['mimeType']=='application/ms-tnef'))
{
$tnefResolved=false;
$tnef_data = $this->getAttachment($headerObject['ATTACHMENTS'][$mime_id]['uid'],$headerObject['ATTACHMENTS'][$mime_id]['partID'],0,false);
$myTnef = $this->tnef_decoder($tnef_data['attachment']);
//error_log(__METHOD__.__LINE__.array2string($myTnef->getParts()));
// Note: MimeId starts with 0, almost always, we cannot use that as winmail_id
// we need to build Something that meets the needs
if ($myTnef)
{
foreach($myTnef->getParts() as $vmime_id => $part)
{
$tnefResolved=true;
$attachment = $part->getAllDispositionParameters();
$attachment['mimeType'] = $part->getType();
$attachment['uid'] = $headerObject['ATTACHMENTS'][$mime_id]['uid'];
$attachment['partID'] = $headerObject['ATTACHMENTS'][$mime_id]['partID'];
$attachment['is_winmail'] = $headerObject['ATTACHMENTS'][$mime_id]['uid'].'@'.$headerObject['ATTACHMENTS'][$mime_id]['partID'].'@'.$vmime_id;
if (!isset($attachment['name'])||empty($attachment['name'])) $attachment['name'] = $part->getName();
$attachment['size'] = $part->getBytes();
if (($cid = $part->getContentId())) $attachment['cid'] = $cid;
if (empty($attachment['name'])) $attachment['name'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$_uid.'_Part'.$mime_id).'.'.mime_magic::mime2ext($attachment['mimeType']);
$headerObject['ATTACHMENTS'][$mime_id.'.'.$vmime_id] = $attachment;
}
if ($tnefResolved) unset($headerObject['ATTACHMENTS'][$mime_id]);
}
}
//error_log(__METHOD__.' ('.__LINE__.') '.' PartDisposition:'.$mime_id.'->'.array2string($part->getName())); //error_log(__METHOD__.' ('.__LINE__.') '.' PartDisposition:'.$mime_id.'->'.array2string($part->getName()));
//error_log(__METHOD__.' ('.__LINE__.') '.' PartDisposition:'.$mime_id.'->'.array2string($part->getAllDispositionParameters())); //error_log(__METHOD__.' ('.__LINE__.') '.' PartDisposition:'.$mime_id.'->'.array2string($part->getAllDispositionParameters()));
//error_log(__METHOD__.' ('.__LINE__.') '.' Attachment:'.$mime_id.'->'.array2string($headerObject['ATTACHMENTS'][$mime_id])); //error_log(__METHOD__.' ('.__LINE__.') '.' Attachment:'.$mime_id.'->'.array2string($headerObject['ATTACHMENTS'][$mime_id]));
@ -4788,6 +4818,7 @@ class emailadmin_imapbase
if (!$_structure || !$_structure->contentTypeMap()) return array(); if (!$_structure || !$_structure->contentTypeMap()) return array();
if (!empty($_partID)) $_structure = $_structure->getPart($_partID); if (!empty($_partID)) $_structure = $_structure->getPart($_partID);
$skipParts = array(); $skipParts = array();
$tnefParts = array();
foreach($_structure->contentTypeMap() as $mime_id => $mime_type) foreach($_structure->contentTypeMap() as $mime_id => $mime_type)
{ {
$part = $_structure->getPart($mime_id); $part = $_structure->getPart($mime_id);
@ -4817,6 +4848,7 @@ class emailadmin_imapbase
// we attempt to fetch "ourselves" // we attempt to fetch "ourselves"
if ($_partID==$part->getMimeId() && $part->getPrimaryType()=='message') continue; if ($_partID==$part->getMimeId() && $part->getPrimaryType()=='message') continue;
$attachment = $part->getAllDispositionParameters(); $attachment = $part->getAllDispositionParameters();
$attachment['mimeType'] = $mime_type; $attachment['mimeType'] = $mime_type;
$attachment['uid'] = $_uid; $attachment['uid'] = $_uid;
$attachment['partID'] = $mime_id; $attachment['partID'] = $mime_id;
@ -4831,9 +4863,52 @@ class emailadmin_imapbase
$attachment['size'] = $part->getBytes(); $attachment['size'] = $part->getBytes();
if (($cid = $part->getContentId())) $attachment['cid'] = $cid; if (($cid = $part->getContentId())) $attachment['cid'] = $cid;
if (empty($attachment['name'])) $attachment['name'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$_uid.'_Part'.$mime_id).'.'.mime_magic::mime2ext($mime_type); if (empty($attachment['name'])) $attachment['name'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$_uid.'_Part'.$mime_id).'.'.mime_magic::mime2ext($mime_type);
$attachments[] = $attachment; //error_log(__METHOD__.' ('.__LINE__.') '.' Uid:'.$uid.' Part:'.$_partID.'->'.$mime_id.':'.array2string($attachment));
//typical winmail.dat attachment is
//Array([size] => 1462762[filename] => winmail.dat[mimeType] => application/ms-tnef[uid] => 100[partID] => 2[name] => winmail.dat)
if ($resolveTNEF && $attachment['mimeType']=='application/ms-tnef')
{
$tnefParts[] = $attachment;
}
else
{
$attachments[] = $attachment;
}
} }
} }
if ($resolveTNEF && !empty($tnefParts))
{
//error_log(__METHOD__.__LINE__.array2string($tnefParts));
foreach ($tnefParts as $k => $tnp)
{
$tnefResolved=false;
$tnef_data = $this->getAttachment($tnp['uid'],$tnp['partID'],$k,false);
$myTnef = $this->tnef_decoder($tnef_data['attachment']);
//error_log(__METHOD__.__LINE__.array2string($myTnef->getParts()));
// Note: MimeId starts with 0, almost always, we cannot use that as winmail_id
// we need to build Something that meets the needs
if ($myTnef)
{
foreach($myTnef->getParts() as $mime_id => $part)
{
$tnefResolved=true;
$attachment = $part->getAllDispositionParameters();
$attachment['mimeType'] = $part->getType();
$attachment['uid'] = $tnp['uid'];
$attachment['partID'] = $tnp['partID'];
$attachment['is_winmail'] = $tnp['uid'].'@'.$tnp['partID'].'@'.$mime_id;
if (!isset($attachment['name'])||empty($attachment['name'])) $attachment['name'] = $part->getName();
$attachment['size'] = $part->getBytes();
if (($cid = $part->getContentId())) $attachment['cid'] = $cid;
if (empty($attachment['name'])) $attachment['name'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$_uid.'_Part'.$mime_id).'.'.mime_magic::mime2ext($attachment['mimeType']);
$attachments[] = $attachment;
}
}
if ($tnefResolved===false) $attachments[]=$tnp;
}
}
//error_log(__METHOD__.__LINE__.array2string($attachments));
return $attachments; return $attachments;
} }
@ -4845,10 +4920,11 @@ class emailadmin_imapbase
* @return boolean|Horde_Mime_part Multipart/Mixed part decoded attachments | * @return boolean|Horde_Mime_part Multipart/Mixed part decoded attachments |
* return false if there's no attachments or failure * return false if there's no attachments or failure
*/ */
public function tnef_decoder($_uid, $data ) public function tnef_decoder( $data )
{ {
if (class_exists('Horde_Compress',true)==false) return false;
$parts_obj = $this->getStructure($_uid); $parts_obj = new Horde_Mime_part;
$parts_obj->setType('multipart/mixed'); $parts_obj->setType('multipart/mixed');
$tnef_object = Horde_Compress::factory('tnef'); $tnef_object = Horde_Compress::factory('tnef');
@ -4862,7 +4938,7 @@ class emailadmin_imapbase
{ {
foreach ($tnef_data as &$data) foreach ($tnef_data as &$data)
{ {
$tmp_part = $this->getStructure($_uid); $tmp_part = new Horde_Mime_part;
$tmp_part->setName($data['name']); $tmp_part->setName($data['name']);
$tmp_part->setContents($data['stream']); $tmp_part->setContents($data['stream']);
@ -4873,9 +4949,11 @@ class emailadmin_imapbase
{ {
$type = Horde_Mime_Magic::filenameToMIME($data['name']); $type = Horde_Mime_Magic::filenameToMIME($data['name']);
} }
$tmp_part->setType($data['type']); $tmp_part->setType($type);
//error_log(__METHOD__.__LINE__.array2string($tmp_part));
$parts_obj->addPart($tmp_part); $parts_obj->addPart($tmp_part);
} }
$parts_obj->buildMimeIds();
return $parts_obj; return $parts_obj;
} }
return false; return false;
@ -4894,6 +4972,7 @@ class emailadmin_imapbase
*/ */
function getAttachment($_uid, $_partID, $_winmail_nr=0, $_returnPart=true, $_stream=false) function getAttachment($_uid, $_partID, $_winmail_nr=0, $_returnPart=true, $_stream=false)
{ {
//error_log(__METHOD__.__LINE__."Uid:$_uid, PartId:$_partID, WinMailNr:$_winmail_nr, ReturnPart:$_returnPart, Stream:$_stream");
$_folder = ($this->sessionData['mailbox']? $this->sessionData['mailbox'] : $this->icServer->getCurrentMailbox()); $_folder = ($this->sessionData['mailbox']? $this->sessionData['mailbox'] : $this->icServer->getCurrentMailbox());
$uidsToFetch = new Horde_Imap_Client_Ids(); $uidsToFetch = new Horde_Imap_Client_Ids();
@ -4938,27 +5017,57 @@ class emailadmin_imapbase
} }
$ext = mime_magic::mime2ext($structure_mime); $ext = mime_magic::mime2ext($structure_mime);
if ($ext && stripos($filename,'.')===false && stripos($filename,$ext)===false) $filename = trim($filename).'.'.$ext; if ($ext && stripos($filename,'.')===false && stripos($filename,$ext)===false) $filename = trim($filename).'.'.$ext;
//error_log(__METHOD__.__LINE__.'#'.$structure_mime.'#'.$filename);
$attachmentData = array( $attachmentData = array(
'type' => $structure_mime, 'type' => $structure_mime,
'filename' => $filename, 'filename' => $filename,
'attachment' => $part->getContents(array('stream'=>$_stream)) 'attachment' => $part->getContents(array('stream'=>$_stream))
); );
/*
// try guessing the mimetype, if we get the application/octet-stream // try guessing the mimetype, if we get the application/octet-stream
if (strtolower($attachmentData['type']) == 'application/octet-stream') $attachmentData['type'] = mime_magic::filename2mime($attachmentData['filename']); if (strtolower($attachmentData['type']) == 'application/octet-stream') $attachmentData['type'] = mime_magic::filename2mime($attachmentData['filename']);
# if the attachment holds a winmail number and is a winmail.dat then we have to handle that. # if the attachment holds a winmail number and is a winmail.dat then we have to handle that.
if ( $filename == 'winmail.dat' && $_winmail_nr > 0 && if ( $filename == 'winmail.dat' && $_winmail_nr)
( $wmattach = $this->decode_winmail( $_uid, $_partID, $_winmail_nr ) ) )
{ {
$ext = mime_magic::mime2ext($wmattach['type']); //by now _uid is of type array
if ($ext && stripos($wmattach['name'],'.')===false && stripos($wmattach['name'],$ext)===false) $wmattach['name'] = trim($wmattach['name']).'.'.$ext; $tnefResolved=false;
$attachmentData = array( $wantedPart=$_uid[0].'@'.$_partID;
'type' => $wmattach['type'], $myTnef = $this->tnef_decoder($attachmentData['attachment']);
'filename' => $wmattach['name'], //error_log(__METHOD__.__LINE__.array2string($myTnef->getParts()));
'attachment' => $wmattach['attachment'], // Note: MimeId starts with 0, almost always, we cannot use that as winmail_id
); // we need to build Something that meets the needs
if ($myTnef)
{
foreach($myTnef->getParts() as $mime_id => $part)
{
$tnefResolved=true;
$attachment = $part->getAllDispositionParameters();
$attachment['mimeType'] = $part->getType();
//error_log(__METHOD__.__LINE__.'#'.$mime_id.'#'.$filename.'#'.array2string($attachment));
//error_log(__METHOD__.__LINE__." $_winmail_nr == $wantedPart@$mime_id");
if ($_winmail_nr == $wantedPart.'@'.$mime_id)
{
//error_log(__METHOD__.__LINE__.'#'.$structure_mime.'#'.$filename.'#'.array2string($attachment));
if (!isset($attachment['filename'])||empty($attachment['filename'])) $attachment['filename'] = $part->getName();
if (($cid = $part->getContentId())) $attachment['cid'] = $cid;
if (empty($attachment['filename'])) $attachment['filename'] = (isset($attachment['cid'])&&!empty($attachment['cid'])?$attachment['cid']:lang("unknown").'_Uid'.$_uid.'_Part'.$mime_id).'.'.mime_magic::mime2ext($attachment['mimeType']);
$wmattach = $attachment;
$wmattach['attachment'] = $part->getContents(array('stream'=>$_stream));
}
}
}
if ($tnefResolved)
{
$ext = mime_magic::mime2ext($wmattach['mimeType']);
if ($ext && stripos($wmattach['filename'],'.')===false && stripos($wmattach['filename'],$ext)===false) $wmattach['filename'] = trim($wmattach['filename']).'.'.$ext;
$attachmentData = array(
'type' => $wmattach['mimeType'],
'filename' => $wmattach['filename'],
'attachment' => $wmattach['attachment'],
);
}
} }
*/
return $attachmentData; return $attachmentData;
} }