Merge branch 'the-djmaze:master' into master

This commit is contained in:
cm-schl 2023-03-21 09:20:15 +01:00 committed by GitHub
commit c2b7ddc76b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 135 additions and 66 deletions

View file

@ -316,5 +316,5 @@ dev_email = ""
dev_password = ""
[version]
current = "2.26.4"
current = "2.27.0"
saved = "Sun, 18 Dec 2022 22:10:48 +0000"

View file

@ -1,3 +1,57 @@
## 2.27.0 2023-03-14
## Added
- Unique attachments.zip filename
[#992](https://github.com/the-djmaze/snappymail/pull/992)
- Select next email after (re)move current
[#968](https://github.com/the-djmaze/snappymail/pull/968)
## Changed
- Improved FolderCollection handling
- MODSEQ requires 64-bit int
- Update russian language by @Akrobs
[#994](https://github.com/the-djmaze/snappymail/pull/994)
- Don't make font bigger when screen > 1400px
- Put top menu "accountPlace" inside top-system-dropdown-id
- Put attachment controls inside attachmentsPlace
- Show message toolbar on screens > 1400px
[#970](https://github.com/the-djmaze/snappymail/pull/970)
- Chinese updated by @mayswind
[#1011](https://github.com/the-djmaze/snappymail/pull/1011)
- Prevent folder/messages flags conflict by using the right name `attributes` for Folders
- FolderInformation() use jsonSerialize()
- Squire space handling on paste use `\u00A0` instead of ` ` for
[#1004](https://github.com/the-djmaze/snappymail/pull/1004)
- Better line-height for QR code
## Fixed
- Composer src is null
- Image in Signature disappears in Sent/Draft
[#932](https://github.com/the-djmaze/snappymail/pull/932)
- Mail list is empty
[#998](https://github.com/the-djmaze/snappymail/pull/998)
- Cache handling issues
[#1003](https://github.com/the-djmaze/snappymail/pull/1003)
- No message notification popup when installed in sub-directory
[#1007](https://github.com/the-djmaze/snappymail/pull/1007)
- ERROR: Undefined constant "MailSo\Log\Drivers\STDERR"
[#965](https://github.com/the-djmaze/snappymail/pull/965)
- 'Location:' headers using proper '302 Found' header
- Can't send email
[#1006](https://github.com/the-djmaze/snappymail/pull/1006)
- Attachment preview
[#1005](https://github.com/the-djmaze/snappymail/pull/1005)
- When decrypt message, subject was replaced empty
### Removed
- \MailSo\Imap\ImapClient::GetConnectedPort()
### Nextcloud
- CSS `--panel-bg-clr` was missing
- SnappyMail Menu under Nextcloud top bar
[#1017](https://github.com/the-djmaze/snappymail/pull/1017)
## 2.26.4 2023-02-24
## Added
@ -62,7 +116,6 @@
- Unused Squire code
## 2.26.2 2023-02-17
## Added

View file

@ -141,26 +141,26 @@ RainLoop 1.17 vs SnappyMail
|js/* |RainLoop |Snappy |
|--------------- |--------: |--------: |
|admin.js |2.170.153 | 78.971 |
|app.js |4.207.787 | 409.340 |
|admin.js |2.170.153 | 78.985 |
|app.js |4.207.787 | 407.112 |
|boot.js | 868.735 | 4.142 |
|libs.js | 658.812 | 185.881 |
|libs.js | 658.812 | 185.826 |
|sieve.js | 0 | 85.599 |
|polyfills.js | 334.608 | 0 |
|serviceworker.js | 0 | 285 |
|TOTAL |8.240.095 | 764.218 |
|TOTAL |8.240.095 | 761.949 |
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|admin.min.js | 256.831 | 38.936 | 73.606 | 13.036 | 60.877 | 11.694 |
|app.min.js | 515.367 | 186.883 |139.456 | 63.102 |110.485 | 54.200 |
|admin.min.js | 256.831 | 38.922 | 73.606 | 13.044 | 60.877 | 11.689 |
|app.min.js | 515.367 | 185.851 |139.456 | 62.793 |110.485 | 54.006 |
|boot.min.js | 84.659 | 2.084 | 26.998 | 1.202 | 23.643 | 1.003 |
|libs.min.js | 584.772 | 90.445 |180.901 | 33.592 |155.182 | 30.108 |
|libs.min.js | 584.772 | 90.419 |180.901 | 33.579 |155.182 | 30.112 |
|sieve.min.js | 0 | 41.525 | 0 | 10.435 | 0 | 9.401 |
|polyfills.min.js | 32.837 | 0 | 11.406 | 0 | 10.175 | 0 |
|TOTAL user |1.217.635 | 279.412 |358.761 | 97.896 |299.485 | 85.311 |
|TOTAL user+sieve |1.217.635 | 320.937 |358.761 |108.331 |299.485 | 94.712 |
|TOTAL admin | 959.099 | 131.465 |292.911 | 47.830 |249.877 | 42.805 |
|TOTAL user |1.217.635 | 278.354 |358.761 | 97.574 |299.485 | 85.121 |
|TOTAL user+sieve |1.217.635 | 319.879 |358.761 |108.009 |299.485 | 94.522 |
|TOTAL admin | 959.099 | 131.425 |292.911 | 47.825 |249.877 | 42.804 |
For a user it is around 72% smaller and faster than traditional RainLoop.
@ -189,8 +189,8 @@ For a user it is around 72% smaller and faster than traditional RainLoop.
|css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli |
|------------ |-------: |------: |------: |------: |--------: |
|app.css | 340.331 | 81.526 | 46.946 | 16.960 | 14.620 |
|app.min.css | 274.947 | 65.398 | 39.647 | 15.032 | 13.119 |
|app.css | 340.331 | 81.459 | 46.946 | 16.976 | 14.618 |
|app.min.css | 274.947 | 65.368 | 39.647 | 15.033 | 13.117 |
|boot.css | | 1.326 | | 664 | 545 |
|boot.min.css | | 1.071 | | 590 | 474 |
|admin.css | | 30.296 | | 6.939 | 6.066 |

View file

@ -4,7 +4,7 @@ import { logoutLink } from 'Common/Links';
import { i18nToNodes, initOnStartOrLangChange } from 'Common/Translator';
import { LanguageStore } from 'Stores/Language';
import { ThemeStore } from 'Stores/Theme';
import { initThemes } from 'Stores/Theme';
import { SelectComponent } from 'Component/Select';
import { CheckboxComponent } from 'Component/Checkbox';
@ -46,7 +46,7 @@ export class AbstractApp {
initOnStartOrLangChange();
LanguageStore.populate();
ThemeStore.populate();
initThemes();
this.start();
}

View file

@ -1,7 +1,7 @@
import 'External/ko';
import { Settings, SettingsGet } from 'Common/Globals';
import { ThemeStore } from 'Stores/Theme';
import { initThemes } from 'Stores/Theme';
import Remote from 'Remote/Admin/Fetch';
@ -18,7 +18,7 @@ export class AdminApp extends AbstractApp {
}
refresh() {
ThemeStore.populate();
initThemes();
this.start();
}

View file

@ -37,7 +37,7 @@ import { IdentityUserStore } from 'Stores/User/Identity';
import { FolderUserStore } from 'Stores/User/Folder';
import { PgpUserStore } from 'Stores/User/Pgp';
import { MessagelistUserStore } from 'Stores/User/Messagelist';
import { ThemeStore, changeTheme } from 'Stores/Theme';
import { ThemeStore, initThemes } from 'Stores/Theme';
import { LanguageStore } from 'Stores/Language';
import { MessageUserStore } from 'Stores/User/Message';
@ -183,7 +183,7 @@ export class AppUser extends AbstractApp {
super.bootstart();
addEventListener('beforeunload', event => {
if (arePopupsVisible() || (!SettingsUserStore.layout() && MessageUserStore.message())) {
if (arePopupsVisible() || (!SettingsUserStore.usePreviewPane() && MessageUserStore.message())) {
event.preventDefault();
return event.returnValue = i18n('POPUPS_ASK/EXIT_ARE_YOU_SURE');
}
@ -191,9 +191,8 @@ export class AppUser extends AbstractApp {
}
refresh() {
ThemeStore.populate();
initThemes();
LanguageStore.language(SettingsGet('language'));
changeTheme(SettingsGet('Theme'));
this.start();
}

View file

@ -13,10 +13,11 @@ export function MimeToMessage(data, message)
let signed;
const struct = ParseMime(data);
if (struct.headers) {
let html = struct.getByContentType('text/html');
let html = struct.getByContentType('text/html'),
subject = struct.headerValue('subject');
html = html ? html.body : '';
message.subject(struct.headerValue('subject') || '');
subject && message.subject(subject);
// EmailCollectionModel
['from','to'].forEach(name => message[name].fromString(struct.headerValue(name)));

View file

@ -19,23 +19,25 @@ export const
fontSansSerif: ko.observable(''),
fontSerif: ko.observable(''),
fontMono: ko.observable(''),
isMobile: ko.observable(false),
isMobile: ko.observable(false)
},
populate: () => {
const themes = Settings.app('themes');
initThemes = () => {
const theme = SettingsGet('Theme'),
themes = Settings.app('themes');
ThemeStore.themes(isArray(themes) ? themes : []);
ThemeStore.theme(SettingsGet('Theme'));
if (!ThemeStore.isMobile()) {
ThemeStore.userBackgroundName(SettingsGet('userBackgroundName'));
ThemeStore.userBackgroundHash(SettingsGet('userBackgroundHash'));
}
ThemeStore.fontSansSerif(SettingsGet('fontSansSerif'));
ThemeStore.fontSerif(SettingsGet('fontSerif'));
ThemeStore.fontMono(SettingsGet('fontMono'));
leftPanelDisabled(ThemeStore.isMobile());
ThemeStore.themes(isArray(themes) ? themes : []);
ThemeStore.theme(theme);
changeTheme(theme);
if (!ThemeStore.isMobile()) {
ThemeStore.userBackgroundName(SettingsGet('userBackgroundName'));
ThemeStore.userBackgroundHash(SettingsGet('userBackgroundHash'));
}
ThemeStore.fontSansSerif(SettingsGet('fontSansSerif'));
ThemeStore.fontSerif(SettingsGet('fontSerif'));
ThemeStore.fontMono(SettingsGet('fontMono'));
leftPanelDisabled(ThemeStore.isMobile());
},
changeTheme = (value, themeTrigger = ()=>0) => {

View file

@ -50,10 +50,10 @@ export const SettingsUserStore = new class {
self.init();
self.usePreviewPane = koComputable(() => self.layout() && !ThemeStore.isMobile());
self.usePreviewPane = koComputable(() => ThemeStore.isMobile() ? 0 : self.layout());
const toggleLayout = () => {
const value = ThemeStore.isMobile() ? 0 : self.layout();
const value = self.usePreviewPane();
$htmlCL.toggle('sm-msgView-side', Layout.SidePreview === value);
$htmlCL.toggle('sm-msgView-bottom', Layout.BottomPreview === value);
fireEvent('rl-layout', value);

View file

@ -50,7 +50,7 @@
.accountPlace {
border-right: 1px solid var(--btn-border-clr, rgba(0, 0, 0, 0.2));
display: inline-block;
font-weight: bold;
font-weight: 600;
font-size: 16px;
line-height: 22px;
margin: 0 6px -3px 0;

View file

@ -801,7 +801,7 @@ export class ComposePopupView extends AbstractViewPopup {
}
if (msgComposeType && message) {
sDate = timestampToString(message.dateTimeStampInUTC(), 'FULL');
sDate = timestampToString(message.dateTimestamp(), 'FULL');
sSubject = message.subject();
aDraftInfo = message.draftInfo;

View file

@ -566,11 +566,9 @@ export class MailMessageList extends AbstractViewRight {
// initMailboxLayoutResizer
const top = dom.querySelector('.messageList'),
fToggle = () => {
let layout = SettingsUserStore.layout();
let layout = SettingsUserStore.usePreviewPane();
setLayoutResizer(top, ClientSideKeyNameMessageListSize,
(ThemeStore.isMobile() || !layout)
? 0
: (Layout.SidePreview === layout ? 'Width' : 'Height')
layout ? (Layout.SidePreview === layout ? 'Width' : 'Height') : 0
);
};
if (top) {

View file

@ -1,4 +1,4 @@
This app packages SnappyMail <upstream>2.26.4</upstream>.
This app packages SnappyMail <upstream>2.27.0</upstream>.
SnappyMail is a simple, modern, lightweight & fast web-based email client.

View file

@ -4,7 +4,7 @@ RUN mkdir -p /app/code
WORKDIR /app/code
# If you change the extraction below, be sure to test on scaleway
VERSION=2.26.4
VERSION=2.27.0
RUN wget https://github.com/the-djmaze/snappymail/releases/download/v${VERSION}/snappymail-${VERSION}.zip -O /tmp/snappymail.zip && \
unzip /tmp/snappymail.zip -d /app/code && \
rm /tmp/snappymail.zip && \

View file

@ -87,6 +87,8 @@
--border-radius: var(--border-radius);
--hr-color: var(--color-border);
--panel-bg-clr: var(--color-main-background);
--warning-clr: var(--color-warning);
--warning-bg-clr: #fcf8e3;
--warning-border-clr: #fbeed5;

View file

@ -3,7 +3,7 @@
<id>snappymail</id>
<name>SnappyMail</name>
<summary>SnappyMail Webmail</summary>
<version>2.26.4</version>
<version>2.27.0</version>
<licence>agpl</licence>
<author>SnappyMail, RainLoop Team, Nextgen-Networks, Tab Fitts, Nathan Kinkade, Pierre-Alain Bandinelli</author>
<description><![CDATA[**Simple, modern, lightweight & fast web-based email client.**

View file

@ -120,3 +120,9 @@ a.selectable::after {
padding-top: 0;
}
}
@media screen and (max-width: 799px) {
#body-user #rl-left {
top: 50px;
}
}

View file

@ -20,7 +20,7 @@ return "SnappyMail Webmail is a browser-based multilingual IMAP client with an a
# script_snappymail_versions()
sub script_snappymail_versions
{
return ( "2.26.4" );
return ( "2.27.0" );
}
sub script_snappymail_version_desc

View file

@ -3,7 +3,7 @@
"title": "SnappyMail",
"description": "Simple, modern & fast web-based email client",
"private": true,
"version": "2.26.4",
"version": "2.27.0",
"homepage": "https://snappymail.eu",
"author": {
"name": "DJ Maze",

View file

@ -4,8 +4,8 @@ class NextcloudPlugin extends \RainLoop\Plugins\AbstractPlugin
{
const
NAME = 'Nextcloud',
VERSION = '2.20',
RELEASE = '2023-02-22',
VERSION = '2.21',
RELEASE = '2023-03-18',
CATEGORY = 'Integrations',
DESCRIPTION = 'Integrate with Nextcloud v20+',
REQUIRED = '2.25.1';

View file

@ -6,3 +6,6 @@ SELECT_FOLDER = "Select folder"
SELECT_FILES = "Select file(s)"
ATTACH_FILES = "Attach Nextcloud files"
SELECT_CALENDAR = "Select calendar"
FILE_ATTACH = "attach"
FILE_INTERNAL = "internal"
FILE_PUBLIC = "public"

View file

@ -6,3 +6,6 @@ SELECT_FOLDER = "选择文件夹"
SELECT_FILES = "选择文件"
ATTACH_FILES = "添加 Nextcloud 文件"
SELECT_CALENDAR = "选择日历"
FILE_ATTACH = "attach"
FILE_INTERNAL = "internal"
FILE_PUBLIC = "public"

View file

@ -12,7 +12,7 @@
<ul id="sm-nc-files-tree"></ul>
</div>
<footer data-bind="visible:files">
<button data-bind="click:attach" name="select" data-icon="📎" class="button-vue">attach</button>
<button data-bind="click:shareInternal" name="share-internal" data-icon="🔗" class="button-vue">internal</button>
<button data-bind="click:sharePublic" name="share-public" data-icon="🔗" class="button-vue">public</button>
<button data-bind="click:attach" name="select" data-icon="📎" class="button-vue" data-i18n="NEXTCLOUD/FILE_ATTACH">attach</button>
<button data-bind="click:shareInternal" name="share-internal" data-icon="🔗" class="button-vue" data-i18n="NEXTCLOUD/FILE_INTERNAL">internal</button>
<button data-bind="click:sharePublic" name="share-public" data-icon="🔗" class="button-vue" data-i18n="NEXTCLOUD/FILE_PUBLIC">public</button>
</footer>

View file

@ -47,7 +47,7 @@
<blockquote>
<p class="muted width100-on-mobile" style="width: 550px" data-i18n="PLUGIN_2FA/TWO_FACTOR_SECRET_DESC"></p>
</blockquote>
<pre data-bind="text: viewQRCode" style="line-height:1;letter-spacing:-1px;font-family:monospace"></pre>
<pre data-bind="text: viewQRCode" style="line-height:1.1;letter-spacing:-1px;font-family:monospace"></pre>
</div>
</div>
<div class="control-group" data-bind="visible: '' !== viewBackupCodes()">

View file

@ -61,6 +61,8 @@ abstract class Service
} else {
\ob_start('ob_gzhandler');
}
} else {
\ob_start();
}
$sQuery = \trim($_SERVER['QUERY_STRING'] ?? '');
@ -110,7 +112,6 @@ abstract class Service
}
$bIndex = true;
$sResult = '';
if (\count($aPaths) && !empty($aPaths[0]) && 'index' !== \strtolower($aPaths[0])) {
if ('mailto' !== \strtolower($aPaths[0]) && !\SnappyMail\HTTP\SecFetch::matchAnyRule($oConfig->Get('security', 'secfetch_allow', ''))) {
\MailSo\Base\Http::StatusHeader(403);
@ -123,15 +124,15 @@ abstract class Service
return false;
}
$bIndex = false;
$sMethodName = 'Service'.\preg_replace('/@.+$/', '', $aPaths[0]);
$sMethodExtra = \strpos($aPaths[0], '@') ? \preg_replace('/^[^@]+@/', '', $aPaths[0]) : '';
if (\method_exists($oServiceActions, $sMethodName) && \is_callable(array($oServiceActions, $sMethodName))) {
$bIndex = false;
$oServiceActions->SetQuery($sQuery)->SetPaths($aPaths);
$sResult = $oServiceActions->{$sMethodName}($sMethodExtra);
} else if (!$oActions->Plugins()->RunAdditionalPart($aPaths[0], $aPaths)) {
$bIndex = true;
echo $oServiceActions->{$sMethodName}($sMethodExtra);
} else if ($oActions->Plugins()->RunAdditionalPart($aPaths[0], $aPaths)) {
$bIndex = false;
}
}
@ -196,6 +197,8 @@ abstract class Service
$oActions->verifyCacheByKey($sCacheFileName);
if ($oConfig->Get('cache', 'system_data', true)) {
$sResult = $oActions->Cacher()->Get($sCacheFileName);
} else {
$sResult = '';
}
if ($sResult) {
@ -232,14 +235,13 @@ abstract class Service
static::setCSP(null, $sScriptHash);
*/
$oActions->cacheByKey($sCacheFileName);
echo $sResult;
unset($sResult);
} else if (!\headers_sent()) {
\header('X-XSS-Protection: 1; mode=block');
}
// Output result
echo $sResult;
unset($sResult);
$oActions->BootEnd();
return true;