mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 15:45:55 +08:00
Merge pull request #1247 from SergeyMosin/some-improvements
Some improvements
This commit is contained in:
commit
4cc1e8429e
|
@ -116,7 +116,8 @@ export const FileType = {
|
||||||
Spreadsheet: 'spreadsheet',
|
Spreadsheet: 'spreadsheet',
|
||||||
Presentation: 'presentation',
|
Presentation: 'presentation',
|
||||||
Certificate: 'certificate',
|
Certificate: 'certificate',
|
||||||
Archive: 'archive'
|
Archive: 'archive',
|
||||||
|
Calendar: 'calendar'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FileInfo = {
|
export const FileInfo = {
|
||||||
|
@ -190,6 +191,9 @@ export const FileInfo = {
|
||||||
case 'eml' == ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType):
|
case 'eml' == ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType):
|
||||||
result = FileType.Eml;
|
result = FileType.Eml;
|
||||||
break;
|
break;
|
||||||
|
case 'ics' == ext || mimeType == 'text/calendar':
|
||||||
|
result = FileType.Calendar;
|
||||||
|
break;
|
||||||
case 'text' == mimeTypeParts[0] || 'txt' == ext || 'log' == ext:
|
case 'text' == mimeTypeParts[0] || 'txt' == ext || 'log' == ext:
|
||||||
result = FileType.Text;
|
result = FileType.Text;
|
||||||
break;
|
break;
|
||||||
|
@ -240,6 +244,7 @@ export const FileInfo = {
|
||||||
case FileType.Certificate:
|
case FileType.Certificate:
|
||||||
case FileType.Spreadsheet:
|
case FileType.Spreadsheet:
|
||||||
case FileType.Presentation:
|
case FileType.Presentation:
|
||||||
|
case FileType.Calendar:
|
||||||
return result + '-' + fileType;
|
return result + '-' + fileType;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -165,7 +165,9 @@ export class EmailAddressesComponent {
|
||||||
|
|
||||||
_parseInput(force) {
|
_parseInput(force) {
|
||||||
let val = this.input.value;
|
let val = this.input.value;
|
||||||
if ((force || val.includes(',') || val.includes(';')) && this._parseValue(val)) {
|
if ((force || val.includes(',') || val.includes(';')
|
||||||
|
|| (val.charAt(val.length-1)===' ' && this._simpleEmailMatch(val)))
|
||||||
|
&& this._parseValue(val)) {
|
||||||
this.input.value = '';
|
this.input.value = '';
|
||||||
}
|
}
|
||||||
this._resizeInput();
|
this._resizeInput();
|
||||||
|
@ -284,6 +286,13 @@ export class EmailAddressesComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_simpleEmailMatch(value) {
|
||||||
|
// A very SIMPLE test to check if the value might be an email
|
||||||
|
const val = value.trim();
|
||||||
|
return /^[^@]*<[^\s@]{1,128}@[^\s@]{1,256}\.[\w]{2,32}>$/g.test(val)
|
||||||
|
|| /^[^\s@]{1,128}@[^\s@]{1,256}\.[\w]{2,32}$/g.test(val);
|
||||||
|
}
|
||||||
|
|
||||||
_renderTags() {
|
_renderTags() {
|
||||||
let self = this;
|
let self = this;
|
||||||
[...self.ul.children].forEach(node => node !== self.inputCont && node.remove());
|
[...self.ul.children].forEach(node => node !== self.inputCont && node.remove());
|
||||||
|
|
|
@ -493,6 +493,19 @@ export class ComposePopupView extends AbstractViewPopup {
|
||||||
|| getNotification(Notifications.CantSendMessage));
|
|| getNotification(Notifications.CantSendMessage));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (arrayLength(this.aDraftInfo) > 0) {
|
||||||
|
const flag = {
|
||||||
|
'reply': '\\answered',
|
||||||
|
'forward': '$forwarded'
|
||||||
|
}[this.aDraftInfo[0]];
|
||||||
|
if (flag) {
|
||||||
|
const aFlags = MessageUserStore.message().flags();
|
||||||
|
if (aFlags.indexOf(flag) === -1) {
|
||||||
|
aFlags.push(flag);
|
||||||
|
MessageUserStore.message().flags(aFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
setFolderETag(this.draftsFolder(), '');
|
setFolderETag(this.draftsFolder(), '');
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import { ScopeFolderList, ScopeMessageList } from 'Common/Enums';
|
import { ScopeFolderList, ScopeMessageList } from 'Common/Enums';
|
||||||
import { addShortcut, stopEvent } from 'Common/Globals';
|
import { addShortcut, leftPanelDisabled, stopEvent } from 'Common/Globals';
|
||||||
import { mailBox, settings } from 'Common/Links';
|
import { mailBox, settings } from 'Common/Links';
|
||||||
//import { setFolderETag } from 'Common/Cache';
|
//import { setFolderETag } from 'Common/Cache';
|
||||||
import { addComputablesTo } from 'External/ko';
|
import { addComputablesTo } from 'External/ko';
|
||||||
|
@ -21,6 +21,7 @@ import { ContactsPopupView } from 'View/Popup/Contacts';
|
||||||
import { ComposePopupView } from 'View/Popup/Compose';
|
import { ComposePopupView } from 'View/Popup/Compose';
|
||||||
|
|
||||||
import { setExpandedFolder, foldersFilter } from 'Model/FolderCollection';
|
import { setExpandedFolder, foldersFilter } from 'Model/FolderCollection';
|
||||||
|
import { ThemeStore } from '../../../Stores/Theme';
|
||||||
|
|
||||||
export class MailFolderList extends AbstractViewLeft {
|
export class MailFolderList extends AbstractViewLeft {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -112,6 +113,9 @@ export class MailFolderList extends AbstractViewLeft {
|
||||||
search = 'unseen';
|
search = 'unseen';
|
||||||
}
|
}
|
||||||
hasher.setHash(mailBox(folder.fullNameHash, 1, search));
|
hasher.setHash(mailBox(folder.fullNameHash, 1, search));
|
||||||
|
|
||||||
|
// in mobile mode hide the panel when a folder is clicked
|
||||||
|
ThemeStore.isMobile() && leftPanelDisabled()===false && leftPanelDisabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppUserStore.focusedState(ScopeMessageList);
|
AppUserStore.focusedState(ScopeMessageList);
|
||||||
|
|
|
@ -86,7 +86,8 @@ class Application extends App implements IBootstrap
|
||||||
// https://github.com/nextcloud/server/issues/36083#issuecomment-1387370634
|
// https://github.com/nextcloud/server/issues/36083#issuecomment-1387370634
|
||||||
// \OC::$server->getSession()['snappymail-password'] = '';
|
// \OC::$server->getSession()['snappymail-password'] = '';
|
||||||
SnappyMailHelper::loadApp();
|
SnappyMailHelper::loadApp();
|
||||||
\RainLoop\Api::Actions()->Logout(true);
|
// \RainLoop\Api::Actions()->Logout(true);
|
||||||
|
\RainLoop\Api::Actions()->DoLogout();
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://github.com/nextcloud/impersonate/issues/179
|
// https://github.com/nextcloud/impersonate/issues/179
|
||||||
|
|
|
@ -80,7 +80,9 @@ class SnappyMailHelper
|
||||||
if ($doLogin && $aCredentials[1] && $aCredentials[2]) {
|
if ($doLogin && $aCredentials[1] && $aCredentials[2]) {
|
||||||
try {
|
try {
|
||||||
$oActions->Logger()->AddSecret($aCredentials[2]);
|
$oActions->Logger()->AddSecret($aCredentials[2]);
|
||||||
$oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], false);
|
|
||||||
|
$bSignMe = $oConfig->Get('login', 'sign_me_auto', \RainLoop\Enumerations\SignMeType::DEFAULT_OFF) === \RainLoop\Enumerations\SignMeType::DEFAULT_ON;
|
||||||
|
$oAccount = $oActions->LoginProcess($aCredentials[1], $aCredentials[2], $bSignMe);
|
||||||
if ($oAccount) {
|
if ($oAccount) {
|
||||||
$oActions->Plugins()->RunHook('login.success', array($oAccount));
|
$oActions->Plugins()->RunHook('login.success', array($oAccount));
|
||||||
$oActions->SetAuthToken($oAccount);
|
$oActions->SetAuthToken($oAccount);
|
||||||
|
|
|
@ -679,16 +679,17 @@ class Actions
|
||||||
|
|
||||||
'contactsAllowed' => $this->AddressBookProvider($oAccount)->IsActive(),
|
'contactsAllowed' => $this->AddressBookProvider($oAccount)->IsActive(),
|
||||||
|
|
||||||
|
'allowSpellcheck' => $oConfig->Get('defaults', 'allow_spellcheck', false),
|
||||||
'ViewHTML' => (bool) $oConfig->Get('defaults', 'view_html', true),
|
'ViewHTML' => (bool) $oConfig->Get('defaults', 'view_html', true),
|
||||||
'ViewImages' => $oConfig->Get('defaults', 'view_images', 'ask'),
|
'ViewImages' => $oConfig->Get('defaults', 'view_images', 'ask'),
|
||||||
'ViewImagesWhitelist' => '',
|
'ViewImagesWhitelist' => '',
|
||||||
'RemoveColors' => (bool) $oConfig->Get('defaults', 'remove_colors', false),
|
'RemoveColors' => (bool) $oConfig->Get('defaults', 'remove_colors', false),
|
||||||
'AllowStyles' => false,
|
'AllowStyles' => false,
|
||||||
'ListInlineAttachments' => false,
|
'ListInlineAttachments' => false,
|
||||||
'CollapseBlockquotes' => true,
|
'CollapseBlockquotes' => $oConfig->Get('defaults', 'collapse_blockquotes', true),
|
||||||
'MaxBlockquotesLevel' => 0,
|
'MaxBlockquotesLevel' => 0,
|
||||||
'simpleAttachmentsList' => false,
|
'simpleAttachmentsList' => false,
|
||||||
'listGrouped' => false,
|
'listGrouped' => $oConfig->Get('defaults', 'mail_list_grouped', false),
|
||||||
'MessagesPerPage' => (int) $oConfig->Get('webmail', 'messages_per_page', 25),
|
'MessagesPerPage' => (int) $oConfig->Get('webmail', 'messages_per_page', 25),
|
||||||
'MessageReadDelay' => (int) $oConfig->Get('webmail', 'message_read_delay', 5),
|
'MessageReadDelay' => (int) $oConfig->Get('webmail', 'message_read_delay', 5),
|
||||||
'MsgDefaultAction' => (int) $oConfig->Get('defaults', 'msg_default_action', 1),
|
'MsgDefaultAction' => (int) $oConfig->Get('defaults', 'msg_default_action', 1),
|
||||||
|
@ -773,7 +774,7 @@ class Actions
|
||||||
$aResult['requireTLS'] = (bool) $oSettings->GetConf('requireTLS', false);
|
$aResult['requireTLS'] = (bool) $oSettings->GetConf('requireTLS', false);
|
||||||
$aResult['pgpSign'] = (bool) $oSettings->GetConf('pgpSign', false);
|
$aResult['pgpSign'] = (bool) $oSettings->GetConf('pgpSign', false);
|
||||||
$aResult['pgpEncrypt'] = (bool) $oSettings->GetConf('pgpEncrypt', false);
|
$aResult['pgpEncrypt'] = (bool) $oSettings->GetConf('pgpEncrypt', false);
|
||||||
$aResult['allowSpellcheck'] = (bool) $oSettings->GetConf('allowSpellcheck', false);
|
$aResult['allowSpellcheck'] = (bool) $oSettings->GetConf('allowSpellcheck', $aResult['allowSpellcheck']);
|
||||||
// $aResult['allowCtrlEnterOnCompose'] = (bool) $oSettings->GetConf('allowCtrlEnterOnCompose', true);
|
// $aResult['allowCtrlEnterOnCompose'] = (bool) $oSettings->GetConf('allowCtrlEnterOnCompose', true);
|
||||||
|
|
||||||
$aResult['ViewHTML'] = (bool)$oSettings->GetConf('ViewHTML', $aResult['ViewHTML']);
|
$aResult['ViewHTML'] = (bool)$oSettings->GetConf('ViewHTML', $aResult['ViewHTML']);
|
||||||
|
|
|
@ -139,7 +139,14 @@ trait UserAuth
|
||||||
|
|
||||||
$this->imapConnect($oAccount, true);
|
$this->imapConnect($oAccount, true);
|
||||||
if ($bMainAccount) {
|
if ($bMainAccount) {
|
||||||
$bSignMe && $this->SetSignMeToken($oAccount);
|
if($bSignMe){
|
||||||
|
// SetAuthToken token needs to be called before SetSignMeToken
|
||||||
|
// because $_COOKIE['smctoken'] is used by Crypt::Passphrase.
|
||||||
|
// If the $_COOKIE['smctoken'] is not set then SetSignMeToken
|
||||||
|
// throws an exception
|
||||||
|
$this->SetAuthToken($oAccount);
|
||||||
|
$this->SetSignMeToken($oAccount);
|
||||||
|
}
|
||||||
$this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true');
|
$this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -301,10 +301,13 @@ Values:
|
||||||
"match" - whitelist or ask
|
"match" - whitelist or ask
|
||||||
"always" - show always'),
|
"always" - show always'),
|
||||||
'contacts_autosave' => array(true),
|
'contacts_autosave' => array(true),
|
||||||
'mail_use_threads' => array(false),
|
'mail_list_grouped' => array(false),
|
||||||
|
'mail_use_threads' => array(false),
|
||||||
'allow_draft_autosave' => array(true),
|
'allow_draft_autosave' => array(true),
|
||||||
'mail_reply_same_folder' => array(false),
|
'mail_reply_same_folder' => array(false),
|
||||||
'msg_default_action' => array(1, '1 - reply, 2 - reply all'),
|
'msg_default_action' => array(1, '1 - reply, 2 - reply all'),
|
||||||
|
'collapse_blockquotes' => array(true),
|
||||||
|
'allow_spellcheck' => array(false)
|
||||||
),
|
),
|
||||||
|
|
||||||
'logs' => array(
|
'logs' => array(
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Cookies
|
||||||
if ($cookie_remove) {
|
if ($cookie_remove) {
|
||||||
\header_remove('Set-Cookie');
|
\header_remove('Set-Cookie');
|
||||||
foreach ($cookies as $cookie) {
|
foreach ($cookies as $cookie) {
|
||||||
\header($cookie);
|
\header($cookie,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,14 +118,14 @@ class Cookies
|
||||||
foreach (\str_split($sValue, $iMaxSize) as $i => $sPart) {
|
foreach (\str_split($sValue, $iMaxSize) as $i => $sPart) {
|
||||||
$sCookieName = $i ? "{$sName}~{$i}" : $sName;
|
$sCookieName = $i ? "{$sName}~{$i}" : $sName;
|
||||||
Log::debug('COOKIE', "set {$sCookieName}");
|
Log::debug('COOKIE', "set {$sCookieName}");
|
||||||
static::_set($sCookieName, $sPart, $iExpire);
|
static::_set($sCookieName, $sPart, $iExpire, $httponly);
|
||||||
}
|
}
|
||||||
// Delete unused old 4K split cookie parts
|
// Delete unused old 4K split cookie parts
|
||||||
foreach (\array_keys($_COOKIE) as $sCookieName) {
|
foreach (\array_keys($_COOKIE) as $sCookieName) {
|
||||||
$aSplit = \explode('~', $sCookieName);
|
$aSplit = \explode('~', $sCookieName);
|
||||||
if (isset($aSplit[1]) && $aSplit[0] == $sName && $aSplit[1] > $i) {
|
if (isset($aSplit[1]) && $aSplit[0] == $sName && $aSplit[1] > $i) {
|
||||||
Log::debug('COOKIE', "unset {$sCookieName}");
|
Log::debug('COOKIE', "unset {$sCookieName}");
|
||||||
static::_set($sCookieName, '', 0);
|
static::_set($sCookieName, '', 0, $httponly);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,6 +254,7 @@
|
||||||
"TITLE_UPDATE_IDENTITY": "Update Identity?",
|
"TITLE_UPDATE_IDENTITY": "Update Identity?",
|
||||||
"BUTTON_ADD_IDENTITY": "Add",
|
"BUTTON_ADD_IDENTITY": "Add",
|
||||||
"BUTTON_UPDATE_IDENTITY": "Update",
|
"BUTTON_UPDATE_IDENTITY": "Update",
|
||||||
|
"LABEL_SIGNATURE_ADD": "Add/Edit signature",
|
||||||
"LABEL_SIGNATURE_INSERT_BEFORE": "Insert this signature before quoted text in replies"
|
"LABEL_SIGNATURE_INSERT_BEFORE": "Insert this signature before quoted text in replies"
|
||||||
},
|
},
|
||||||
"POPUPS_CREATE_FOLDER": {
|
"POPUPS_CREATE_FOLDER": {
|
||||||
|
|
|
@ -130,7 +130,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td data-i18n="GLOBAL/SUBJECT"></div>
|
<td data-i18n="GLOBAL/SUBJECT"></div>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" name="subject" autocomplete="off" data-bind="textInput: subject">
|
<input type="text" name="subject" autocomplete="off" data-bind="textInput: subject, attr:{spellcheck:allowSpellcheck()?'true':'false'}">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="control-group g-ui-user-select-none">
|
<div class="control-group g-ui-user-select-none">
|
||||||
|
<h4 data-i18n="POPUPS_IDENTITY/LABEL_SIGNATURE_ADD"></h4>
|
||||||
<div data-bind="component: {
|
<div data-bind="component: {
|
||||||
name: 'Checkbox',
|
name: 'Checkbox',
|
||||||
params: {
|
params: {
|
||||||
|
|
3
vendors/fontastic/styles.css
vendored
3
vendors/fontastic/styles.css
vendored
|
@ -106,3 +106,6 @@
|
||||||
.icon-check-mark-circle-two::before {
|
.icon-check-mark-circle-two::before {
|
||||||
content: "\e073";
|
content: "\e073";
|
||||||
}
|
}
|
||||||
|
.icon-file-calendar::before {
|
||||||
|
content: "📅";
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue