mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-11 00:14:50 +03:00
Save attachments as ...
This commit is contained in:
parent
f5f067f1f3
commit
48b91fb957
20 changed files with 687 additions and 76 deletions
19
build/test.php
Normal file
19
build/test.php
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
// simple connection test
|
||||
|
||||
$host = 'imap.gmail.com';
|
||||
$port = 993;
|
||||
|
||||
echo $host.':'.$port;
|
||||
|
||||
$errorStr = '';
|
||||
$errorNo = 0;
|
||||
|
||||
$connection = stream_socket_client($host.':'.$port, $errorNo, $errorStr, 5, STREAM_CLIENT_CONNECT);
|
||||
if (is_resource($connection)) {
|
||||
echo ' = OK';
|
||||
fclose($connection);
|
||||
} else {
|
||||
echo ' = ERROR ([#'.$errorNo.'] '.$errorStr.')';
|
||||
}
|
||||
|
|
@ -59,47 +59,62 @@
|
|||
|
||||
/**
|
||||
* @param {string} sDownload
|
||||
* @param {string=} sCustomSpecSuffix
|
||||
* @return {string}
|
||||
*/
|
||||
Links.prototype.attachmentDownload = function (sDownload)
|
||||
Links.prototype.attachmentDownload = function (sDownload, sCustomSpecSuffix)
|
||||
{
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/Download/' + this.subQueryPrefix() + '/' + sDownload;
|
||||
sCustomSpecSuffix = Utils.isUnd(sCustomSpecSuffix) ? this.sSpecSuffix : sCustomSpecSuffix;
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + sCustomSpecSuffix + '/Download/' +
|
||||
this.subQueryPrefix() + '/' + sDownload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} sDownload
|
||||
* @param {string=} sCustomSpecSuffix
|
||||
* @return {string}
|
||||
*/
|
||||
Links.prototype.attachmentPreview = function (sDownload)
|
||||
Links.prototype.attachmentPreview = function (sDownload, sCustomSpecSuffix)
|
||||
{
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/View/' + this.subQueryPrefix() + '/' + sDownload;
|
||||
sCustomSpecSuffix = Utils.isUnd(sCustomSpecSuffix) ? this.sSpecSuffix : sCustomSpecSuffix;
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + sCustomSpecSuffix + '/View/' +
|
||||
this.subQueryPrefix() + '/' + sDownload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} sDownload
|
||||
* @param {string=} sCustomSpecSuffix
|
||||
* @return {string}
|
||||
*/
|
||||
Links.prototype.attachmentThumbnailPreview = function (sDownload)
|
||||
Links.prototype.attachmentThumbnailPreview = function (sDownload, sCustomSpecSuffix)
|
||||
{
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ViewThumbnail/' + this.subQueryPrefix() + '/' + sDownload;
|
||||
sCustomSpecSuffix = Utils.isUnd(sCustomSpecSuffix) ? this.sSpecSuffix : sCustomSpecSuffix;
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + sCustomSpecSuffix + '/ViewThumbnail/' +
|
||||
this.subQueryPrefix() + '/' + sDownload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} sDownload
|
||||
* @param {string=} sCustomSpecSuffix
|
||||
* @return {string}
|
||||
*/
|
||||
Links.prototype.attachmentPreviewAsPlain = function (sDownload)
|
||||
Links.prototype.attachmentPreviewAsPlain = function (sDownload, sCustomSpecSuffix)
|
||||
{
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/ViewAsPlain/' + this.subQueryPrefix() + '/' + sDownload;
|
||||
sCustomSpecSuffix = Utils.isUnd(sCustomSpecSuffix) ? this.sSpecSuffix : sCustomSpecSuffix;
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + sCustomSpecSuffix + '/ViewAsPlain/' +
|
||||
this.subQueryPrefix() + '/' + sDownload;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} sDownload
|
||||
* @param {string=} sCustomSpecSuffix
|
||||
* @return {string}
|
||||
*/
|
||||
Links.prototype.attachmentFramed = function (sDownload)
|
||||
Links.prototype.attachmentFramed = function (sDownload, sCustomSpecSuffix)
|
||||
{
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + this.sSpecSuffix + '/FramedView/' + this.subQueryPrefix() + '/' + sDownload;
|
||||
sCustomSpecSuffix = Utils.isUnd(sCustomSpecSuffix) ? this.sSpecSuffix : sCustomSpecSuffix;
|
||||
return this.sServer + '/Raw/' + this.subQueryPrefix() + '/' + sCustomSpecSuffix + '/FramedView/' +
|
||||
this.subQueryPrefix() + '/' + sDownload;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@
|
|||
UserAjaxUserPromises.prototype.attachmentsActions = function (sAction, aHashes, fTrigger)
|
||||
{
|
||||
return this.postRequest('AttachmentsActions', fTrigger, {
|
||||
'Action': sAction,
|
||||
'Do': sAction,
|
||||
'Hashes': aHashes
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
Enums = require('Common/Enums'),
|
||||
Globals = require('Common/Globals'),
|
||||
Utils = require('Common/Utils'),
|
||||
|
||||
Settings = require('Storage/Settings'),
|
||||
|
||||
|
|
@ -52,6 +53,8 @@
|
|||
|
||||
this.contactsIsAllowed = ko.observable(false);
|
||||
|
||||
this.attahcmentsActions = ko.observableArray([]);
|
||||
|
||||
this.devEmail = '';
|
||||
this.devPassword = '';
|
||||
}
|
||||
|
|
@ -67,6 +70,9 @@
|
|||
|
||||
this.contactsIsAllowed(!!Settings.settingsGet('ContactsIsAllowed'));
|
||||
|
||||
var mAttahcmentsActions = Settings.settingsGet('AttahcmentsActions');
|
||||
this.attahcmentsActions(Utils.isNonEmptyArray(mAttahcmentsActions) ? mAttahcmentsActions : []);
|
||||
|
||||
this.devEmail = Settings.settingsGet('DevEmail');
|
||||
this.devPassword = Settings.settingsGet('DevPassword');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -263,6 +263,14 @@ html.rl-no-preview-pane {
|
|||
}
|
||||
}
|
||||
|
||||
&.unselectedAttachmentsError {
|
||||
.attachmentItem {
|
||||
box-shadow: 0 1px 4px red;
|
||||
box-shadow: 0 1px 5px rgba(255, 0, 0, 0.4);
|
||||
box-shadow: 0 0 0 1px rgba(255, 0, 0, 0.2), 0 1px 5px rgba(255, 0, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.controls-handle {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
|
|
|
|||
|
|
@ -1440,7 +1440,7 @@
|
|||
{
|
||||
oScript = window.document.createElement('script');
|
||||
oScript.type = 'text/javascript';
|
||||
oScript.src = 'https://www.dropbox.com/static/api/1/dropins.js';
|
||||
oScript.src = 'https://www.dropbox.com/static/api/2/dropins.js';
|
||||
$(oScript).attr('id', 'dropboxjs').attr('data-app-key', self.dropboxApiKey());
|
||||
|
||||
window.document.body.appendChild(oScript);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
'use strict';
|
||||
|
||||
var
|
||||
window = require('window'),
|
||||
_ = require('_'),
|
||||
$ = require('$'),
|
||||
ko = require('ko'),
|
||||
|
|
@ -19,9 +20,11 @@
|
|||
Events = require('Common/Events'),
|
||||
Translator = require('Common/Translator'),
|
||||
Audio = require('Common/Audio'),
|
||||
Links = require('Common/Links'),
|
||||
|
||||
Cache = require('Common/Cache'),
|
||||
|
||||
SocialStore = require('Stores/Social'),
|
||||
AppStore = require('Stores/User/App'),
|
||||
SettingsStore = require('Stores/User/Settings'),
|
||||
AccountStore = require('Stores/User/Account'),
|
||||
|
|
@ -62,6 +65,8 @@
|
|||
|
||||
this.pswp = null;
|
||||
|
||||
this.attahcmentsActions = AppStore.attahcmentsActions;
|
||||
|
||||
this.message = MessageStore.message;
|
||||
this.messageListChecked = MessageStore.messageListChecked;
|
||||
this.hasCheckedMessages = MessageStore.hasCheckedMessages;
|
||||
|
|
@ -80,12 +85,64 @@
|
|||
|
||||
this.messageListOfThreadsLoading = ko.observable(false).extend({'rateLimit': 1});
|
||||
|
||||
this.allowAttachmnetControls = ko.observable(false);
|
||||
this.highlightUnselectedAttachments = ko.observable(false).extend({'falseTimeout': 2000});
|
||||
|
||||
this.showAttachmnetControls = ko.observable(false);
|
||||
|
||||
this.allowAttachmnetControls = ko.computed(function () {
|
||||
return 0 < this.attahcmentsActions().length;
|
||||
}, this);
|
||||
|
||||
this.downloadAsZipAllowed = ko.computed(function () {
|
||||
return -1 < Utils.inArray('zip', this.attahcmentsActions());
|
||||
}, this);
|
||||
|
||||
this.downloadAsZipLoading = ko.observable(false);
|
||||
this.downloadAsZipError = ko.observable(false).extend({'falseTimeout': 7000});
|
||||
|
||||
this.saveToOwnCloudAllowed = ko.computed(function () {
|
||||
return -1 < Utils.inArray('owncloud', this.attahcmentsActions());
|
||||
}, this);
|
||||
|
||||
this.saveToOwnCloudLoading = ko.observable(false);
|
||||
this.saveToOwnCloudSuccess = ko.observable(false).extend({'falseTimeout': 2000});
|
||||
this.saveToOwnCloudError = ko.observable(false).extend({'falseTimeout': 7000});
|
||||
|
||||
this.saveToOwnCloudSuccess.subscribe(function (bV) {
|
||||
if (bV)
|
||||
{
|
||||
this.saveToOwnCloudError(false);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.saveToOwnCloudError.subscribe(function (bV) {
|
||||
if (bV)
|
||||
{
|
||||
this.saveToOwnCloudSuccess(false);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.saveToDropboxAllowed = ko.computed(function () {
|
||||
return -1 < Utils.inArray('dropbox', this.attahcmentsActions());
|
||||
}, this);
|
||||
|
||||
this.saveToDropboxLoading = ko.observable(false);
|
||||
this.saveToDropboxSuccess = ko.observable(false).extend({'falseTimeout': 2000});
|
||||
this.saveToDropboxError = ko.observable(false).extend({'falseTimeout': 7000});
|
||||
|
||||
this.saveToDropboxSuccess.subscribe(function (bV) {
|
||||
if (bV)
|
||||
{
|
||||
this.saveToDropboxError(false);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.saveToDropboxError.subscribe(function (bV) {
|
||||
if (bV)
|
||||
{
|
||||
this.saveToDropboxSuccess(false);
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.showAttachmnetControls.subscribe(function (bV) {
|
||||
if (this.message())
|
||||
|
|
@ -203,6 +260,9 @@
|
|||
}
|
||||
}, this.messageVisibility);
|
||||
|
||||
this.dropboxEnabled = SocialStore.dropbox.enabled;
|
||||
this.dropboxApiKey = SocialStore.dropbox.apiKey;
|
||||
|
||||
// viewer
|
||||
|
||||
this.viewBodyTopValue = ko.observable(0);
|
||||
|
|
@ -475,6 +535,7 @@
|
|||
{
|
||||
var
|
||||
self = this,
|
||||
oScript = null,
|
||||
sErrorMessage = Translator.i18n('PREVIEW_POPUP/IMAGE_ERROR'),
|
||||
fCheckHeaderHeight = _.bind(this.checkHeaderHeight, this)
|
||||
;
|
||||
|
|
@ -503,6 +564,16 @@
|
|||
Utils.windowResize(250);
|
||||
});
|
||||
|
||||
if (this.dropboxEnabled() && this.dropboxApiKey() && !window.Dropbox)
|
||||
{
|
||||
oScript = window.document.createElement('script');
|
||||
oScript.type = 'text/javascript';
|
||||
oScript.src = 'https://www.dropbox.com/static/api/2/dropins.js';
|
||||
$(oScript).attr('id', 'dropboxjs').attr('data-app-key', self.dropboxApiKey());
|
||||
|
||||
window.document.body.appendChild(oScript);
|
||||
}
|
||||
|
||||
this.oHeaderDom = $('.messageItemHeader', oDom);
|
||||
this.oHeaderDom = this.oHeaderDom[0] ? this.oHeaderDom : null;
|
||||
|
||||
|
|
@ -943,28 +1014,109 @@
|
|||
|
||||
MessageViewMailBoxUserView.prototype.downloadAsZip = function ()
|
||||
{
|
||||
var aHashes = this.getAttachmentsHashes();
|
||||
var self = this, aHashes = this.getAttachmentsHashes();
|
||||
if (0 < aHashes.length)
|
||||
{
|
||||
Promises.attachmentsActions('Zip', aHashes, this.downloadAsZipLoading);
|
||||
Promises.attachmentsActions('Zip', aHashes, this.downloadAsZipLoading).then(function (oResult) {
|
||||
if (oResult && oResult.Result && oResult.Result.Files &&
|
||||
oResult.Result.Files[0] && oResult.Result.Files[0].Hash)
|
||||
{
|
||||
require('App/User').download(
|
||||
Links.attachmentDownload(oResult.Result.Files[0].Hash));
|
||||
}
|
||||
else
|
||||
{
|
||||
self.downloadAsZipError(true);
|
||||
}
|
||||
}).fail(function () {
|
||||
self.downloadAsZipError(true);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.highlightUnselectedAttachments(true);
|
||||
}
|
||||
};
|
||||
|
||||
MessageViewMailBoxUserView.prototype.saveToOwnCloud = function ()
|
||||
{
|
||||
var aHashes = this.getAttachmentsHashes();
|
||||
var self = this, aHashes = this.getAttachmentsHashes();
|
||||
if (0 < aHashes.length)
|
||||
{
|
||||
Promises.attachmentsActions('OwnCloud', aHashes, this.saveToOwnCloudLoading);
|
||||
Promises.attachmentsActions('OwnCloud', aHashes, this.saveToOwnCloudLoading).then(function (oResult) {
|
||||
if (oResult && oResult.Result)
|
||||
{
|
||||
self.saveToOwnCloudSuccess(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.saveToOwnCloudError(true);
|
||||
}
|
||||
}).fail(function () {
|
||||
self.saveToOwnCloudError(true);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.highlightUnselectedAttachments(true);
|
||||
}
|
||||
};
|
||||
|
||||
MessageViewMailBoxUserView.prototype.saveToDropbox = function ()
|
||||
{
|
||||
var aHashes = this.getAttachmentsHashes();
|
||||
var self = this, aFiles = [], aHashes = this.getAttachmentsHashes();
|
||||
if (0 < aHashes.length)
|
||||
{
|
||||
Promises.attachmentsActions('Dropbox', aHashes, this.saveToDropboxLoading);
|
||||
if (window.Dropbox)
|
||||
{
|
||||
Promises.attachmentsActions('Dropbox', aHashes, this.saveToDropboxLoading).then(function (oResult) {
|
||||
if (oResult && oResult.Result && oResult.Result.Url && oResult.Result.ShortLife && oResult.Result.Files)
|
||||
{
|
||||
if (window.Dropbox && Utils.isArray(oResult.Result.Files))
|
||||
{
|
||||
_.each(oResult.Result.Files, function (oItem) {
|
||||
aFiles.push({
|
||||
'url': oResult.Result.Url +
|
||||
Links.attachmentDownload(oItem.Hash, oResult.Result.ShortLife),
|
||||
'filename': oItem.FileName
|
||||
});
|
||||
});
|
||||
|
||||
window.Dropbox.save({
|
||||
'files': aFiles,
|
||||
'progress': function () {
|
||||
self.saveToDropboxLoading(true);
|
||||
self.saveToDropboxError(false);
|
||||
self.saveToDropboxSuccess(false);
|
||||
},
|
||||
'cancel': function () {
|
||||
self.saveToDropboxSuccess(false);
|
||||
self.saveToDropboxError(false);
|
||||
self.saveToDropboxLoading(false);
|
||||
},
|
||||
'success': function () {
|
||||
self.saveToDropboxSuccess(true);
|
||||
self.saveToDropboxLoading(false);
|
||||
},
|
||||
'error': function () {
|
||||
self.saveToDropboxError(true);
|
||||
self.saveToDropboxLoading(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
self.saveToDropboxError(true);
|
||||
}
|
||||
}
|
||||
}).fail(function () {
|
||||
self.saveToDropboxError(true);
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.highlightUnselectedAttachments(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "RainLoop",
|
||||
"title": "RainLoop Webmail",
|
||||
"version": "1.8.3",
|
||||
"release": "305",
|
||||
"version": "1.8.4",
|
||||
"release": "311",
|
||||
"description": "Simple, modern & fast web-based email client",
|
||||
"homepage": "http://rainloop.net",
|
||||
"main": "gulpfile.js",
|
||||
|
|
|
|||
|
|
@ -34,4 +34,5 @@ class Charset
|
|||
const ISO_8859_8 = 'iso-8859-8';
|
||||
const ISO_8859_8_I = 'iso-8859-8-i';
|
||||
const ISO_2022_JP = 'iso-2022-jp';
|
||||
const CP858 = 'cp858';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -567,6 +567,12 @@ class Http
|
|||
return false;
|
||||
}
|
||||
|
||||
$sUrl = \trim($sUrl);
|
||||
if ('//' === substr($sUrl, 0, 2))
|
||||
{
|
||||
$sUrl = 'http:'.$sUrl;
|
||||
}
|
||||
|
||||
$aOptions = array(
|
||||
CURLOPT_URL => $sUrl,
|
||||
CURLOPT_HEADER => false,
|
||||
|
|
|
|||
|
|
@ -235,6 +235,56 @@ END;
|
|||
return $sCharset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sFilePath
|
||||
* @param function $fFileExistsCallback = null
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function SmartFileExists($sFilePath, $fFileExistsCallback = null)
|
||||
{
|
||||
$sFilePath = \str_replace('\\', '/', \trim($sFilePath));
|
||||
if (!$fFileExistsCallback)
|
||||
{
|
||||
$fFileExistsCallback = function ($sPath) {
|
||||
return \file_exists($sPath);
|
||||
};
|
||||
}
|
||||
|
||||
if (!\call_user_func($fFileExistsCallback, $sFilePath))
|
||||
{
|
||||
return $sFilePath;
|
||||
}
|
||||
|
||||
$aFileInfo = \pathinfo($sFilePath);
|
||||
|
||||
$iIndex = 0;
|
||||
|
||||
do
|
||||
{
|
||||
$iIndex++;
|
||||
|
||||
$sFilePathNew = $aFileInfo['dirname'].'/'.
|
||||
\preg_replace('/\(\d{1,2}\)$/', '', $aFileInfo['filename']).
|
||||
' ('.$iIndex.')'.
|
||||
(empty($aFileInfo['extension']) ? '' : '.'.$aFileInfo['extension'])
|
||||
;
|
||||
|
||||
if (!\call_user_func($fFileExistsCallback, $sFilePathNew))
|
||||
{
|
||||
$sFilePath = $sFilePathNew;
|
||||
break;
|
||||
}
|
||||
else if (10 < $iIndex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
|
||||
return $sFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1322,12 +1322,34 @@ class Actions
|
|||
'AllowAppendMessage' => (bool) $oConfig->Get('labs', 'allow_message_append', false),
|
||||
'MaterialDesign' => (bool) $oConfig->Get('labs', 'use_material_design', true),
|
||||
'PremType' => $this->PremType(),
|
||||
'ZipSupported' => !!\class_exists('ZipArchive'),
|
||||
'Admin' => array(),
|
||||
'Capa' => array(),
|
||||
'AttahcmentsActions' => array(),
|
||||
'Plugins' => array()
|
||||
);
|
||||
|
||||
if ($oConfig->Get('capa', 'attachments_actions', false))
|
||||
{
|
||||
if (!!\class_exists('ZipArchive'))
|
||||
{
|
||||
$aResult['AttahcmentsActions'][] = 'zip';
|
||||
}
|
||||
|
||||
if (\RainLoop\Utils::IsOwnCloudLoggedIn() && \class_exists('\\OCP\\Files'))
|
||||
{
|
||||
$aResult['AttahcmentsActions'][] = 'owncloud';
|
||||
}
|
||||
|
||||
if ($oConfig->Get('social', 'dropbox_enable', false) && 0 < \strlen(\trim($oConfig->Get('social', 'dropbox_api_key', ''))))
|
||||
{
|
||||
$aResult['AttahcmentsActions'][] = 'dropbox';
|
||||
}
|
||||
}
|
||||
|
||||
$aResult['AllowDropboxSocial'] = (bool) $oConfig->Get('social', 'dropbox_enable', false);
|
||||
$aResult['DropboxApiKey'] = \trim($oConfig->Get('social', 'dropbox_api_key', ''));
|
||||
|
||||
|
||||
if ($aResult['UseRsaEncryption'] &&
|
||||
\file_exists(APP_PRIVATE_DATA.'rsa/public') && \file_exists(APP_PRIVATE_DATA.'rsa/private'))
|
||||
{
|
||||
|
|
@ -1763,14 +1785,30 @@ class Actions
|
|||
return \preg_replace('/[^a-zA-Z0-9]+/', '-', $this->getUserLanguageFromHeader());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $iWait = 1
|
||||
* @param int $iDelay = 1
|
||||
*/
|
||||
private function requestSleep($iWait = 1, $iDelay = 1)
|
||||
{
|
||||
if (0 < $iDelay && 0 < $iWait)
|
||||
{
|
||||
if ($iWait > \time() - APP_START_TIME)
|
||||
{
|
||||
\sleep($iDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function loginErrorDelay()
|
||||
{
|
||||
$iDelay = (int) $this->Config()->Get('labs', 'login_fault_delay', 0);
|
||||
if (0 < $iDelay)
|
||||
{
|
||||
\sleep($iDelay);
|
||||
$this->requestSleep(1, $iDelay);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
*/
|
||||
|
|
@ -2645,8 +2683,200 @@ class Actions
|
|||
*/
|
||||
public function DoAttachmentsActions()
|
||||
{
|
||||
\sleep(1);
|
||||
return $this->TrueResponse(__FUNCTION__);
|
||||
if (!$this->Config()->Get('capa', 'attachments_actions', false))
|
||||
{
|
||||
return $this->FalseResponse(__FUNCTION__);
|
||||
}
|
||||
|
||||
$oAccount = $this->initMailClientConnection();
|
||||
|
||||
$sAction = $this->GetActionParam('Do', '');
|
||||
$aHashes = $this->GetActionParam('Hashes', null);
|
||||
|
||||
$mResult = false;
|
||||
$bError = false;
|
||||
$aData = false;
|
||||
|
||||
if (\is_array($aHashes) && 0 < \count($aHashes))
|
||||
{
|
||||
$aData = array();
|
||||
foreach ($aHashes as $sZipHash)
|
||||
{
|
||||
$aResult = $this->getMimeFileByHash($oAccount, $sZipHash);
|
||||
if (\is_array($aResult) && !empty($aResult['FileHash']))
|
||||
{
|
||||
$aData[] = $aResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
$bError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oFilesProvider = $this->FilesProvider();
|
||||
if (!empty($sAction) && !$bError && \is_array($aData) && 0 < \count($aData) &&
|
||||
$oFilesProvider && $oFilesProvider->IsActive())
|
||||
{
|
||||
|
||||
$bError = false;
|
||||
switch (\strtolower($sAction))
|
||||
{
|
||||
case 'zip':
|
||||
|
||||
if (\class_exists('ZipArchive'))
|
||||
{
|
||||
$sZipHash = \MailSo\Base\Utils::Md5Rand();
|
||||
$sZipFileName = $oFilesProvider->GenerateLocalFullFileName($oAccount, $sZipHash);
|
||||
|
||||
if (!empty($sZipFileName))
|
||||
{
|
||||
$oZip = new \ZipArchive();
|
||||
$oZip->open($sZipFileName, \ZIPARCHIVE::OVERWRITE);
|
||||
$oZip->setArchiveComment('RainLoop/'.APP_VERSION);
|
||||
|
||||
foreach ($aData as $aItem)
|
||||
{
|
||||
$sFileName = (string) (isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat');
|
||||
$sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
|
||||
|
||||
if (!empty($sFileHash))
|
||||
{
|
||||
$sFullFileNameHash = $oFilesProvider->GetFileName($oAccount, $sFileHash);
|
||||
if (!$oZip->addFile($sFullFileNameHash, $sFileName))
|
||||
{
|
||||
$bError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bError)
|
||||
{
|
||||
$bError = !$oZip->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oZip->close();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aData as $aItem)
|
||||
{
|
||||
$sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
|
||||
if (!empty($sFileHash))
|
||||
{
|
||||
$oFilesProvider->Clear($oAccount, $sFileHash);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bError)
|
||||
{
|
||||
$mResult = array(
|
||||
'Files' => array(array(
|
||||
'FileName' => 'attachments.zip',
|
||||
'Hash' => \RainLoop\Utils::EncodeKeyValues(array(
|
||||
'V' => APP_VERSION,
|
||||
'Account' => $oAccount ? \md5($oAccount->Hash()) : '',
|
||||
'FileName' => 'attachments.zip',
|
||||
'MimeType' => 'application/zip',
|
||||
'FileHash' => $sZipHash
|
||||
))
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'owncloud':
|
||||
|
||||
$mResult = false;
|
||||
|
||||
if (\RainLoop\Utils::IsOwnCloudLoggedIn() && \class_exists('\\OCP\\Files'))
|
||||
{
|
||||
$sSaveFolder = $this->Config()->Get('labs', 'owncloud_save_folder', '');
|
||||
if (!empty($sSaveFolder))
|
||||
{
|
||||
$sSaveFolder = 'Attachments';
|
||||
}
|
||||
|
||||
$oFiles = \OCP\Files::getStorage('files');
|
||||
|
||||
if ($oFilesProvider && $oFiles && $oFilesProvider->IsActive() &&
|
||||
\method_exists($oFiles, 'file_put_contents'))
|
||||
{
|
||||
if (!$oFiles->is_dir($sSaveFolder))
|
||||
{
|
||||
$oFiles->mkdir($sSaveFolder);
|
||||
}
|
||||
|
||||
$mResult = true;
|
||||
foreach ($aData as $aItem)
|
||||
{
|
||||
$sSavedFileName = isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat';
|
||||
$sSavedFileHash = !empty($aItem['FileHash']) ? $aItem['FileHash'] : '';
|
||||
|
||||
if (!empty($sSavedFileHash))
|
||||
{
|
||||
$fFile = $oFilesProvider->GetFile($oAccount, $sSavedFileHash, 'rb');
|
||||
if (\is_resource($fFile))
|
||||
{
|
||||
$sSavedFileNameFull = \MailSo\Base\Utils::SmartFileExists($sSaveFolder.'/'.$sSavedFileName, function ($sPath) use ($oFiles) {
|
||||
return $oFiles->file_exists($sPath);
|
||||
});
|
||||
|
||||
if (!$oFiles->file_put_contents($sSavedFileNameFull, $fFile))
|
||||
{
|
||||
$mResult = false;
|
||||
}
|
||||
|
||||
if (\is_resource($fFile))
|
||||
{
|
||||
@\fclose($fFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($aData as $aItem)
|
||||
{
|
||||
$sFileHash = (string) (isset($aItem['FileHash']) ? $aItem['FileHash'] : '');
|
||||
if (!empty($sFileHash))
|
||||
{
|
||||
$oFilesProvider->Clear($oAccount, $sFileHash);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'dropbox':
|
||||
|
||||
$mResult = array(
|
||||
'ShortLife' => '_'.$this->GetShortLifeSpecAuthToken(),
|
||||
'Url' => \preg_replace('/\?(.*)$/', '', $this->Http()->GetFullUrl()),
|
||||
'Files' => array()
|
||||
);
|
||||
|
||||
foreach ($aData as $aItem)
|
||||
{
|
||||
$mResult['Files'][] = array(
|
||||
'FileName' => isset($aItem['FileName']) ? $aItem['FileName'] : 'file.dat',
|
||||
'Hash' => \RainLoop\Utils::EncodeKeyValues($aItem)
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$bError = true;
|
||||
}
|
||||
|
||||
$this->requestSleep();
|
||||
return $this->DefaultResponse(__FUNCTION__, $bError ? false : $mResult);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3550,7 +3780,6 @@ class Actions
|
|||
*/
|
||||
public function DoAdminLicensing()
|
||||
{
|
||||
$iStart = \time();
|
||||
$this->IsAdminLoggined();
|
||||
|
||||
$bForce = '1' === (string) $this->GetActionParam('Force', '0');
|
||||
|
|
@ -3562,10 +3791,7 @@ class Actions
|
|||
{
|
||||
$sValue = $this->licenseHelper($bForce);
|
||||
|
||||
if ($iStart === \time())
|
||||
{
|
||||
\sleep(1);
|
||||
}
|
||||
$this->requestSleep();
|
||||
|
||||
$iExpired = 0;
|
||||
if ($this->licenseParser($sValue, $iExpired))
|
||||
|
|
@ -3602,7 +3828,6 @@ class Actions
|
|||
*/
|
||||
public function DoAdminLicensingActivate()
|
||||
{
|
||||
$iStart = \time();
|
||||
$this->IsAdminLoggined();
|
||||
|
||||
$sDomain = (string) $this->GetActionParam('Domain', '');
|
||||
|
|
@ -3618,7 +3843,6 @@ class Actions
|
|||
|
||||
$oHttp = \MailSo\Base\Http::SingletonInstance();
|
||||
|
||||
\sleep(1);
|
||||
$sValue = $oHttp->GetUrlAsString(APP_API_PATH.'activate/'.\urlencode($sDomain).'/'.\urlencode($sKey),
|
||||
'RainLoop/'.APP_VERSION, $sContentType, $iCode, $this->Logger(), 10,
|
||||
$this->Config()->Get('labs', 'curl_proxy', ''), $this->Config()->Get('labs', 'curl_proxy_auth', ''),
|
||||
|
|
@ -3630,10 +3854,7 @@ class Actions
|
|||
$sValue = '';
|
||||
}
|
||||
|
||||
if ($iStart + 2 > \time())
|
||||
{
|
||||
\sleep(1);
|
||||
}
|
||||
$this->requestSleep();
|
||||
|
||||
$aMatch = array();
|
||||
if ('OK' === $sValue)
|
||||
|
|
@ -6522,7 +6743,8 @@ class Actions
|
|||
))
|
||||
);
|
||||
|
||||
\sleep(1);
|
||||
$this->requestSleep();
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__,
|
||||
$this->getTwoFactorInfo($oAccount));
|
||||
}
|
||||
|
|
@ -6606,7 +6828,8 @@ class Actions
|
|||
// $this->TwoFactorAuthProvider()->VerifyCode($sSecret, $sCode)
|
||||
// ));
|
||||
|
||||
\sleep(1);
|
||||
$this->requestSleep();
|
||||
|
||||
return $this->DefaultResponse(__FUNCTION__,
|
||||
$this->TwoFactorAuthProvider()->VerifyCode($sSecret, $sCode));
|
||||
}
|
||||
|
|
@ -7901,6 +8124,57 @@ class Actions
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sHash
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getMimeFileByHash($oAccount, $sHash)
|
||||
{
|
||||
$aValues = $this->getDecodedRawKeyValue($sHash);
|
||||
|
||||
$sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
|
||||
$iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
|
||||
$sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
|
||||
|
||||
$sContentTypeIn = (string) isset($aValues['MimeType']) ? $aValues['MimeType'] : '';
|
||||
$sFileNameIn = (string) isset($aValues['FileName']) ? $aValues['FileName'] : '';
|
||||
|
||||
$oFileProvider = $this->FilesProvider();
|
||||
|
||||
$sResultHash = '';
|
||||
|
||||
$mResult = $this->MailClient()->MessageMimeStream(function($rResource, $sContentType, $sFileName, $sMimeIndex = '')
|
||||
use ($oAccount, $oFileProvider, $sFileNameIn, $sContentTypeIn, &$sResultHash) {
|
||||
|
||||
if ($oAccount && \is_resource($rResource))
|
||||
{
|
||||
$sHash = \MailSo\Base\Utils::Md5Rand($sFileNameIn.'~'.$sContentTypeIn);
|
||||
$rTempResource = $oFileProvider->GetFile($oAccount, $sHash, 'wb+');
|
||||
|
||||
if (@\is_resource($rTempResource))
|
||||
{
|
||||
if (false !== \MailSo\Base\Utils::MultipleStreamWriter($rResource, array($rTempResource)))
|
||||
{
|
||||
$sResultHash = $sHash;
|
||||
}
|
||||
|
||||
@\fclose($rTempResource);
|
||||
}
|
||||
}
|
||||
|
||||
}, $sFolder, $iUid, true, $sMimeIndex);
|
||||
|
||||
$aValues['FileHash'] = '';
|
||||
if ($mResult)
|
||||
{
|
||||
$aValues['FileHash'] = $sResultHash;
|
||||
}
|
||||
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $bDownload
|
||||
* @param bool $bThumbnail = false
|
||||
|
|
@ -7913,15 +8187,50 @@ class Actions
|
|||
$aValues = $this->getDecodedRawKeyValue($sRawKey);
|
||||
|
||||
$sFolder = isset($aValues['Folder']) ? $aValues['Folder'] : '';
|
||||
$iUid = (int) isset($aValues['Uid']) ? $aValues['Uid'] : 0;
|
||||
$sMimeIndex = (string) isset($aValues['MimeIndex']) ? $aValues['MimeIndex'] : '';
|
||||
$iUid = isset($aValues['Uid']) ? (int) $aValues['Uid'] : 0;
|
||||
$sMimeIndex = isset($aValues['MimeIndex']) ? (string) $aValues['MimeIndex'] : '';
|
||||
|
||||
$sContentTypeIn = (string) isset($aValues['MimeType']) ? $aValues['MimeType'] : '';
|
||||
$sFileNameIn = (string) isset($aValues['FileName']) ? $aValues['FileName'] : '';
|
||||
$sContentTypeIn = isset($aValues['MimeType']) ? (string) $aValues['MimeType'] : '';
|
||||
$sFileNameIn = isset($aValues['FileName']) ? (string) $aValues['FileName'] : '';
|
||||
$sFileHashIn = isset($aValues['FileHash']) ? (string) $aValues['FileHash'] : '';
|
||||
|
||||
if (!empty($sFolder) && 0 < $iUid)
|
||||
if (!empty($sFileHashIn))
|
||||
{
|
||||
$this->verifyCacheByKey($sRawKey);
|
||||
|
||||
$oAccount = $this->getAccountFromToken();
|
||||
|
||||
$sContentTypeOut = empty($sContentTypeIn) ?
|
||||
\MailSo\Base\Utils::MimeContentType($sFileNameIn) : $sContentTypeIn;
|
||||
|
||||
$sFileNameOut = $this->MainClearFileName($sFileNameIn, $sContentTypeIn, $sMimeIndex);
|
||||
|
||||
$rResource = $this->FilesProvider()->GetFile($oAccount, $sFileHashIn);
|
||||
if (\is_resource($rResource))
|
||||
{
|
||||
$sFileNameOut = \MailSo\Base\Utils::ConvertEncoding(
|
||||
$sFileNameOut, \MailSo\Base\Enumerations\Charset::UTF_8,
|
||||
\MailSo\Base\Enumerations\Charset::CP858);
|
||||
|
||||
\header('Content-Type: '.$sContentTypeOut);
|
||||
\header('Content-Disposition: attachment; '.
|
||||
\trim(\MailSo\Base\Utils::EncodeHeaderUtf8AttributeValue('filename', $sFileNameOut)), true);
|
||||
|
||||
\header('Accept-Ranges: none', true);
|
||||
\header('Content-Transfer-Encoding: binary');
|
||||
|
||||
\MailSo\Base\Utils::FpassthruWithTimeLimitReset($rResource);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!empty($sFolder) && 0 < $iUid)
|
||||
{
|
||||
$this->verifyCacheByKey($sRawKey);
|
||||
}
|
||||
}
|
||||
|
||||
$oAccount = $this->initMailClientConnection();
|
||||
|
|
|
|||
|
|
@ -133,7 +133,8 @@ class Application extends \RainLoop\Config\AbstractConfig
|
|||
|
||||
'capa' => array(
|
||||
'filters' => array(true),
|
||||
'templates' => array(true)
|
||||
'templates' => array(true),
|
||||
'attachments_actions' => array(true)
|
||||
),
|
||||
|
||||
'login' => array(
|
||||
|
|
@ -302,6 +303,7 @@ Enables caching in the system'),
|
|||
'smtp_show_server_errors' => array(false),
|
||||
'sieve_allow_raw_script' => array(false),
|
||||
'sieve_utf8_folder_name' => array(true),
|
||||
'owncloud_save_folder' => array('Attachments'),
|
||||
'curl_proxy' => array(''),
|
||||
'curl_proxy_auth' => array(''),
|
||||
'in_iframe' => array(false),
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ class Account extends \RainLoop\Account // for backward compatibility
|
|||
\RainLoop\Utils::GetShortToken(), // 7
|
||||
$this->sProxyAuthUser, // 8
|
||||
$this->sProxyAuthPassword, // 9
|
||||
0 // 10
|
||||
0 // 10 // timelife
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -116,6 +116,17 @@ class Files extends \RainLoop\Providers\AbstractProvider
|
|||
$this->oDriver->CloseAllOpenedFiles() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GenerateLocalFullFileName($oAccount, $sKey)
|
||||
{
|
||||
return $this->oDriver ? $this->oDriver->GenerateLocalFullFileName($oAccount, $sKey) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -25,6 +25,17 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
$this->sDataPath = \rtrim(\trim($sStoragePath), '\\/');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GenerateLocalFullFileName($oAccount, $sKey)
|
||||
{
|
||||
return $this->generateFullFileName($oAccount, $sKey, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sKey
|
||||
|
|
@ -37,7 +48,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
$bResult = false;
|
||||
if ($rSource)
|
||||
{
|
||||
$rOpenOutput = @\fopen($this->generateFileName($oAccount, $sKey, true), 'w+b');
|
||||
$rOpenOutput = @\fopen($this->generateFullFileName($oAccount, $sKey, true), 'w+b');
|
||||
if ($rOpenOutput)
|
||||
{
|
||||
$bResult = (false !== \MailSo\Base\Utils::MultipleStreamWriter($rSource, array($rOpenOutput)));
|
||||
|
|
@ -57,7 +68,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
public function MoveUploadedFile($oAccount, $sKey, $sSource)
|
||||
{
|
||||
return @\move_uploaded_file($sSource,
|
||||
$this->generateFileName($oAccount, $sKey, true));
|
||||
$this->generateFullFileName($oAccount, $sKey, true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -72,7 +83,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
$mResult = false;
|
||||
$bCreate = !!\preg_match('/[wac]/', $sOpenMode);
|
||||
|
||||
$sFileName = $this->generateFileName($oAccount, $sKey, $bCreate);
|
||||
$sFileName = $this->generateFullFileName($oAccount, $sKey, $bCreate);
|
||||
if ($bCreate || \file_exists($sFileName))
|
||||
{
|
||||
$mResult = @\fopen($sFileName, $sOpenMode);
|
||||
|
|
@ -95,7 +106,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
public function GetFileName($oAccount, $sKey)
|
||||
{
|
||||
$mResult = false;
|
||||
$sFileName = $this->generateFileName($oAccount, $sKey);
|
||||
$sFileName = $this->generateFullFileName($oAccount, $sKey);
|
||||
if (\file_exists($sFileName))
|
||||
{
|
||||
$mResult = $sFileName;
|
||||
|
|
@ -113,7 +124,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
public function Clear($oAccount, $sKey)
|
||||
{
|
||||
$mResult = true;
|
||||
$sFileName = $this->generateFileName($oAccount, $sKey);
|
||||
$sFileName = $this->generateFullFileName($oAccount, $sKey);
|
||||
if (\file_exists($sFileName))
|
||||
{
|
||||
if (isset($this->aResources[$sFileName]) && \is_resource($this->aResources[$sFileName]))
|
||||
|
|
@ -136,7 +147,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
public function FileSize($oAccount, $sKey)
|
||||
{
|
||||
$mResult = false;
|
||||
$sFileName = $this->generateFileName($oAccount, $sKey);
|
||||
$sFileName = $this->generateFullFileName($oAccount, $sKey);
|
||||
if (\file_exists($sFileName))
|
||||
{
|
||||
$mResult = \filesize($sFileName);
|
||||
|
|
@ -153,7 +164,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
*/
|
||||
public function FileExists($oAccount, $sKey)
|
||||
{
|
||||
return @\file_exists($this->generateFileName($oAccount, $sKey));
|
||||
return @\file_exists($this->generateFullFileName($oAccount, $sKey));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -198,7 +209,7 @@ class FileStorage implements \RainLoop\Providers\Files\IFiles
|
|||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generateFileName($oAccount, $sKey, $bMkDir = false)
|
||||
private function generateFullFileName($oAccount, $sKey, $bMkDir = false)
|
||||
{
|
||||
$sEmail = $sSubEmail = '';
|
||||
if ($oAccount instanceof \RainLoop\Model\Account)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@ namespace RainLoop\Providers\Files;
|
|||
|
||||
interface IFiles
|
||||
{
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sKey
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GenerateLocalFullFileName($oAccount, $sKey);
|
||||
|
||||
/**
|
||||
* @param \RainLoop\Model\Account $oAccount
|
||||
* @param string $sKey
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@ class OwnCloudSuggestions implements \RainLoop\Providers\Suggestions\ISuggestion
|
|||
|
||||
try
|
||||
{
|
||||
if ('' === $sQuery || !$oAccount || !\RainLoop\Utils::IsOwnCloud() ||
|
||||
!\class_exists('\\OCP\\Contacts') || !\OCP\Contacts::isEnabled() ||
|
||||
!\class_exists('\\OCP\\User') || !\OCP\User::isLoggedIn()
|
||||
if ('' === $sQuery || !$oAccount || !\RainLoop\Utils::IsOwnCloudLoggedIn() ||
|
||||
!\class_exists('\\OCP\\Contacts') || !\OCP\Contacts::isEnabled()
|
||||
)
|
||||
{
|
||||
return $aResult;
|
||||
|
|
|
|||
|
|
@ -315,6 +315,13 @@ class Utils
|
|||
return isset($_ENV['RAINLOOP_OWNCLOUD']) && $_ENV['RAINLOOP_OWNCLOUD'] &&
|
||||
\class_exists('\\OC');
|
||||
}
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function IsOwnCloudLoggedIn()
|
||||
{
|
||||
return self::IsOwnCloud() && \class_exists('\\OCP\\User') && \OCP\User::isLoggedIn();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
|
|
|||
|
|
@ -319,7 +319,8 @@
|
|||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
style="margin-bottom: 0" data-i18n="[placeholder]MESSAGE/PGP_PASSWORD_INPUT_PLACEHOLDER" data-bind="value: viewPgpPassword, onEnter: function() { decryptPgpEncryptedMessage(message()); }" />
|
||||
</div>
|
||||
<div class="attachmentsPlace" data-bind="visible: message() && message().hasVisibleAttachments(), css: {'selection-mode' : showAttachmnetControls}">
|
||||
<div class="attachmentsPlace" data-bind="visible: message() && message().hasVisibleAttachments(),
|
||||
css: {'selection-mode' : showAttachmnetControls, 'unselectedAttachmentsError': highlightUnselectedAttachments}">
|
||||
<ul class="attachmentList" data-bind="foreach: message() ? message().attachments() : []">
|
||||
<li class="attachmentItem clearfix" draggable="true" data-tooltip-join="top"
|
||||
data-bind="visible: !isLinked, event: { 'dragstart': eventDragStart }, attr: { 'title': fileName }, css: {'checked': checked}">
|
||||
|
|
@ -371,27 +372,33 @@
|
|||
<div class="attachmentsControls"
|
||||
data-bind="visible: showAttachmnetControls() && message() && message().hasVisibleAttachments()">
|
||||
|
||||
<i class="icon-file-zip"
|
||||
data-bind="css: {'icon-file-zip': !downloadAsZipLoading(), 'icon-spinner animated': downloadAsZipLoading()}"></i>
|
||||
<span data-bind="visible: downloadAsZipAllowed">
|
||||
<i class="icon-remove iconcolor-red" data-bind="visible: downloadAsZipError"></i>
|
||||
<i class="icon-file-zip" data-bind="visible: !downloadAsZipError(),
|
||||
css: {'icon-file-zip': !downloadAsZipLoading(), 'icon-spinner animated': downloadAsZipLoading()}"></i>
|
||||
|
||||
<span class="g-ui-link" data-bind="click: downloadAsZip">Download as zip</span>
|
||||
</span>
|
||||
|
||||
|
||||
<span class="g-ui-link" data-bind="click: downloadAsZip">Download as zip</span>
|
||||
<span data-bind="visible: saveToOwnCloudAllowed">
|
||||
|
||||
<i class="icon-remove iconcolor-red" data-bind="visible: saveToOwnCloudError"></i>
|
||||
<i class="icon-ok iconcolor-green" data-bind="visible: saveToOwnCloudSuccess"></i>
|
||||
<i class="icon-cloud-up" data-bind="visible: !saveToOwnCloudSuccess() && !saveToOwnCloudError(),
|
||||
css: {'icon-cloud-up': !saveToOwnCloudLoading(), 'icon-spinner animated': saveToOwnCloudLoading()}"></i>
|
||||
|
||||
<span class="g-ui-link" data-bind="click: saveToOwnCloud">Save to ownCloud</span>
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
<i class="icon-cloud-up"
|
||||
data-bind="css: {'icon-cloud-up': !saveToOwnCloudLoading(), 'icon-spinner animated': saveToOwnCloudLoading()}"></i>
|
||||
|
||||
|
||||
<span class="g-ui-link" data-bind="click: saveToOwnCloud">Save to ownCloud</span>
|
||||
|
||||
|
||||
|
||||
<i class="icon-dropbox"
|
||||
data-bind="css: {'icon-dropbox': !saveToDropboxLoading(), 'icon-spinner animated': saveToDropboxLoading()}"></i>
|
||||
|
||||
|
||||
<span class="g-ui-link" data-bind="click: saveToDropbox">Save to Dropbox</span>
|
||||
<span data-bind="visible: saveToDropboxAllowed">
|
||||
|
||||
<i class="icon-remove iconcolor-red" data-bind="visible: saveToDropboxError"></i>
|
||||
<i class="icon-ok iconcolor-green" data-bind="visible: saveToDropboxSuccess"></i>
|
||||
<i class="icon-dropbox" data-bind="visible: !saveToDropboxSuccess() && !saveToDropboxError(),
|
||||
css: {'icon-dropbox': !saveToDropboxLoading(), 'icon-spinner animated': saveToDropboxLoading()}"></i>
|
||||
|
||||
<span class="g-ui-link" data-bind="click: saveToDropbox">Save to Dropbox</span>
|
||||
</span>
|
||||
|
||||
<!-- // --->
|
||||
<button type="button" class="close" style="margin-right: 5px;"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue