Commit c2f11b36 authored by Manfred Kutas's avatar Manfred Kutas

ZP-584 downloading email attachments within public folders fails on some

android devices.

Released under the Affero GNU General Public License (AGPL) version 3.
parent e3ac9b1d
...@@ -210,6 +210,7 @@ class MAPIMapping { ...@@ -210,6 +210,7 @@ class MAPIMapping {
"html" => PR_HTML, "html" => PR_HTML,
"rtfinsync" => PR_RTF_IN_SYNC, "rtfinsync" => PR_RTF_IN_SYNC,
"processed" => PR_PROCESSED, "processed" => PR_PROCESSED,
"storeentryid" => PR_STORE_ENTRYID,
); );
} }
......
...@@ -677,6 +677,7 @@ class MAPIProvider { ...@@ -677,6 +677,7 @@ class MAPIProvider {
$attachtable = mapi_message_getattachmenttable($mapimessage); $attachtable = mapi_message_getattachmenttable($mapimessage);
$rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM));
$entryid = bin2hex($messageprops[$emailproperties["entryid"]]); $entryid = bin2hex($messageprops[$emailproperties["entryid"]]);
$storeentryid = bin2hex($messageprops[$emailproperties["storeentryid"]]);
foreach($rows as $row) { foreach($rows as $row) {
if(isset($row[PR_ATTACH_NUM])) { if(isset($row[PR_ATTACH_NUM])) {
...@@ -708,7 +709,7 @@ class MAPIProvider { ...@@ -708,7 +709,7 @@ class MAPIProvider {
// set AS version specific parameters // set AS version specific parameters
if (Request::GetProtocolVersion() >= 12.0) { if (Request::GetProtocolVersion() >= 12.0) {
$attach->filereference = $entryid.":".$row[PR_ATTACH_NUM]; $attach->filereference = sprintf("%s:%s:%s", $storeentryid, $entryid, $row[PR_ATTACH_NUM]);
$attach->method = (isset($attachprops[PR_ATTACH_METHOD])) ? $attachprops[PR_ATTACH_METHOD] : ATTACH_BY_VALUE; $attach->method = (isset($attachprops[PR_ATTACH_METHOD])) ? $attachprops[PR_ATTACH_METHOD] : ATTACH_BY_VALUE;
// if displayname does not have the eml extension for embedde messages, android and WP devices won't open it // if displayname does not have the eml extension for embedde messages, android and WP devices won't open it
...@@ -741,7 +742,7 @@ class MAPIProvider { ...@@ -741,7 +742,7 @@ class MAPIProvider {
} }
else { else {
$attach->attsize = $attachprops[PR_ATTACH_SIZE]; $attach->attsize = $attachprops[PR_ATTACH_SIZE];
$attach->attname = $entryid.":".$row[PR_ATTACH_NUM]; $attach->attname = sprintf("%s:%s:%s", $storeentryid, $entryid, $row[PR_ATTACH_NUM]);
if(!isset($message->attachments)) if(!isset($message->attachments))
$message->attachments = array(); $message->attachments = array();
......
...@@ -82,6 +82,7 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -82,6 +82,7 @@ class BackendZarafa implements IBackend, ISearchProvider {
private $store; private $store;
private $storeName; private $storeName;
private $storeCache; private $storeCache;
private $storeProps;
private $importedFolders; private $importedFolders;
private $notifications; private $notifications;
private $changesSink; private $changesSink;
...@@ -108,6 +109,7 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -108,6 +109,7 @@ class BackendZarafa implements IBackend, ISearchProvider {
$this->store = false; $this->store = false;
$this->storeName = false; $this->storeName = false;
$this->storeCache = array(); $this->storeCache = array();
$this->storeProps = array();
$this->importedFolders = array(); $this->importedFolders = array();
$this->notifications = false; $this->notifications = false;
$this->changesSink = false; $this->changesSink = false;
...@@ -665,10 +667,40 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -665,10 +667,40 @@ class BackendZarafa implements IBackend, ISearchProvider {
if(!strpos($attname, ":")) if(!strpos($attname, ":"))
throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, attachment requested for non-existing item", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, attachment requested for non-existing item", $attname), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
list($id, $attachnum) = explode(":", $attname); // backwards compatibility if the storeentryid is not available in the $attname
if (substr_count($attname, ':') == 1) {
list($id, $attachnum) = explode(":", $attname);
}
else {
list($storeEntryid, $id, $attachnum) = explode(":", $attname);
}
// Assume that the attachment is in the user's store.
$store = $this->store;
$entryid = hex2bin($id); $entryid = hex2bin($id);
$message = mapi_msgstore_openentry($this->store, $entryid); if (isset($storeEntryid)) {
$storeEntryid = hex2bin($storeEntryid);
$storeProps = $this->getStoreProps();
// If the attachment is not in the user's store, check if public store is available and it's there.
// Otherwise try to open the store.
if ($storeProps[PR_ENTRYID] != $storeEntryid) {
if (isset($this->storeCache['SYSTEM']) && $this->storeCache['SYSTEM'] == $storeEntryid) {
ZLog::Write(LOGLEVEL_DEBUG, 'ZarafaBackend->GetAttachmentData the attachment is in a message in a public store.');
$store = $this->storeCache['SYSTEM'];
}
else {
ZLog::Write(LOGLEVEL_DEBUG, sprintf("Open store %s", bin2hex($storeEntryid)));
$store = @mapi_openmsgstore($this->session, $storeEntryid);
if (!$store) {
ZLog::Write(LOGLEVEL_WARN, sprintf("ZarafaBackend->GetAttachmentData: Could not open store %s", bin2hex($storeEntryid)));
return false;
}
}
}
}
$message = mapi_msgstore_openentry($store, $entryid);
if(!$message) if(!$message)
throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, unable to open item for attachment data for id '%s' with: 0x%X", $attname, $id, mapi_last_hresult()), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT); throw new StatusException(sprintf("ZarafaBackend->GetAttachmentData('%s'): Error, unable to open item for attachment data for id '%s' with: 0x%X", $attname, $id, mapi_last_hresult()), SYNC_ITEMOPERATIONSSTATUS_INVALIDATT);
...@@ -2091,6 +2123,20 @@ class BackendZarafa implements IBackend, ISearchProvider { ...@@ -2091,6 +2123,20 @@ class BackendZarafa implements IBackend, ISearchProvider {
} }
return true; return true;
} }
/**
* Gets the required store properties.
*
* @access private
* @return array
*/
private function getStoreProps() {
if (empty($this->storeProps)) {
ZLog::Write(LOGLEVEL_DEBUG, "BackendZarafa->getStoreProps(): Getting store properties.");
$this->storeProps = mapi_getprops($this->store, array(PR_ENTRYID));
}
return $this->storeProps;
}
} }
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment