mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-09-26 15:04:36 +08:00
#89 send encrypted using Mailvelope
This commit is contained in:
parent
edc035fc13
commit
0dffa549be
5 changed files with 170 additions and 104 deletions
|
@ -67,6 +67,15 @@ export const PgpUserStore = new class {
|
||||||
return !!(OpenPGPUserStore.isSupported() || GnuPGUserStore.isSupported() || window.mailvelope);
|
return !!(OpenPGPUserStore.isSupported() || GnuPGUserStore.isSupported() || window.mailvelope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async mailvelopeHasPublicKeyForEmails(recipients, all) {
|
||||||
|
const
|
||||||
|
keyring = this.mailvelopeKeyring,
|
||||||
|
mailvelope = keyring && await keyring.validKeyForAddress(recipients)
|
||||||
|
/*.then(LookupResult => Object.entries(LookupResult))*/,
|
||||||
|
entries = mailvelope && Object.entries(mailvelope);
|
||||||
|
return !!(entries && (all ? (entries.filter(value => value[1]).length === recipients.length) : entries.length));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if verifying/encrypting a message is possible with given email addresses.
|
* Checks if verifying/encrypting a message is possible with given email addresses.
|
||||||
* Returns the first library that can.
|
* Returns the first library that can.
|
||||||
|
@ -82,11 +91,7 @@ export const PgpUserStore = new class {
|
||||||
return 'gnupg';
|
return 'gnupg';
|
||||||
}
|
}
|
||||||
|
|
||||||
let keyring = this.mailvelopeKeyring,
|
if (await this.mailvelopeHasPublicKeyForEmails(recipients, all)) {
|
||||||
mailvelope = keyring && await keyring.validKeyForAddress(recipients)
|
|
||||||
/*.then(LookupResult => Object.entries(LookupResult))*/;
|
|
||||||
mailvelope = mailvelope && Object.entries(mailvelope);
|
|
||||||
if (mailvelope && (all ? (mailvelope.filter(([, value]) => value).length === count) : mailvelope.length)) {
|
|
||||||
return 'mailvelope';
|
return 'mailvelope';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,52 +202,29 @@ export const PgpUserStore = new class {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an iframe with an editor for a new encrypted mail.
|
|
||||||
* The iframe will be injected into the container identified by selector.
|
|
||||||
* https://mailvelope.github.io/mailvelope/Editor.html
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
mailvelope.createEditorContainer(selector, this.mailvelopeKeyring, {
|
|
||||||
quota: 20480, // mail content (text + attachments) limit in kilobytes (default: 20480)
|
|
||||||
signMsg: false, // if true then the mail will be signed (default: false)
|
|
||||||
armoredDraft: '', // Ascii Armored PGP Text Block
|
|
||||||
a PGP message, signed and encrypted with the default key of the user, will be used to restore a draft in the editor
|
|
||||||
The armoredDraft parameter can't be combined with the parameters: predefinedText, quotedMail... parameters, keepAttachments
|
|
||||||
predefinedText: '', // text that will be added to the editor
|
|
||||||
quotedMail: '', // Ascii Armored PGP Text Block mail that should be quoted
|
|
||||||
quotedMailIndent: true, // if true the quoted mail will be indented (default: true)
|
|
||||||
quotedMailHeader: '', // header to be added before the quoted mail
|
|
||||||
keepAttachments: false, // add attachments of quotedMail to editor (default: false)
|
|
||||||
}).then(editor => {
|
|
||||||
editor.editorId;
|
|
||||||
}, error_handler)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns headers that should be added to an outgoing email.
|
* Returns headers that should be added to an outgoing email.
|
||||||
* So far this is only the autocrypt header.
|
* So far this is only the autocrypt header.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
this.mailvelopeKeyring.additionalHeadersForOutgoingEmail(headers)
|
this.mailvelopeKeyring.additionalHeadersForOutgoingEmail(headers)
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
this.mailvelopeKeyring.addSyncHandler(syncHandlerObj)
|
this.mailvelopeKeyring.addSyncHandler(syncHandlerObj)
|
||||||
*/
|
this.mailvelopeKeyring.createKeyBackupContainer(selector, options)
|
||||||
/*
|
|
||||||
this.mailvelopeKeyring.createKeyGenContainer(selector, {
|
this.mailvelopeKeyring.createKeyGenContainer(selector, {
|
||||||
// userIds: [],
|
// userIds: [],
|
||||||
keySize: 4096
|
keySize: 4096
|
||||||
})
|
})
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
exportOwnPublicKey(emailAddr).then(<AsciiArmored, Error>)
|
|
||||||
|
|
||||||
this.mailvelopeKeyring.hasPrivateKey(fingerprint)
|
|
||||||
|
|
||||||
|
this.mailvelopeKeyring.exportOwnPublicKey(emailAddr).then(<AsciiArmored, Error>)
|
||||||
this.mailvelopeKeyring.importPublicKey(armored)
|
this.mailvelopeKeyring.importPublicKey(armored)
|
||||||
|
|
||||||
|
// https://mailvelope.github.io/mailvelope/global.html#SyncHandlerObject
|
||||||
|
this.mailvelopeKeyring.addSyncHandler({
|
||||||
|
uploadSync
|
||||||
|
downloadSync
|
||||||
|
backup
|
||||||
|
restore
|
||||||
|
});
|
||||||
*/
|
*/
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,11 @@
|
||||||
|
|
||||||
|
.mailvelope-icon {
|
||||||
|
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACjElEQVQ4y2XTXWjVdRgH8M/vf457OUVJzc7U5myWmysrFROKjFyUgqasEsNIrFFetC5KYkXMdVP0chne1MVWUBGWnlAKcogLJmiGXciUkaPtHPYSWumo6XbOv4v/afbyXP14+H6/z8vv+Qb/iNijEdFK4p1Yh1sQ4WccJe4h9Ae54t+ccJW88VpSb+NZdZWVmm+muR4xgwVODzM0dQWfEb0Q7L80KxDbmCH6irDO82uCHZvIVJMfT9Tn11Askevlnd7YdOk4xYeCg5PpBBG9R2gB9bXkjrD/GIXLSYlsBetX0NZK/cLgue41pLrxeIhtuZP4R6uyvPoEVdUcOMKH3/tf3FXDx6/x6de89W1MfH+qS2MnxdVynYyeZzDPM1sYHeH2LJMX2XAHjTfSN8zkOO1P8v6hQLQgjRZLarlhLk/vxTW0b6XjKaoqmJomjslUsrqPjn28tIOVi/lh+O4Ii61dQmEs2WnrUobHad3DR4eoruCxPXz+DQ+sSDAD51jbBDdFYKZ0dc4Hl5EvkJ/itiwjBfKXqath4tfyn8ekEmqEIf3nWJBFKRml/3QCzFzH4VPl/Dy+G0jyyxroOwMTafT6aazJxUlefpjXe7gwnbTa2c0v5ff5C2y+l/saSQdODCGcSnVpzJPaJT0ZtG+j9ySDvyeVfpvhSpwInDzL8vnJZb7yAaN/ILSl3nB2vEtTjRP5eyzKsHs7188wMZaQ5wQWVbFpFQ31bN/L6J+wL8i9W77Emd2kb9XxxSMK48HW9WzbwMhYsrDaeZRKfHkYUYzjlHb+x0ytVRTfxC51ldWaF7K0jjkpzuQZmDXTJxRfDA5e+pdAIrI5Il5OaEMLGsqYsp31EI4FB2bt/Bf/WNuibWZY5gAAAABJRU5ErkJggg==') center/contain no-repeat;
|
||||||
|
display: inline-block;
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
#V-PopupsCompose {
|
#V-PopupsCompose {
|
||||||
height: calc(100vh - 52px);
|
height: calc(100vh - 52px);
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
|
|
|
@ -14,14 +14,14 @@ import {
|
||||||
|
|
||||||
import { inFocus, pInt, isArray, arrayLength, forEachObjectEntry } from 'Common/Utils';
|
import { inFocus, pInt, isArray, arrayLength, forEachObjectEntry } from 'Common/Utils';
|
||||||
import { delegateRunOnDestroy, initFullscreen } from 'Common/UtilsUser';
|
import { delegateRunOnDestroy, initFullscreen } from 'Common/UtilsUser';
|
||||||
import { encodeHtml, HtmlEditor } from 'Common/Html';
|
import { encodeHtml, HtmlEditor, htmlToPlain } from 'Common/Html';
|
||||||
|
|
||||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||||
import { serverRequest } from 'Common/Links';
|
import { serverRequest } from 'Common/Links';
|
||||||
import { i18n, getNotification, getUploadErrorDescByCode } from 'Common/Translator';
|
import { i18n, getNotification, getUploadErrorDescByCode } from 'Common/Translator';
|
||||||
import { timestampToString } from 'Common/Momentor';
|
import { timestampToString } from 'Common/Momentor';
|
||||||
import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
|
import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
|
||||||
import { doc, Settings, SettingsGet, getFullscreenElement, exitFullscreen } from 'Common/Globals';
|
import { doc, Settings, SettingsGet, getFullscreenElement, exitFullscreen, elementById } from 'Common/Globals';
|
||||||
|
|
||||||
import { AppUserStore } from 'Stores/User/App';
|
import { AppUserStore } from 'Stores/User/App';
|
||||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||||
|
@ -172,21 +172,21 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
pgpEncrypt: false,
|
pgpEncrypt: false,
|
||||||
canPgpSign: false,
|
canPgpSign: false,
|
||||||
canPgpEncrypt: false,
|
canPgpEncrypt: false,
|
||||||
|
canMailvelope: false,
|
||||||
|
|
||||||
draftsFolder: '',
|
draftsFolder: '',
|
||||||
draftUid: 0,
|
draftUid: 0,
|
||||||
sending: false,
|
sending: false,
|
||||||
saving: false,
|
saving: false,
|
||||||
|
|
||||||
attachmentsPlace: false,
|
viewArea: 'body',
|
||||||
|
|
||||||
composeUploaderButton: null,
|
composeUploaderButton: null, // initDom
|
||||||
composeUploaderDropPlace: null,
|
composeUploaderDropPlace: null, // initDom
|
||||||
attacheMultipleAllowed: false,
|
attacheMultipleAllowed: false,
|
||||||
addAttachmentEnabled: false,
|
addAttachmentEnabled: false,
|
||||||
|
|
||||||
// div.textAreaParent
|
editorArea: null, // initDom
|
||||||
composeEditorArea: null,
|
|
||||||
|
|
||||||
currentIdentity: IdentityUserStore()[0] || null
|
currentIdentity: IdentityUserStore()[0] || null
|
||||||
});
|
});
|
||||||
|
@ -382,10 +382,10 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
if (this.attachmentsInProcess().length) {
|
if (this.attachmentsInProcess().length) {
|
||||||
this.attachmentsInProcessError(true);
|
this.attachmentsInProcessError(true);
|
||||||
this.attachmentsPlace(true);
|
this.attachmentsArea();
|
||||||
} else if (this.attachmentsInError().length) {
|
} else if (this.attachmentsInError().length) {
|
||||||
this.attachmentsInErrorError(true);
|
this.attachmentsInErrorError(true);
|
||||||
this.attachmentsPlace(true);
|
this.attachmentsArea();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.to().trim() && !this.cc().trim() && !this.bcc().trim()) {
|
if (!this.to().trim() && !this.cc().trim() && !this.bcc().trim()) {
|
||||||
|
@ -452,7 +452,13 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
30000
|
30000
|
||||||
);
|
);
|
||||||
|
|
||||||
if (encrypt) {
|
if (this.mailvelope && 'mailvelope' === this.viewArea()) {
|
||||||
|
this.mailvelope.encrypt(this.allRecipients()).then(armored => {
|
||||||
|
params.Html = '';
|
||||||
|
params.Text = armored;
|
||||||
|
send();
|
||||||
|
});
|
||||||
|
} else if (encrypt) {
|
||||||
if (params.Html) {
|
if (params.Html) {
|
||||||
throw 'Encrypt HTML with ' + encrypt + ' not yet implemented';
|
throw 'Encrypt HTML with ' + encrypt + ' not yet implemented';
|
||||||
}
|
}
|
||||||
|
@ -557,44 +563,56 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
setFolderHash(FolderUserStore.draftsFolder(), '');
|
setFolderHash(FolderUserStore.draftsFolder(), '');
|
||||||
|
|
||||||
Remote.request('SaveMessage',
|
const
|
||||||
(iError, oData) => {
|
params = this.getMessageRequestParams(FolderUserStore.draftsFolder()),
|
||||||
let result = false;
|
save = () =>
|
||||||
|
Remote.request('SaveMessage',
|
||||||
|
(iError, oData) => {
|
||||||
|
let result = false;
|
||||||
|
|
||||||
this.saving(false);
|
this.saving(false);
|
||||||
|
|
||||||
if (!iError) {
|
if (!iError) {
|
||||||
if (oData.Result.NewFolder && oData.Result.NewUid) {
|
if (oData.Result.NewFolder && oData.Result.NewUid) {
|
||||||
result = true;
|
result = true;
|
||||||
|
|
||||||
if (this.bFromDraft) {
|
if (this.bFromDraft) {
|
||||||
const message = MessageUserStore.message();
|
const message = MessageUserStore.message();
|
||||||
if (message && this.draftsFolder() === message.folder && this.draftUid() == message.uid) {
|
if (message && this.draftsFolder() === message.folder && this.draftUid() == message.uid) {
|
||||||
MessageUserStore.message(null);
|
MessageUserStore.message(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.draftsFolder(oData.Result.NewFolder);
|
||||||
|
this.draftUid(oData.Result.NewUid);
|
||||||
|
|
||||||
|
this.savedTime(new Date);
|
||||||
|
|
||||||
|
if (this.bFromDraft) {
|
||||||
|
setFolderHash(this.draftsFolder(), '');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.draftsFolder(oData.Result.NewFolder);
|
if (!result) {
|
||||||
this.draftUid(oData.Result.NewUid);
|
this.savedError(true);
|
||||||
|
this.savedErrorDesc(getNotification(Notification.CantSaveMessage));
|
||||||
this.savedTime(new Date);
|
|
||||||
|
|
||||||
if (this.bFromDraft) {
|
|
||||||
setFolderHash(this.draftsFolder(), '');
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
this.reloadDraftFolder();
|
||||||
this.savedError(true);
|
},
|
||||||
this.savedErrorDesc(getNotification(Notification.CantSaveMessage));
|
params,
|
||||||
}
|
200000
|
||||||
|
);
|
||||||
|
|
||||||
this.reloadDraftFolder();
|
if (this.mailvelope && 'mailvelope' === this.viewArea()) {
|
||||||
},
|
this.mailvelope.createDraft().then(armored => {
|
||||||
this.getMessageRequestParams(FolderUserStore.draftsFolder()),
|
params.Text = armored;
|
||||||
200000
|
save();
|
||||||
);
|
});
|
||||||
|
} else {
|
||||||
|
save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -736,14 +754,21 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
(getFullscreenElement() === this.oContent) && exitFullscreen();
|
(getFullscreenElement() === this.oContent) && exitFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dropMailvelope() {
|
||||||
|
if (this.mailvelope) {
|
||||||
|
elementById('mailvelope-editor').textContent = '';
|
||||||
|
this.mailvelope = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
editor(fOnInit) {
|
editor(fOnInit) {
|
||||||
if (fOnInit && this.composeEditorArea()) {
|
if (fOnInit && this.editorArea()) {
|
||||||
if (this.oEditor) {
|
if (this.oEditor) {
|
||||||
fOnInit(this.oEditor);
|
fOnInit(this.oEditor);
|
||||||
} else {
|
} else {
|
||||||
// setTimeout(() => {
|
// setTimeout(() => {
|
||||||
this.oEditor = new HtmlEditor(
|
this.oEditor = new HtmlEditor(
|
||||||
this.composeEditorArea(),
|
this.editorArea(),
|
||||||
null,
|
null,
|
||||||
() => fOnInit(this.oEditor),
|
() => fOnInit(this.oEditor),
|
||||||
bHtml => this.isHtml(!!bHtml)
|
bHtml => this.isHtml(!!bHtml)
|
||||||
|
@ -1201,7 +1226,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
this.dragAndDropOver(false);
|
this.dragAndDropOver(false);
|
||||||
})
|
})
|
||||||
.on('onBodyDragEnter', () => {
|
.on('onBodyDragEnter', () => {
|
||||||
this.attachmentsPlace(true);
|
this.attachmentsArea();
|
||||||
this.dragAndDropVisible(true);
|
this.dragAndDropVisible(true);
|
||||||
})
|
})
|
||||||
.on('onBodyDragLeave', () => {
|
.on('onBodyDragLeave', () => {
|
||||||
|
@ -1231,7 +1256,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
this.attachments.push(attachment);
|
this.attachments.push(attachment);
|
||||||
|
|
||||||
this.attachmentsPlace(true);
|
this.attachmentsArea();
|
||||||
|
|
||||||
if (0 < size && 0 < attachmentSizeLimit && attachmentSizeLimit < size) {
|
if (0 < size && 0 < attachmentSizeLimit && attachmentSizeLimit < size) {
|
||||||
attachment
|
attachment
|
||||||
|
@ -1423,7 +1448,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
this.attachments.push(attachment);
|
this.attachments.push(attachment);
|
||||||
|
|
||||||
this.attachmentsPlace(true);
|
this.attachmentsArea();
|
||||||
|
|
||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
@ -1498,7 +1523,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
this.requestReadReceipt(false);
|
this.requestReadReceipt(false);
|
||||||
this.markAsImportant(false);
|
this.markAsImportant(false);
|
||||||
|
|
||||||
this.attachmentsPlace(false);
|
this.bodyArea();
|
||||||
|
|
||||||
this.aDraftInfo = null;
|
this.aDraftInfo = null;
|
||||||
this.sInReplyTo = '';
|
this.sInReplyTo = '';
|
||||||
|
@ -1532,6 +1557,8 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
this.saving(false);
|
this.saving(false);
|
||||||
|
|
||||||
this.oEditor && this.oEditor.clear();
|
this.oEditor && this.oEditor.clear();
|
||||||
|
|
||||||
|
this.dropMailvelope();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1543,6 +1570,43 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mailvelopeArea() {
|
||||||
|
/**
|
||||||
|
* Creates an iframe with an editor for a new encrypted mail.
|
||||||
|
* The iframe will be injected into the container identified by selector.
|
||||||
|
* https://mailvelope.github.io/mailvelope/Editor.html
|
||||||
|
*/
|
||||||
|
let text = this.oEditor.getData(true),
|
||||||
|
size = SettingsGet('PhpUploadSizes')['post_max_size'],
|
||||||
|
quota = pInt(size);
|
||||||
|
switch (size.slice(-1)) {
|
||||||
|
case 'G': quota *= 1024; // fallthrough
|
||||||
|
case 'M': quota *= 1024; // fallthrough
|
||||||
|
case 'K': quota *= 1024;
|
||||||
|
}
|
||||||
|
this.mailvelope ||
|
||||||
|
mailvelope.createEditorContainer('#mailvelope-editor', PgpUserStore.mailvelopeKeyring, {
|
||||||
|
// https://mailvelope.github.io/mailvelope/global.html#EditorContainerOptions
|
||||||
|
quota: Math.max(2048, (quota / 1024)) - 48, // (text + attachments) limit in kilobytes
|
||||||
|
predefinedText: this.oEditor.isHtml() ? htmlToPlain(text) : text
|
||||||
|
/*
|
||||||
|
signMsg: false, // if true then the mail will be signed (default: false)
|
||||||
|
armoredDraft: '', // Ascii Armored PGP Text Block
|
||||||
|
quotedMail: '', // Ascii Armored PGP Text Block mail that should be quoted
|
||||||
|
quotedMailIndent: true, // if true the quoted mail will be indented (default: true)
|
||||||
|
quotedMailHeader: '', // header to be added before the quoted mail
|
||||||
|
keepAttachments: false, // add attachments of quotedMail to editor (default: false)
|
||||||
|
*/
|
||||||
|
}).then(editor => this.mailvelope = editor);
|
||||||
|
this.viewArea('mailvelope');
|
||||||
|
}
|
||||||
|
attachmentsArea() {
|
||||||
|
this.viewArea('attachments');
|
||||||
|
}
|
||||||
|
bodyArea() {
|
||||||
|
this.viewArea('body');
|
||||||
|
}
|
||||||
|
|
||||||
allRecipients() {
|
allRecipients() {
|
||||||
const email = new EmailModel();
|
const email = new EmailModel();
|
||||||
return [
|
return [
|
||||||
|
@ -1555,14 +1619,22 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
email.clear();
|
email.clear();
|
||||||
email.parse(value.trim());
|
email.parse(value.trim());
|
||||||
return email.email || false;
|
return email.email || false;
|
||||||
}).filter(v => v);
|
}).validUnique();
|
||||||
}
|
}
|
||||||
|
|
||||||
initPgpEncrypt() {
|
initPgpEncrypt() {
|
||||||
return PgpUserStore.hasPublicKeyForEmails(this.allRecipients(), 1).then(result => {
|
PgpUserStore.hasPublicKeyForEmails(this.allRecipients(), 1).then(result => {
|
||||||
console.log({canPgpEncrypt:result});
|
console.log({canPgpEncrypt:result});
|
||||||
this.canPgpEncrypt(result);
|
this.canPgpEncrypt(result);
|
||||||
});
|
});
|
||||||
|
PgpUserStore.mailvelopeHasPublicKeyForEmails(this.allRecipients(), 1).then(result => {
|
||||||
|
console.log({canMailvelope:result});
|
||||||
|
this.canMailvelope(result);
|
||||||
|
if (!result) {
|
||||||
|
'mailvelope' === this.viewArea() && this.bodyArea();
|
||||||
|
// this.dropMailvelope();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
togglePgpSign() {
|
togglePgpSign() {
|
||||||
|
|
|
@ -782,14 +782,11 @@ class Actions
|
||||||
$aResult['ContactsPdoPassword'] = (string)APP_DUMMY;
|
$aResult['ContactsPdoPassword'] = (string)APP_DUMMY;
|
||||||
|
|
||||||
$aResult['WeakPassword'] = \is_file($passfile);
|
$aResult['WeakPassword'] = \is_file($passfile);
|
||||||
|
|
||||||
$aResult['PhpUploadSizes'] = array(
|
|
||||||
'upload_max_filesize' => \ini_get('upload_max_filesize'),
|
|
||||||
'post_max_size' => \ini_get('post_max_size')
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$aResult['Capa'] = $this->Capa(true);
|
$aResult['Capa'] = $this->Capa(true);
|
||||||
|
$aResult['LanguageAdmin'] = $this->ValidateLanguage($oConfig->Get('webmail', 'language_admin', 'en'), '', true);
|
||||||
|
$aResult['UserLanguageAdmin'] = $this->ValidateLanguage($UserLanguageRaw, '', true, true);
|
||||||
} else {
|
} else {
|
||||||
$oAccount = $this->getAccountFromToken(false);
|
$oAccount = $this->getAccountFromToken(false);
|
||||||
if ($oAccount) {
|
if ($oAccount) {
|
||||||
|
@ -901,16 +898,19 @@ class Actions
|
||||||
$aResult['Capa'] = $this->Capa(false, $oAccount);
|
$aResult['Capa'] = $this->Capa(false, $oAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($aResult['Auth']) {
|
||||||
|
$aResult['PhpUploadSizes'] = array(
|
||||||
|
'upload_max_filesize' => \ini_get('upload_max_filesize'),
|
||||||
|
'post_max_size' => \ini_get('post_max_size')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
$sStaticCache = $this->StaticCache();
|
$sStaticCache = $this->StaticCache();
|
||||||
|
|
||||||
$aResult['Theme'] = $this->GetTheme($bAdmin);
|
$aResult['Theme'] = $this->GetTheme($bAdmin);
|
||||||
|
|
||||||
$aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false);
|
$aResult['Language'] = $this->ValidateLanguage($sLanguage, '', false);
|
||||||
$aResult['UserLanguage'] = $this->ValidateLanguage($UserLanguageRaw, '', false, true);
|
$aResult['UserLanguage'] = $this->ValidateLanguage($UserLanguageRaw, '', false, true);
|
||||||
if ($bAdmin) {
|
|
||||||
$aResult['LanguageAdmin'] = $this->ValidateLanguage($oConfig->Get('webmail', 'language_admin', 'en'), '', true);
|
|
||||||
$aResult['UserLanguageAdmin'] = $this->ValidateLanguage($UserLanguageRaw, '', true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$aResult['PluginsLink'] = '';
|
$aResult['PluginsLink'] = '';
|
||||||
if (0 < $this->oPlugins->Count() && $this->oPlugins->HaveJs($bAdmin)) {
|
if (0 < $this->oPlugins->Count() && $this->oPlugins->HaveJs($bAdmin)) {
|
||||||
|
|
|
@ -134,13 +134,13 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td style="display:flex">
|
<td style="display:flex">
|
||||||
<div class="btn-group" style="flex-grow:1">
|
<div class="btn-group" style="flex-grow:1" id="area-toggle">
|
||||||
<button type="button" class="btn" data-bind="click: function () { attachmentsPlace(false); },
|
<button type="button" class="btn" data-bind="click: bodyArea,
|
||||||
css: { 'active': !attachmentsPlace() }">
|
css: { 'active': 'body' == viewArea() }">
|
||||||
<i class="icon-file-text"></i>
|
<i class="icon-file-text"></i>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn" data-bind="click: function () { attachmentsPlace(true); },
|
<button type="button" class="btn" data-bind="click: attachmentsArea,
|
||||||
css: { 'btn-danger': attachmentsInErrorCount(), 'active': attachmentsPlace() },
|
css: { 'btn-danger': attachmentsInErrorCount(), 'active': 'attachments' == viewArea() },
|
||||||
tooltipErrorTip: attachmentsErrorTooltip">
|
tooltipErrorTip: attachmentsErrorTooltip">
|
||||||
<span data-bind="visible: attachmentsCount()">
|
<span data-bind="visible: attachmentsCount()">
|
||||||
<b data-bind="text: attachmentsCount"></b>
|
<b data-bind="text: attachmentsCount"></b>
|
||||||
|
@ -148,6 +148,9 @@
|
||||||
</span>
|
</span>
|
||||||
<i data-bind="css: { 'icon-attachment': !attachmentsInProcessCount(), 'icon-spinner': attachmentsInProcessCount()}"></i>
|
<i data-bind="css: { 'icon-attachment': !attachmentsInProcessCount(), 'icon-spinner': attachmentsInProcessCount()}"></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="btn" data-bind="visible: canMailvelope, click: mailvelopeArea, css: { 'active': 'mailvelope' == viewArea() }">
|
||||||
|
<i class="mailvelope-icon"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a class="btn"
|
<a class="btn"
|
||||||
|
@ -161,7 +164,7 @@
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attachmentAreaParent" data-bind="visible: attachmentsPlace">
|
<div class="attachmentAreaParent" data-bind="visible: 'attachments' == viewArea()">
|
||||||
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropVisible(), initDom: composeUploaderDropPlace, css: {'dragAndDropOver': dragAndDropOver}"
|
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropVisible(), initDom: composeUploaderDropPlace, css: {'dragAndDropOver': dragAndDropOver}"
|
||||||
data-i18n="COMPOSE/ATTACH_DROP_FILES_DESC"></div>
|
data-i18n="COMPOSE/ATTACH_DROP_FILES_DESC"></div>
|
||||||
<ul class="attachmentList" data-bind="foreach: attachments">
|
<ul class="attachmentList" data-bind="foreach: attachments">
|
||||||
|
@ -182,5 +185,7 @@
|
||||||
data-i18n="COMPOSE/NO_ATTACHMENTS_HERE_DESC"></div>
|
data-i18n="COMPOSE/NO_ATTACHMENTS_HERE_DESC"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="textAreaParent" data-bind="visible: !attachmentsPlace(), initDom: composeEditorArea"></div>
|
<div class="textAreaParent" data-bind="visible: 'body' == viewArea(), initDom: editorArea"></div>
|
||||||
|
|
||||||
|
<div class="textAreaParent" id="mailvelope-editor" data-bind="visible: 'mailvelope' == viewArea()"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue