Many fixes

New ownCloud package with a built-in webmail
This commit is contained in:
RainLoop Team 2015-02-12 01:39:27 +04:00
parent 323dd34c8b
commit 6116597f6f
56 changed files with 1137 additions and 232 deletions

View file

@ -1,26 +1,23 @@
************************************************************************
*
* ownCloud - RainLoop Webmail mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*
************************************************************************
REQUIREMENTS:
- Installed and configured RainLoop Webmail (standalone)
- ownCloud version 6 or higher
- Both apps (RainLoop & ownCloud) running on the same domain
INSTALL:
- Unpack the RainLoop Webmail application package in the apps directory of your OwnCloud instance
CONFIGURATION:
- ownCloud:
1) In the Apps > Enable 'RainLoop' plugin
2) In the Settings > Admin > Enter "RainLoop Webmail URL" and "Absolute (full) path to RainLoop Webmail installation"
3) In the Settings > Personal > Type your mail server email (login) and password
************************************************************************
*
* ownCloud - RainLoop Webmail package
*
* @author RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*
************************************************************************
REQUIREMENTS:
- ownCloud version 6 or higher
INSTALL:
- Unpack the RainLoop Webmail application package in the apps directory of your OwnCloud instance
CONFIGURATION:
- ownCloud:
1) In the Apps > Enable 'RainLoop' plugin
2) In the Settings > Personal > Type your mail server email (login) and password

View file

@ -1,20 +1,32 @@
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\User::checkAdminUser();
OCP\Util::addScript('rainloop', 'admin');
$oTemplate = new OCP\Template('rainloop', 'admin');
$oTemplate->assign('rainloop-url', OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
$oTemplate->assign('rainloop-path', OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
$oTemplate->assign('rainloop-autologin', OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false));
return $oTemplate->fetchPage();
<?php
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
OCP\User::checkAdminUser();
OCP\Util::addScript('rainloop', 'admin');
$bInstalledLocaly = file_exists(__DIR__.'/app/index.php');
if ($bInstalledLocaly)
{
$oTemplate = new OCP\Template('rainloop', 'admin-local');
$oTemplate->assign('rainloop-admin-panel-link',
OC_RainLoop_Helper::getAppUrl().'?admin');
}
else
{
$oTemplate = new OCP\Template('rainloop', 'admin');
$oTemplate->assign('rainloop-admin-panel-link', '');
$oTemplate->assign('rainloop-url', OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
$oTemplate->assign('rainloop-path', OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
}
$oTemplate->assign('rainloop-autologin', OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false));
return $oTemplate->fetchPage();

View file

@ -4,7 +4,7 @@
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
@ -17,22 +17,32 @@ $sUrl = '';
$sPath = '';
$bAutologin = false;
if (isset($_POST['appname'], $_POST['rainloop-url'], $_POST['rainloop-path']) && 'rainloop' === $_POST['appname'])
$bInstalledLocaly = file_exists(__DIR__.'/../app/index.php');
if (isset($_POST['appname']) && 'rainloop' === $_POST['appname'] &&
($bInstalledLocaly ? true : isset($_POST['rainloop-url'], $_POST['rainloop-path'])))
{
OCP\Config::setAppValue('rainloop', 'rainloop-url', $_POST['rainloop-url']);
OCP\Config::setAppValue('rainloop', 'rainloop-path', $_POST['rainloop-path']);
OCP\Config::setAppValue('rainloop', 'rainloop-autologin', isset($_POST['rainloop-autologin']) ?
'1' === $_POST['rainloop-autologin'] : false);
$sUrl = OCP\Config::getAppValue('rainloop', 'rainloop-url', '');
$sPath = OCP\Config::getAppValue('rainloop', 'rainloop-path', '');
if (!$bInstalledLocaly)
{
OCP\Config::setAppValue('rainloop', 'rainloop-url', $_POST['rainloop-url']);
OCP\Config::setAppValue('rainloop', 'rainloop-path', $_POST['rainloop-path']);
$sUrl = OCP\Config::getAppValue('rainloop', 'rainloop-url', '');
$sPath = OCP\Config::getAppValue('rainloop', 'rainloop-path', '');
}
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
}
else
{
sleep(1);
OC_JSON::error(array('Message' => 'Invalid Argument(s)', 'Url' => $sUrl, 'Path' => $sPath));
return false;
}
sleep(1);
OCP\JSON::success(array('Message' => 'Saved successfully', 'Url' => $sUrl, 'Path' => $sPath));
return true;

View file

@ -4,7 +4,7 @@
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
@ -37,9 +37,11 @@ if (isset($_POST['appname'], $_POST['rainloop-password'], $_POST['rainloop-email
}
else
{
sleep(1);
OC_JSON::error(array('Message' => 'Invalid argument(s)', 'Email' => $sEmail));
return false;
}
sleep(1);
OCP\JSON::success(array('Message' => 'Saved successfully', 'Email' => $sEmail));
return true;

View file

@ -0,0 +1,10 @@
<?php
if (@file_exists(__DIR__.'/app/index.php'))
{
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
OC_RainLoop_Helper::regRainLoopDataFunction();
include __DIR__.'/app/index.php';
}

View file

@ -4,7 +4,7 @@
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/owncloud
*/

View file

@ -2,7 +2,10 @@
<info>
<id>rainloop</id>
<name>RainLoop</name>
<description>RainLoop Webmail</description>
<description>Simple, modern & fast web-based email client.
Modest system requirements, decent performance, simple installation and upgrade, no database required -
all these make RainLoop Webmail a perfect choice for your email solution.</description>
<version>0.0</version>
<licence>CC BY-NC-SA 3.0</licence>
<author>RainLoop Team</author>

View file

@ -0,0 +1,13 @@
<?php
$this->create('rainloop_index', '/')
->actionInclude('rainloop/index.php');
$this->create('rainloop_app', '/app/')
->actionInclude('rainloop/app.php');
$this->create('rainloop_ajax_personal', 'ajax/personal.php')
->actionInclude('rainloop/ajax/personal.php');
$this->create('rainloop_ajax_admin', 'ajax/admin.php')
->actionInclude('rainloop/ajax/admin.php');

View file

@ -4,7 +4,7 @@
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
@ -13,8 +13,23 @@ OCP\User::checkLoggedIn();
OCP\App::checkAppEnabled('rainloop');
OCP\App::setActiveNavigationEntry('rainloop_index');
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
$sUrl = '';
$sPath = '';
$bInstalledLocaly = file_exists(__DIR__.'/app/index.php');
if ($bInstalledLocaly)
{
$sUrl = OC_RainLoop_Helper::getAppUrl();
$sPath = __DIR__.'/app/';
}
else
{
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
}
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
if ('' === $sUrl || '' === $sPath)
@ -23,10 +38,6 @@ if ('' === $sUrl || '' === $sPath)
}
else
{
include_once OC_App::getAppPath('rainloop').'/lib/RainLoopHelper.php';
OC_Config::setValue('xframe_restriction', false);
$sUser = OCP\User::getUser();
if ($bAutologin)

View file

@ -1,13 +1,13 @@
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
});
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-admin-form', 'admin.php');
});

View file

@ -1,13 +1,13 @@
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php');
});
/**
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
$(function() {
RainLoopFormHelper('#mail-rainloop-personal-form', 'personal.php');
});

View file

@ -2,6 +2,18 @@
class OC_RainLoop_Helper
{
/**
* @return string
*/
public static function getAppUrl()
{
$sRequestUri = empty($_SERVER['REQUEST_URI']) ? '': trim($_SERVER['REQUEST_URI']);
$sRequestUri = preg_replace('/index.php\/.+$/', 'index.php/', $sRequestUri);
$sRequestUri = $sRequestUri.'apps/rainloop/app/';
return '/'.ltrim($sRequestUri, '/\\');
}
/**
* @param string $sPath
* @param string $sEmail
@ -16,6 +28,8 @@ class OC_RainLoop_Helper
$sPath = rtrim(trim($sPath), '\\/').'/index.php';
if (file_exists($sPath))
{
self::regRainLoopDataFunction();
$_ENV['RAINLOOP_INCLUDE_AS_API'] = true;
include $sPath;
@ -124,4 +138,102 @@ class OC_RainLoop_Helper
return false;
}
public static function regRainLoopDataFunction()
{
if (!@function_exists('__get_custom_data_full_path'))
{
$_ENV['RAINLOOP_OWNCLOUD'] = true;
function __get_custom_data_full_path()
{
$sData = __DIR__.'/../../data/';
if (class_exists('OC_Config'))
{
$sData = rtrim(trim(OC_Config::getValue('datadirectory', '')), '\\/').'/';
}
return @is_dir($sData) ? $sData.'rainloop-storage' : '';
}
}
}
public static function mimeContentType($filename) {
$mime_types = array(
'woff' => 'application/font-woff',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'php' => 'text/html',
'css' => 'text/css',
'js' => 'application/javascript',
'json' => 'application/json',
'xml' => 'application/xml',
'swf' => 'application/x-shockwave-flash',
'flv' => 'video/x-flv',
// images
'png' => 'image/png',
'jpe' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'gif' => 'image/gif',
'bmp' => 'image/bmp',
'ico' => 'image/vnd.microsoft.icon',
'tiff' => 'image/tiff',
'tif' => 'image/tiff',
'svg' => 'image/svg+xml',
'svgz' => 'image/svg+xml',
// archives
'zip' => 'application/zip',
'rar' => 'application/x-rar-compressed',
'exe' => 'application/x-msdownload',
'msi' => 'application/x-msdownload',
'cab' => 'application/vnd.ms-cab-compressed',
// audio/video
'mp3' => 'audio/mpeg',
'qt' => 'video/quicktime',
'mov' => 'video/quicktime',
// adobe
'pdf' => 'application/pdf',
'psd' => 'image/vnd.adobe.photoshop',
'ai' => 'application/postscript',
'eps' => 'application/postscript',
'ps' => 'application/postscript',
// ms office
'doc' => 'application/msword',
'rtf' => 'application/rtf',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
// open office
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
);
if (0 < strpos($filename, '.'))
{
$ext = strtolower(array_pop(explode('.',$filename)));
if (array_key_exists($ext, $mime_types))
{
return $mime_types[$ext];
}
else if (function_exists('finfo_open'))
{
$finfo = finfo_open(FILEINFO_MIME);
$mimetype = finfo_file($finfo, $filename);
finfo_close($finfo);
return $mimetype;
}
}
return 'application/octet-stream';
}
}

View file

@ -4,7 +4,7 @@
* ownCloud - RainLoop mail plugin
*
* @author RainLoop Team
* @copyright 2014 RainLoop Team
* @copyright 2015 RainLoop Team
*
* https://github.com/RainLoop/rainloop-webmail/tree/master/build/owncloud
*/
@ -14,11 +14,19 @@ OCP\App::checkAppEnabled('rainloop');
OCP\Util::addScript('rainloop', 'personal');
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
$sUrl = '';
$sPath = '';
$bAutologin = OCP\Config::getAppValue('rainloop', 'rainloop-autologin', false);
if ($bAutologin || '' === $sUrl || '' === $sPath)
$bInstalledLocaly = file_exists(__DIR__.'/app/index.php');
if (!$bInstalledLocaly)
{
$sUrl = trim(OCP\Config::getAppValue('rainloop', 'rainloop-url', ''));
$sPath = trim(OCP\Config::getAppValue('rainloop', 'rainloop-path', ''));
}
if ($bAutologin || (!$bInstalledLocaly && ('' === $sUrl || '' === $sPath)))
{
$oTemplate = new OCP\Template('rainloop', 'empty');
}

View file

@ -0,0 +1,29 @@
<div class="section">
<form id="mail-rainloop-admin-form" action="#" method="post">
<input type="hidden" name="requesttoken" value="<?php echo $_['requesttoken'] ?>" id="requesttoken">
<input type="hidden" name="appname" value="rainloop">
<fieldset class="personalblock">
<h2><?php p($l->t('RainLoop Webmail')); ?></h2>
<br />
<?php if ($_['rainloop-admin-panel-link']): ?>
<p>
<a href="<?php echo $_['rainloop-admin-panel-link'] ?>" target="_blank" style="text-decoration: underline">
<?php p($l->t('Go to RainLoop Webmail admin panel')); ?>
</a>
</p>
<br />
<?php endif; ?>
<p>
<input type="checkbox" id="rainloop-autologin" id="rainloop-autologin" name="rainloop-autologin" value="1" <?php if ($_['rainloop-autologin']): ?>checked="checked"<?php endif; ?> />
<label for="rainloop-autologin">
<?php p($l->t('Automatically login with ownCloud user credentials')); ?>
</label>
<br />
<br />
<input type="button" id="rainloop-save-button" name="rainloop-save-button" value="<?php p($l->t('Save')); ?>" />
&nbsp;&nbsp;<span class="rainloop-result-desc"></span>
</p>
</fieldset>
</form>
</div>

View file

@ -50,6 +50,37 @@
}
});
Globals.$win.on('resize', function () {
Events.pub('window.resize');
});
Events.sub('window.resize', _.throttle(function () {
var
iH = Globals.$win.height(),
iW = Globals.$win.height()
;
if (Globals.$win.__sizes[0] !== iH || Globals.$win.__sizes[1] !== iW)
{
Globals.$win.__sizes[0] = iH;
Globals.$win.__sizes[1] = iW;
Events.pub('window.resize.real');
}
}, 50));
// TODO
// Events.sub({
// 'window.resize': function () {
// window.console.log('window.resize');
// },
// 'window.resize.real': function () {
// window.console.log('window.resize.real');
// }
// });
Globals.$doc.on('keydown', function (oEvent) {
if (oEvent && oEvent.ctrlKey)
{
@ -315,6 +346,8 @@
ssm.ready();
require('Stores/Language').populate();
require('Stores/Theme').populate();
require('Stores/Social').populate();

View file

@ -41,6 +41,7 @@
MessageModel = require('Model/Message'),
AccountModel = require('Model/Account'),
IdentityModel = require('Model/Identity'),
TemplateModel = require('Model/Template'),
OpenPgpKeyModel = require('Model/OpenPgpKey'),
AbstractApp = require('App/Abstract')
@ -611,12 +612,10 @@
{
Utils.delegateRunOnDestroy(TemplateStore.templates());
IdentityStore.templates(_.map(oData.Result['Templates'], function (oIdentityData) {
return {
'id': Utils.pString(oIdentityData['Id']),
'name': Utils.pString(oIdentityData['Name'])
};
}));
TemplateStore.templates(_.compact(_.map(oData.Result['Templates'], function (oTemplateData) {
var oTemplate = new TemplateModel();
return oTemplate.parse(oTemplateData) ? oTemplate : null;
})));
}
});
};

View file

@ -45,6 +45,7 @@
'Sieve': 'SIEVE',
'Filters': 'FILTERS',
'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS',
'Templates': 'TEMPLATES',
'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS'
};

View file

@ -28,12 +28,24 @@
*/
Events.prototype.sub = function (sName, fFunc, oContext)
{
if (Utils.isUnd(this.oSubs[sName]))
if (Utils.isObject(sName))
{
this.oSubs[sName] = [];
}
oContext = fFunc || null;
fFunc = null;
this.oSubs[sName].push([fFunc, oContext]);
_.each(sName, function (fSubFunc, sSubName) {
this.sub(sSubName, fSubFunc, oContext);
}, this);
}
else
{
if (Utils.isUnd(this.oSubs[sName]))
{
this.oSubs[sName] = [];
}
this.oSubs[sName].push([fFunc, oContext]);
}
return this;
};

View file

@ -20,6 +20,8 @@
Globals.$html = $('html');
Globals.$div = $('<div></div>');
Globals.$win.__sizes = [0, 0];
/**
* @type {?}
*/
@ -255,7 +257,7 @@
});
Globals.keyScopeReal.subscribe(function (sValue) {
// window.console.log(sValue);
// window.console.log(sValue); //TODO
key.setScope(sValue);
});

View file

@ -106,8 +106,13 @@
.replace("\u0002", '').replace("\u0002", '')
.replace("\u0003", '').replace("\u0003", '')
.replace("\u0003", '').replace("\u0003", '')
.replace("\u0004", '').replace("\u0004", '')
.replace("\u0004", '').replace("\u0004", '')
.replace("\u0005", '').replace("\u0005", '')
.replace("\u0005", '').replace("\u0005", '')
;
}
};
/**
* @param {boolean=} bWrapIsHtml = false
* @param {boolean=} bClearSignatureSigns = false

View file

@ -24,6 +24,7 @@
Utils.trim = $.trim;
Utils.inArray = $.inArray;
Utils.isArray = _.isArray;
Utils.isObject = _.isObject;
Utils.isFunc = _.isFunction;
Utils.isUnd = _.isUndefined;
Utils.isNull = _.isNull;

View file

@ -41,7 +41,7 @@
AbstractModel.prototype.onDestroy = function ()
{
Utils.disposeObject(this);
// window.console.log('onDestroy: ' + this.sModelName);
// window.console.log('onDestroy: ' + this.sModelName); // TODO
};
module.exports = AbstractModel;

View file

@ -7,6 +7,8 @@
_ = require('_'),
ko = require('ko'),
Utils = require('Common/Utils'),
AbstractModel = require('Knoin/AbstractModel')
;
@ -24,6 +26,7 @@
this.id = sID;
this.name = sName;
this.body = sBody;
this.populated = true;
this.deleteAccess = ko.observable(false);
}
@ -45,6 +48,30 @@
*/
TemplateModel.prototype.body = '';
/**
* @type {boolean}
*/
TemplateModel.prototype.populated = true;
/**
* @type {boolean}
*/
TemplateModel.prototype.parse = function (oItem)
{
var bResult = false;
if (oItem && 'Object/Template' === oItem['@Object'])
{
this.id = Utils.pString(oItem['ID']);
this.name = Utils.pString(oItem['Name']);
this.body = Utils.pString(oItem['Body']);
this.populated = !!oItem['Populated'];
bResult = true;
}
return bResult;
};
module.exports = TemplateModel;
}());

View file

@ -85,8 +85,11 @@
'SettingsChangePassword', 'SETTINGS_LABELS/LABEL_CHANGE_PASSWORD_NAME', 'change-password');
}
// kn.addSettingsViewModel(require('Settings/User/Templates'),
// 'SettingsTemplates', 'SETTINGS_LABELS/LABEL_TEMPLATES_NAME', 'templates');
if (Settings.capa(Enums.Capa.Templates))
{
kn.addSettingsViewModel(require('Settings/User/Templates'),
'SettingsTemplates', 'SETTINGS_LABELS/LABEL_TEMPLATES_NAME', 'templates');
}
kn.addSettingsViewModel(require('Settings/User/Folders'),
'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders');

View file

@ -34,6 +34,7 @@
this.capaGravatar = CapaAdminStore.gravatar;
this.capaAdditionalAccounts = CapaAdminStore.additionalAccounts;
this.capaAttachmentThumbnails = CapaAdminStore.attachmentThumbnails;
this.capaTemplates = CapaAdminStore.templates;
this.allowLanguagesOnSettings = AppAdminStore.allowLanguagesOnSettings;
this.weakPassword = AppAdminStore.weakPassword;
@ -105,6 +106,12 @@
});
});
self.capaTemplates.subscribe(function (bValue) {
Remote.saveAdminConfig(null, {
'CapaTemplates': bValue ? '1' : '0'
});
});
self.capaGravatar.subscribe(function (bValue) {
Remote.saveAdminConfig(null, {
'CapaGravatar': bValue ? '1' : '0'

View file

@ -9,7 +9,6 @@
ko = require('ko'),
Enums = require('Common/Enums'),
Utils = require('Common/Utils'),
Translator = require('Common/Translator'),
Links = require('Common/Links'),

View file

@ -293,7 +293,17 @@
/**
* @param {?Function} fCallback
*/
RemoteUserStorage.prototype.templateGetById = function (fCallback, sID, sName, sBody)
RemoteUserStorage.prototype.templateDelete = function (fCallback, sID)
{
this.defaultRequest(fCallback, 'TemplateDelete', {
'IdToDelete': sID
});
};
/**
* @param {?Function} fCallback
*/
RemoteUserStorage.prototype.templateSetup = function (fCallback, sID, sName, sBody)
{
this.defaultRequest(fCallback, 'TemplateSetup', {
'ID': sID,

View file

@ -25,6 +25,7 @@
this.userBackground = ko.observable(false);
this.openPGP = ko.observable(false);
this.twoFactorAuth = ko.observable(false);
this.templates = ko.observable(false);
}
CapaAdminStore.prototype.populate = function()
@ -38,6 +39,7 @@
this.userBackground(Settings.capa(Enums.Capa.UserBackground));
this.openPGP(Settings.capa(Enums.Capa.OpenPGP));
this.twoFactorAuth(Settings.capa(Enums.Capa.TwoFactor));
this.templates(Settings.capa(Enums.Capa.Templates));
};
module.exports = new CapaAdminStore();

View file

@ -5,9 +5,9 @@
var
_ = require('_'),
ko = require('ko'),
ko = require('ko')
Remote = require('Storage/User/Remote')
// Remote = require('Storage/User/Remote')
;
/**
@ -27,16 +27,16 @@
})));
}, this);
this.templatesNames.subscribe(function (aList) {
if (this.templatesNames.skipFirst)
{
this.templatesNames.skipFirst = false;
}
else if (aList && 1 < aList.length)
{
Remote.templatesSortOrder(null, aList);
}
}, this);
// this.templatesNames.subscribe(function (aList) {
// if (this.templatesNames.skipFirst)
// {
// this.templatesNames.skipFirst = false;
// }
// else if (aList && 1 < aList.length)
// {
// Remote.templatesSortOrder(null, aList);
// }
// }, this);
}
module.exports = new TemplateUserStore();

View file

@ -1,5 +1,5 @@
.b-settings-identities {
.b-settings-templates {
.process-place {
text-align: center;

View file

@ -2,11 +2,15 @@
.b-template-add-content {
&.modal {
width: 700px;
width: 750px;
}
.modal-header {
background-color: #fff;
}
.e-template-place {
height: 300px;
}
}
}

View file

@ -80,7 +80,7 @@
this.bFromDraft = false;
this.sReferences = '';
this.triggerForResize = _.bind(this.triggerForResize, this);
this.resizerTrigger = _.bind(this.resizerTrigger, this);
this.allowContacts = !!AppStore.contactsIsAllowed();
@ -90,8 +90,6 @@
this.capaOpenPGP = PgpStore.capaOpenPGP;
this.resizer = ko.observable(false).extend({'throttle': 50});
this.identitiesDropdownTrigger = ko.observable(false);
this.to = ko.observable('');
@ -241,11 +239,13 @@
}
}, this);
this.editorResizeThrottle = _.throttle(_.bind(this.editorResize, this), 100);
this.resizer = ko.observable(false).extend({'throttle': 50});
this.resizer.subscribe(function () {
this.editorResizeThrottle();
}, this);
this.resizer.subscribe(_.bind(function () {
if (this.oEditor){
this.oEditor.resize();
}
}, this));
this.canBeSendedOrSaved = ko.computed(function () {
return !this.sending() && !this.saving();
@ -429,9 +429,9 @@
}
}, this);
this.showCc.subscribe(this.triggerForResize);
this.showBcc.subscribe(this.triggerForResize);
this.showReplyTo.subscribe(this.triggerForResize);
this.showCc.subscribe(this.resizerTrigger);
this.showBcc.subscribe(this.resizerTrigger);
this.showReplyTo.subscribe(this.resizerTrigger);
this.dropboxEnabled = SocialStore.dropbox.enabled;
this.dropboxApiKey = SocialStore.dropbox.apiKey;
@ -1230,7 +1230,7 @@
this.currentIdentity(oIdentity);
}
this.triggerForResize();
this.resizerTrigger();
};
ComposePopupView.prototype.onFocus = function ()
@ -1244,15 +1244,7 @@
this.oEditor.focus();
}
this.triggerForResize();
};
ComposePopupView.prototype.editorResize = function ()
{
if (this.oEditor)
{
this.oEditor.resize();
}
this.resizerTrigger();
};
ComposePopupView.prototype.tryToClosePopup = function ()
@ -1315,7 +1307,7 @@
return false;
});
Globals.$win.on('resize', self.triggerForResize);
Events.sub('window.resize.real', this.resizerTrigger);
if (this.dropboxEnabled())
{
@ -2034,10 +2026,9 @@
});
};
ComposePopupView.prototype.triggerForResize = function ()
ComposePopupView.prototype.resizerTrigger = function ()
{
this.resizer(!this.resizer());
this.editorResizeThrottle();
};
module.exports = ComposePopupView;

View file

@ -36,6 +36,7 @@
this.name.focus = ko.observable(false);
this.body = ko.observable('');
this.body.loading = ko.observable(false);
this.body.error = ko.observable(false);
this.name.subscribe(function () {
@ -51,6 +52,8 @@
this.addTemplateCommand = Utils.createCommand(this, function () {
this.populateBodyFromEditor();
this.name.error('' === Utils.trim(this.name()));
this.body.error('' === Utils.trim(this.body()) ||
':HTML:' === Utils.trim(this.body()));
@ -109,40 +112,52 @@
this.submitRequest(false);
this.submitError('');
if (this.editor)
{
this.setBody('');
}
};
TemplatePopupView.prototype.setBody = function (sBody)
{
if (this.editor)
{
if (':HTML:' === sBody.substr(0, 6))
{
this.editor.setHtml(sBody.substr(6), false);
}
else
{
this.editor.setPlain(sBody, false);
}
}
};
TemplatePopupView.prototype.populateBodyFromEditor = function ()
{
if (this.editor)
{
this.body(
(this.editor.isHtml() ? ':HTML:' : '') + this.editor.getData()
);
}
};
TemplatePopupView.prototype.editorSetBody = function (sBody)
{
var
self = this,
fEditorSetData = function (sBody) {
if (self.editor)
{
if (':HTML:' === sBody.substr(0, 6))
{
self.editor.setHtml(sBody.substr(6), false);
}
else
{
self.editor.setPlain(sBody, false);
}
}
}
;
if (!this.editor && this.signatureDom())
{
var self = this;
this.editor = new HtmlEditor(self.signatureDom(), function () {
self.body(
(self.editor.isHtml() ? ':HTML:' : '') + self.editor.getData()
);
self.populateBodyFromEditor();
}, function () {
fEditorSetData(sBody);
self.setBody(sBody);
});
}
else if (this.editor)
else
{
fEditorSetData(sBody);
this.setBody(sBody);
}
};
@ -156,16 +171,44 @@
{
this.id(oTemplate.id);
this.name(oTemplate.name);
this.body(oTemplate.body);
this.body.loading(true);
if (oTemplate.populated)
{
self.editorSetBody(this.body());
}
else
{
this.body.loading(true);
self.body.error(false);
Remote.templateGetById(function () {
Remote.templateGetById(function (sResult, oData) {
self.body.loading(false);
self.body.loading(false);
self.editorSetBody('');
if (Enums.StorageResultType.Success === sResult && oData && oData.Result &&
'Object/Template' === oData.Result['@Object'] && Utils.isNormal(oData.Result['Body']))
{
oTemplate.body = oData.Result['Body'];
oTemplate.populated = true;
}, this.id());
self.body(oTemplate.body);
self.body.error(false);
}
else
{
self.body('');
self.body.error(true);
}
self.editorSetBody(self.body());
}, this.id());
}
}
else
{
self.editorSetBody('');
}
};

View file

@ -423,11 +423,11 @@
this.showFullInfo.subscribe(fCheckHeaderHeight);
this.message.subscribe(fCheckHeaderHeight);
Globals.$win.on('resize', function () {
Events.sub('window.resize', _.throttle(function () {
_.delay(fCheckHeaderHeight, 1);
_.delay(fCheckHeaderHeight, 200);
_.delay(fCheckHeaderHeight, 500);
});
}, 50));
this.showFullInfo.subscribe(function () {
Utils.windowResize();

View file

@ -7,6 +7,7 @@ var
devVersion: '0.0.0',
releasesPath: 'build/dist/releases',
rainloopBuilded: false,
destPath: '',
cleanPath: '',
zipSrcPath: '',
@ -459,6 +460,8 @@ gulp.task('rainloop:setup', ['rainloop:copy'], function() {
cfg.zipSrcPath = dist;
cfg.zipFile = 'rainloop-' + versionFull + '.zip';
cfg.md5File = cfg.zipFile;
cfg.rainloopBuilded = true;
});
gulp.task('rainloop:zip', ['rainloop:copy', 'rainloop:setup'], function() {
@ -490,7 +493,28 @@ gulp.task('rainloop:owncloud:copy', function() {
.pipe(gulp.dest(dist + 'rainloop'));
});
gulp.task('rainloop:owncloud:setup', ['rainloop:owncloud:copy'], function() {
gulp.task('rainloop:owncloud:copy-rainloop', ['rainloop:start', 'rainloop:owncloud:copy'], function() {
var
versionFull = pkg.ownCloudPackageVersion,
dist = cfg.releasesPath + '/owncloud/' + versionFull + '/src/rainloop/'
;
if (cfg.rainloopBuilded && cfg.destPath)
{
return gulp.src(cfg.destPath + '/src/**/*', {base: cfg.destPath + '/src/'})
.pipe(gulp.dest(dist + 'app/'));
}
return true;
});
gulp.task('rainloop:owncloud:copy-rainloop:clean', ['rainloop:owncloud:copy-rainloop'], function() {
return (cfg.cleanPath) ? cleanDir(cfg.cleanPath) : false;
});
gulp.task('rainloop:owncloud:setup', ['rainloop:owncloud:copy',
'rainloop:owncloud:copy-rainloop'], function() {
var
versionFull = pkg.ownCloudPackageVersion,
@ -529,8 +553,12 @@ gulp.task('rainloop:owncloud:clean', ['rainloop:owncloud:copy', 'rainloop:ownclo
gulp.task('default', ['js:libs', 'js:boot', 'js:openpgp', 'js:min', 'css:main:min', 'ckeditor', 'fontastic']);
gulp.task('fast', ['js:app', 'js:admin', 'js:chunks', 'css:main']);
gulp.task('rainloop', ['js:lint', 'rainloop:copy', 'rainloop:setup', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']);
gulp.task('owncloud', ['rainloop:owncloud:copy', 'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']);
gulp.task('rainloop:start', ['js:lint', 'rainloop:copy', 'rainloop:setup']);
gulp.task('rainloop', ['rainloop:start', 'rainloop:zip', 'rainloop:md5', 'rainloop:clean']);
gulp.task('owncloud', ['rainloop:owncloud:copy',
'rainloop:owncloud:copy-rainloop',
'rainloop:owncloud:setup', 'rainloop:owncloud:zip', 'rainloop:owncloud:md5', 'rainloop:owncloud:clean']);
//WATCH
gulp.task('watch', ['fast'], function() {

View file

@ -1,8 +1,8 @@
{
"name": "RainLoop",
"title": "RainLoop Webmail",
"version": "1.8.0",
"release": "251",
"version": "1.8.1",
"release": "255",
"description": "Simple, modern & fast web-based email client",
"homepage": "http://rainloop.net",
"main": "gulpfile.js",
@ -36,7 +36,7 @@
"plugins"
],
"readmeFilename": "README.md",
"ownCloudPackageVersion": "2.3",
"ownCloudPackageVersion": "3.0",
"engines": {
"node": ">= 0.10.0"
},

View file

@ -263,7 +263,6 @@ class Http
*/
public function GetHeader($sHeader)
{
$sResultHeader = '';
$sServerKey = 'HTTP_'.\strtoupper(\str_replace('-', '_', $sHeader));
$sResultHeader = $this->GetServer($sServerKey, '');

View file

@ -65,7 +65,7 @@ class SubStreams
\stream_wrapper_register(self::STREAM_NAME, '\MailSo\Base\StreamWrappers\SubStreams');
}
$sHashName = \md5(\microtime(true).\rand(1000, 9999));
$sHashName = \MailSo\Base\Utils::Md5Rand();
self::$aStreams[$sHashName] = $aSubStreams;
@ -84,7 +84,7 @@ class SubStreams
{
return $this->aSubStreams[$this->iIndex];
}
return $nNull;
}

View file

@ -2147,6 +2147,28 @@ class Utils
return \is_string($mResult) && 0 < \strlen($mResult) ? $mResult : '';
}
/**
* @param string $sAdditionalSalt = ''
*
* @return string
*/
public static function Md5Rand($sAdditionalSalt = '')
{
return \md5(\microtime(true).\rand(10000, 99999).
\md5($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
}
/**
* @param string $sAdditionalSalt = ''
*
* @return string
*/
public static function Sha1Rand($sAdditionalSalt = '')
{
return \sha1(\microtime(true).\rand(10000, 99999).
\sha1($sAdditionalSalt).\rand(10000, 99999).\microtime(true));
}
/**
* @param string $sData
* @param string $sKey

View file

@ -121,7 +121,7 @@ class Logger extends \MailSo\Base\Collection
static $sCache = null;
if (null === $sCache)
{
$sCache = \substr(\md5(\microtime(true).\rand(10000, 99999)), -8);
$sCache = \substr(\MailSo\Base\Utils::Md5Rand(), -8);
}
return $sCache;

View file

@ -990,7 +990,7 @@ class MailClient
{
do
{
$sKey = \md5(\rand(10000, 90000).\microtime(true));
$sKey = \MailSo\Base\Utils::Md5Rand();
}
while (isset($aCache[$sKey]));
@ -1006,7 +1006,7 @@ class MailClient
{
do
{
$sKey = \md5(\rand(10000, 90000).\microtime(true));
$sKey = \MailSo\Base\Utils::Md5Rand();
}
while (isset($aCache[$sKey]));

View file

@ -535,8 +535,9 @@ class Message
$sHostName = 'localhost';
}
return '<'.\md5(\rand(100000, 999999).\time().$sHostName.
(\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? @\getmypid() : '')).'@'.$sHostName.'>';
return '<'.
\MailSo\Base\Utils::Md5Rand($sHostName.
(\MailSo\Base\Utils::FunctionExistsAndEnabled('getmypid') ? @\getmypid() : '')).'@'.$sHostName.'>';
}
/**

View file

@ -1511,7 +1511,7 @@ class Actions
$aResult['UseLocalProxyForExternalImages'] = (bool) $oConfig->Get('labs', 'use_local_proxy_for_external_images', false);
// user
$aResult['ShowImages'] = (bool) $oConfig->Get('webmail', 'show_images', false);
$aResult['ShowImages'] = (bool) $oConfig->Get('defaults', 'show_images', false);
$aResult['MPP'] = (int) $oConfig->Get('webmail', 'messages_per_page', 25);
$aResult['SoundNotification'] = false;
$aResult['DesktopNotifications'] = false;
@ -1982,7 +1982,7 @@ class Actions
*/
private function generateSignMeToken($sEmail)
{
return \md5(\microtime(true).APP_SALT.\rand(10000, 99999).$sEmail);
return \MailSo\Base\Utils::Md5Rand(APP_SALT.$sEmail);
}
/**
@ -2122,6 +2122,85 @@ class Actions
return $aAccounts;
}
/**
* @param \RainLoop\Model\Account $oAccount
*
* @return array
*/
public function GetTemplates($oAccount)
{
$aTemplates = array();
if ($oAccount)
{
$aData = array();
$sData = $this->StorageProvider(true)->Get($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
'templates'
);
if ('' !== $sData && '[' === \substr($sData, 0, 1))
{
$aData = @\json_decode($sData, true);
}
if (\is_array($aData) && 0 < \count($aData))
{
foreach ($aData as $aItem)
{
$oItem = \RainLoop\Model\Template::NewInstance();
$oItem->FromJSON($aItem);
if ($oItem && $oItem->Validate())
{
\array_push($aTemplates, $oItem);
}
}
}
if (1 < \count($aTemplates))
{
$sOrder = $this->StorageProvider()->Get($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
'templates_order'
);
$aOrder = empty($sOrder) ? array() : @\json_decode($sOrder, true);
if (\is_array($aOrder) && 1 < \count($aOrder))
{
\usort($aTemplates, function ($a, $b) use ($aOrder) {
return \array_search($a->Id(), $aOrder) < \array_search($b->Id(), $aOrder) ? -1 : 1;
});
}
}
}
return $aTemplates;
}
/**
* @param \RainLoop\Model\Account $oAccount
* @param string $sID
*
* @return \RainLoop\Model\Identity
*/
public function GetTemplateByID($oAccount, $sID)
{
$aTemplates = $this->GetTemplates($oAccount);
if (\is_array($aTemplates))
{
foreach ($aTemplates as $oIdentity)
{
if ($oIdentity && $sID === $oIdentity->Id())
{
return $oIdentity;
}
}
}
return isset($aTemplates[0]) ? $aTemplates[0] : null;
}
/**
* @param \RainLoop\Model\Account $oAccount
*
@ -2279,6 +2358,27 @@ class Actions
);
}
/**
* @param \RainLoop\Model\Account $oAccount
* @param array $aTemplates = array()
*
* @return array
*/
public function SetTemplates($oAccount, $aTemplates = array())
{
$aResult = array();
foreach ($aTemplates as $oItem)
{
$aResult[] = $oItem->ToSimpleJSON(false);
}
return $this->StorageProvider(true)->Put($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
'templates',
@\json_encode($aResult)
);
}
/**
* @return array
*
@ -2497,6 +2597,117 @@ class Actions
return $this->DefaultResponse(__FUNCTION__, $this->SetIdentities($oAccount, $aNew));
}
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoTemplateSetup()
{
$oAccount = $this->getAccountFromToken();
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
{
return $this->FalseResponse(__FUNCTION__);
}
$oTemplate = \RainLoop\Model\Template::NewInstance();
if (!$oTemplate->FromJSON($this->GetActionParams(), true))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
}
if ('' === $oTemplate->Id())
{
$oTemplate->GenerateID();
}
$aTemplatesForSave = array();
$aTemplates = $this->GetTemplates($oAccount);
foreach ($aTemplates as $oItem)
{
if ($oItem && $oItem->Id() !== $oTemplate->Id())
{
$aTemplatesForSave[] = $oItem;
}
}
$aTemplatesForSave[] = $oTemplate;
return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aTemplatesForSave));
}
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoTemplateDelete()
{
$oAccount = $this->getAccountFromToken();
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
{
return $this->FalseResponse(__FUNCTION__);
}
$sId = \trim($this->GetActionParam('IdToDelete', ''));
if (empty($sId))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
}
$aNew = array();
$aTemplates = $this->GetTemplates($oAccount);
foreach ($aTemplates as $oItem)
{
if ($oItem && $sId !== $oItem->Id())
{
$aNew[] = $oItem;
}
}
return $this->DefaultResponse(__FUNCTION__, $this->SetTemplates($oAccount, $aNew));
}
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoTemplateGetByID()
{
$oAccount = $this->getAccountFromToken();
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
{
return $this->FalseResponse(__FUNCTION__);
}
$sId = \trim($this->GetActionParam('ID', ''));
if (empty($sId))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::UnknownError);
}
$oTemplate = false;
$aTemplates = $this->GetTemplates($oAccount);
foreach ($aTemplates as $oItem)
{
if ($oItem && $sId === $oItem->Id())
{
$oTemplate = $oItem;
break;
}
}
$oTemplate->SetPopulateAlways(true);
return $this->DefaultResponse(__FUNCTION__, $oTemplate);
}
/**
* @return array
*
@ -2550,6 +2761,25 @@ class Actions
));
}
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoTemplates()
{
$oAccount = $this->getAccountFromToken();
if (!$this->GetCapa(false, \RainLoop\Enumerations\Capa::TEMPLATES, $oAccount))
{
return $this->FalseResponse(__FUNCTION__);
}
return $this->DefaultResponse(__FUNCTION__, array(
'Templates' => $this->GetTemplates($oAccount)
));
}
/**
* @param string $sHash
*
@ -2821,6 +3051,9 @@ class Actions
case \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS:
$this->setConfigFromParams($oConfig, $sParamName, 'webmail', 'allow_additional_accounts', 'bool');
break;
case \RainLoop\Enumerations\Capa::TEMPLATES:
$this->setConfigFromParams($oConfig, $sParamName, 'capa', 'templates', 'bool');
break;
case \RainLoop\Enumerations\Capa::TWO_FACTOR:
$this->setConfigFromParams($oConfig, $sParamName, 'security', 'allow_two_factor_auth', 'bool');
break;
@ -2923,6 +3156,7 @@ class Actions
});
$this->setCapaFromParams($oConfig, 'CapaAdditionalAccounts', \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS);
$this->setCapaFromParams($oConfig, 'CapaTemplates', \RainLoop\Enumerations\Capa::TEMPLATES);
$this->setCapaFromParams($oConfig, 'CapaTwoFactorAuth', \RainLoop\Enumerations\Capa::TWO_FACTOR);
$this->setCapaFromParams($oConfig, 'CapaOpenPGP', \RainLoop\Enumerations\Capa::OPEN_PGP);
$this->setCapaFromParams($oConfig, 'CapaGravatar', \RainLoop\Enumerations\Capa::GRAVATAR);
@ -5303,6 +5537,27 @@ class Actions
return $oMessage;
}
/**
* @param \RainLoop\Model\Account $oAccount
*
* @return void
*/
private function deleteMessageAttachmnets($oAccount)
{
$aAttachments = $this->GetActionParam('Attachments', null);
if (\is_array($aAttachments))
{
foreach (\array_keys($aAttachments) as $sTempName)
{
if ($this->FilesProvider()->FileExists($oAccount, $sTempName))
{
$this->FilesProvider()->Clear($oAccount, $sTempName);
}
}
}
}
/**
* @param \RainLoop\Model\Account $oAccount
*
@ -5600,6 +5855,8 @@ class Actions
{
$this->smtpSendMessage($oAccount, $oMessage, $rMessageStream, $iMessageStreamSize);
$this->deleteMessageAttachmnets($oAccount);
if (is_array($aDraftInfo) && 3 === count($aDraftInfo))
{
$sDraftInfoType = $aDraftInfo[0];
@ -6967,7 +7224,7 @@ class Actions
$oSettings = $this->SettingsProvider()->Load($oAccount);
if ($oSettings)
{
$sHash = \md5($sName.APP_VERSION.APP_SALT.\rand(1000, 9999).\microtime(true));
$sHash = \MailSo\Base\Utils::Md5Rand($sName.APP_VERSION.APP_SALT);
$oSettings->SetConf('UserBackgroundName', $sName);
$oSettings->SetConf('UserBackgroundHash', $sHash);
@ -7225,7 +7482,7 @@ class Actions
$sLast = \array_pop($aParams);
$sUrl = $this->Http()->GetFullUrl().'?/Raw/&s=/'.implode('/', $aParams).'/&ss=/'.$sLast;
$sFullUrl = 'http://docs.google.com/viewer?embedded=true&url='.urlencode($sUrl);
$sFullUrl = 'https://docs.google.com/viewer?embedded=true&url='.urlencode($sUrl);
@\header('Content-Type: text/html; charset=utf-8');
echo '<html style="height: 100%; width: 100%; margin: 0; padding: 0"><head></head>'.
@ -7272,6 +7529,8 @@ class Actions
$rMessageStream = $this->FilesProvider()->GetFile($oAccount, $sSavedName);
$this->MailClient()->MessageAppendStream($rMessageStream, $iMessageStreamSize, $sFolderFullNameRaw);
$this->FilesProvider()->Clear($oAccount, $sSavedName);
}
}
}
@ -7301,6 +7560,11 @@ class Actions
}
}
// if ($oConfig->Get('capa', 'templates', true))
// {
// $aResult[] = \RainLoop\Enumerations\Capa::TEMPLATES;
// }
if ($oConfig->Get('webmail', 'allow_additional_accounts', false))
{
$aResult[] = \RainLoop\Enumerations\Capa::ADDITIONAL_ACCOUNTS;
@ -7455,7 +7719,7 @@ class Actions
{
\MailSo\Base\StreamWrappers\TempFile::Reg();
$sFileName = 'mailsotempfile://'.\md5($sFileNameOut.\rand(1000, 9999));
$sFileName = 'mailsotempfile://'.\MailSo\Base\Utils::Md5Rand($sFileNameOut);
$rTempResource = \fopen($sFileName, 'r+b');
if (@\is_resource($rTempResource))
@ -8256,25 +8520,6 @@ class Actions
@\header('Location: '.$sUrl);
}
/**
* @param string $sTitle
* @param string $sDesc
*
* @return mixed
*/
public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true)
{
return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array(
'{{BaseWebStaticPath}}' => APP_WEB_STATIC_PATH,
'{{ErrorTitle}}' => $sTitle,
'{{ErrorHeader}}' => $sTitle,
'{{ErrorDesc}}' => $sDesc,
'{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none',
'{{BackLink}}' => $this->StaticI18N('STATIC/BACK_LINK'),
'{{BackHref}}' => './'
));
}
/**
* @param object $oData
* @param string $sParent

View file

@ -136,7 +136,7 @@ class Api
*/
public static function GetUserSsoHash($sEmail, $sPassword, $bUseTimeout = true)
{
$sSsoHash = \sha1(\rand(10000, 99999).$sEmail.$sPassword.\microtime(true));
$sSsoHash = \MailSo\Base\Utils::Sha1Rand($sEmail.$sPassword);
return \RainLoop\Api::Actions()->Cacher()->Set(\RainLoop\KeyPathHelper::SsoCacherKey($sSsoHash), \RainLoop\Utils::EncodeKeyValues(array(
'Email' => $sEmail,

View file

@ -129,7 +129,8 @@ class Application extends \RainLoop\Config\AbstractConfig
),
'capa' => array(
'filters' => array(true)
'filters' => array(true),
'templates' => array(true)
),
'login' => array(
@ -164,6 +165,7 @@ Values:
'view_editor_type' => array('Html', 'Editor mode used by default (Plain, Html, HtmlForced or PlainForced)'),
'view_layout' => array(1, 'layout: 0 - no preview, 1 - side preview, 3 - bottom preview'),
'view_use_checkboxes' => array(true),
'show_images' => array(false),
'contacts_autosave' => array(true),
'mail_use_threads' => array(false),
'mail_reply_same_folder' => array(false)

View file

@ -15,4 +15,5 @@ class Capa
const FILTERS = 'FILTERS';
const ATTACHMENT_THUMBNAILS = 'ATTACHMENT_THUMBNAILS';
const ADDITIONAL_ACCOUNTS = 'ADDITIONAL_ACCOUNTS';
const TEMPLATES = 'TEMPLATES';
}

View file

@ -0,0 +1,149 @@
<?php
namespace RainLoop\Model;
class Template
{
/**
* @var string
*/
private $sId;
/**
* @var string
*/
private $sName;
/**
* @var string
*/
private $sBody;
/**
* @var bool
*/
private $bPopulateAlways;
/**
* @param string $sId = ''
* @param string $sName = ''
* @param string $sBody = ''
*
* @return void
*/
protected function __construct($sId = '', $sName = '', $sBody = '')
{
$this->sId = $sId;
$this->sName = $sName;
$this->sBody = $sBody;
$this->bPopulateAlways = false;
}
/**
* @param string $sId = ''
* @param string $sName = ''
* @param string $sBody = ''
*
* @return \RainLoop\Model\Template
*/
public static function NewInstance($sId = '', $sName = '', $sBody = '')
{
return new self($sId, $sBody);
}
/**
* @return string
*/
public function Id()
{
return $this->sId;
}
/**
* @return string
*/
public function Name()
{
return $this->sName;
}
/**
* @return string
*/
public function Body()
{
return $this->sBody;
}
/**
* @param bool $bPopulateAlways
*/
public function SetPopulateAlways($bPopulateAlways)
{
$this->bPopulateAlways = !!$bPopulateAlways;
}
/**
* @param array $aData
* @param bool $bAjax = false
*
* @return bool
*/
public function FromJSON($aData, $bAjax = false)
{
if (isset($aData['ID'], $aData['Name'], $aData['Body']))
{
$this->sId = $aData['ID'];
$this->sName = $aData['Name'];
$this->sBody = $aData['Body'];
return true;
}
return false;
}
/**
* @param bool $bAjax = false
*
* @return array
*/
public function ToSimpleJSON($bAjax = false)
{
$sBody = $this->Body();
$bPopulated = true;
if ($bAjax && $bPopulated && !$this->bPopulateAlways)
{
if (1024 * 5 < \strlen($sBody) || true)
{
$bPopulated = false;
$sBody = '';
}
}
return array(
'ID' => $this->Id(),
'Name' => $this->Name(),
'Populated' => $bPopulated,
'Body' => $sBody
);
}
/**
* @return bool
*/
public function GenerateID()
{
return $this->sId = \MailSo\Base\Utils::Md5Rand();
}
/**
* @return bool
*/
public function Validate()
{
return 0 < \strlen($this->sBody);
}
}

View file

@ -151,7 +151,7 @@ class Contact
public function RegenerateContactStr()
{
$this->IdContactStr = \class_exists('Sabre\DAV\Client') ?
\Sabre\DAV\UUIDUtil::getUUID() : \md5(\microtime(true).'-'.\rand(10000, 99999));
\Sabre\DAV\UUIDUtil::getUUID() : \MailSo\Base\Utils::Md5Rand();
}
/**

View file

@ -107,6 +107,15 @@ class Files extends \RainLoop\Providers\AbstractProvider
return $this->oDriver ? $this->oDriver->GC($iTimeToClearInHours) : false;
}
/**
* @return bool
*/
public function CloseAllOpenedFiles()
{
return $this->oDriver && \method_exists($this->oDriver, 'CloseAllOpenedFiles') ?
$this->oDriver->CloseAllOpenedFiles() : false;
}
/**
* @return bool
*/

View file

@ -4,6 +4,11 @@ namespace RainLoop\Providers\Files;
class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
{
/**
* @var array
*/
private $aResources;
/**
* @var string
*/
@ -16,6 +21,7 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
*/
public function __construct($sStoragePath)
{
$this->aResources = array();
$this->sDataPath = \rtrim(\trim($sStoragePath), '\\/');
}
@ -70,6 +76,11 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
if ($bCreate || \file_exists($sFileName))
{
$mResult = @\fopen($sFileName, $sOpenMode);
if (\is_resource($mResult))
{
$this->aResources[$sFileName] = $mResult;
}
}
return $mResult;
@ -105,6 +116,11 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
$sFileName = $this->generateFileName($oAccount, $sKey);
if (\file_exists($sFileName))
{
if (isset($this->aResources[$sFileName]) && \is_resource($this->aResources[$sFileName]))
{
@\fclose($this->aResources[$sFileName]);
}
$mResult = @\unlink($sFileName);
}
@ -156,6 +172,25 @@ class DefaultStorage implements \RainLoop\Providers\Files\FilesInterface
return false;
}
/**
* @return bool
*/
public function CloseAllOpenedFiles()
{
if (\is_array($this->aResources) && 0 < \count($this->aResources))
{
foreach ($this->aResources as $sFileName => $rFile)
{
if (!empty($sFileName) && \is_resource($rFile))
{
@\fclose($rFile);
}
}
}
return true;
}
/**
* @param \RainLoop\Model\Account $oAccount
* @param string $sKey

View file

@ -125,7 +125,7 @@ class Service
if ($bAdmin && !$this->oActions->Config()->Get('security', 'allow_admin_panel', true))
{
echo $this->oActions->ErrorTemplates('Access Denied.',
echo $this->oServiceActions->ErrorTemplates('Access Denied.',
'Access to the RainLoop Webmail Admin Panel is not allowed!', true);
return $this;
@ -150,6 +150,9 @@ class Service
if ($bIndex)
{
@\header('Content-Security-Policy:');
@\header_remove('Content-Security-Policy');
@header('Content-Type: text/html; charset=utf-8');
$this->oHttp->ServerNoCache();
@ -216,7 +219,7 @@ class Service
$bAppJsDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_js', false);
$bAppCssDebug = !!$this->oActions->Config()->Get('labs', 'use_app_debug_css', false);
$sStaticPrefix = APP_WEB_STATIC_PATH;
$sStaticPrefix = $this->oServiceActions->WebStaticPath();
$aData = array(
'Language' => $sLanguage,
@ -254,7 +257,7 @@ class Service
\implode('~', array(
\md5($this->oActions->Config()->Get('cache', 'index', '')),
$this->oActions->Plugins()->Hash(),
APP_WEB_PATH, APP_VERSION
$this->oServiceActions->WebVersionPath(), APP_VERSION
)).
\implode('~', $aTemplateParameters)
);

View file

@ -675,7 +675,7 @@ class ServiceActions
if (\file_exists($sThemeFile) && \file_exists($sThemeTemplateFile) && \file_exists($sThemeValuesFile))
{
$aResult[] = '@base: "'.($bCustomTheme ? '' : APP_WEB_PATH).'themes/'.$sRealTheme.'/";';
$aResult[] = '@base: "'.($bCustomTheme ? $this->WebPath() : $this->WebVersionPath()).'themes/'.$sRealTheme.'/";';
$aResult[] = \file_get_contents($sThemeValuesFile);
$aResult[] = \file_get_contents($sThemeFile);
$aResult[] = \file_get_contents($sThemeTemplateFile);
@ -779,7 +779,7 @@ class ServiceActions
@\header('Content-Type: text/html; charset=utf-8');
return \strtr(\file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/BadBrowser.html'), array(
'{{BaseWebStaticPath}}' => APP_WEB_STATIC_PATH,
'{{BaseWebStaticPath}}' => $this->WebStaticPath(),
'{{ErrorTitle}}' => $sTitle,
'{{ErrorHeader}}' => $sTitle,
'{{ErrorDesc}}' => $sDesc
@ -1051,6 +1051,58 @@ class ServiceActions
return '';
}
/**
* @param string $sTitle
* @param string $sDesc
*
* @return mixed
*/
public function ErrorTemplates($sTitle, $sDesc, $bShowBackLink = true)
{
return strtr(file_get_contents(APP_VERSION_ROOT_PATH.'app/templates/Error.html'), array(
'{{BaseWebStaticPath}}' => $this->WebStaticPath(),
'{{ErrorTitle}}' => $sTitle,
'{{ErrorHeader}}' => $sTitle,
'{{ErrorDesc}}' => $sDesc,
'{{BackLinkVisibilityStyle}}' => $bShowBackLink ? 'display:inline-block' : 'display:none',
'{{BackLink}}' => $this->oActions->StaticI18N('STATIC/BACK_LINK'),
'{{BackHref}}' => './'
));
}
/**
* @return string
*/
public function WebPath()
{
if (isset($_ENV['RAINLOOP_OWNCLOUD']) && $_ENV['RAINLOOP_OWNCLOUD'])
{
$sUrl = $this->oHttp->GetUrl();
if ($sUrl && \preg_match('/\/index\.php\/apps\/rainloop/', $sUrl))
{
$sUrl = \preg_replace('/\/index\.php\/apps\/rainloop.+$/', '/', $sUrl);
return \rtrim(\trim($sUrl), '\//').'/apps/rainloop/app/';
}
}
return '';
}
/**
* @return string
*/
public function WebVersionPath()
{
return $this->WebPath().'rainloop/v/'.APP_VERSION.'/';
}
/**
* @return string
*/
public function WebStaticPath()
{
return $this->WebVersionPath().'static/';
}
/**
* @param string $sTitle
* @param string $sDesc

View file

@ -72,7 +72,7 @@ class Utils
$sToken = \RainLoop\Utils::GetCookie($sKey, null);
if (null === $sToken)
{
$sToken = \md5(\rand(10000, 99999).\microtime(true).APP_SALT);
$sToken = \MailSo\Base\Utils::Md5Rand(APP_SALT);
\RainLoop\Utils::SetCookie($sKey, $sToken, \time() + 60 * 60 * 24 * 30, '/', null, null, true);
}
@ -97,7 +97,7 @@ class Utils
$sToken = \RainLoop\Utils::GetCookie($sKey, null);
if (null === $sToken)
{
$sToken = \md5(\rand(10000, 99999).\microtime(true).APP_SALT);
$sToken = \MailSo\Base\Utils::Md5Rand(APP_SALT);
\RainLoop\Utils::SetCookie($sKey, $sToken, 0, '/', null, null, true);
}

View file

@ -138,5 +138,18 @@
}"></div>
</div>
</div>
<!--
<div class="control-group">
<div class="controls">
<div data-bind="component: {
name: 'Checkbox',
params: {
label: 'Allow templates',
value: capaTemplates
}
}"></div>
</div>
</div>
-->
</div>
</div>

View file

@ -16,13 +16,15 @@
</div>
<br />
<div class="control-group" data-bind="css: {'error': name.error}">
<label class="i18n" data-i18n-text="POPUPS_ADD_TEMPLATE/LABEL_NAME"></label>
<input type="text" class="inputName span6" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: name, onEnter: addTemplateCommand, hasfocus: name.focus" />
<label class="i18n control-label" data-i18n-text="POPUPS_ADD_TEMPLATE/LABEL_NAME"></label>
<div class="controls">
<input type="text" class="inputName input-xlarge" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="textInput: name, onEnter: addTemplateCommand, hasfocus: name.focus" />
</div>
</div>
<hr />
<div class="control-group" data-bind="css: {'error': body.error}">
<label class="i18n" data-i18n-text="POPUPS_ADD_TEMPLATE/LABEL_TEXT"></label>
<div class="e-body-place" data-bind="initDom: signatureDom"></div>
<div class="e-template-place" data-bind="initDom: signatureDom"></div>
</div>
</div>
</div>

View file

@ -26,9 +26,9 @@ Options -Indexes
if (file_exists(APP_INDEX_ROOT_PATH.'include.php'))
{
include_once APP_INDEX_ROOT_PATH.'include.php';
$sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : '';
}
$sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : '';
define('APP_DATA_FOLDER_PATH', 0 === strlen($sCustomDataPath) ? APP_INDEX_ROOT_PATH.'data/' : $sCustomDataPath.'/');
unset($sCustomDataPath);
@ -58,8 +58,6 @@ Options -Indexes
define('APP_REP_PATH', 'http://repository.rainloop.net/v1/');
define('APP_REPO_CORE_FILE', 'http://repository.rainloop.net/v2/core.{{channel}}.json');
define('APP_STATUS_PATH', 'http://status.rainloop.net/');
define('APP_WEB_PATH', 'rainloop/v/'.APP_VERSION.'/');
define('APP_WEB_STATIC_PATH', APP_WEB_PATH.'static/');
define('APP_DATA_FOLDER_PATH_UNIX', str_replace('\\', '/', APP_DATA_FOLDER_PATH));
$sSalt = @file_get_contents(APP_DATA_FOLDER_PATH.'SALT.php');