From 135406ebfe1407ad7ee4b3fe2690e76561f809b0 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Sun, 29 May 2022 10:12:49 +0200
Subject: [PATCH 01/20] Some changes for #419 flags
---
.../MailSo/Imap/FolderInformation.php | 22 +++++++++++++++++-
.../app/libraries/MailSo/Mail/Folder.php | 1 +
.../app/libraries/MailSo/Mail/MailClient.php | 23 ++++++++-----------
.../MailSo/Mail/MessageCollection.php | 4 ++++
.../libraries/RainLoop/Actions/Folders.php | 3 +--
5 files changed, 37 insertions(+), 16 deletions(-)
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php
index dcedd1860..cee0a0c9d 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/FolderInformation.php
@@ -15,7 +15,7 @@ namespace MailSo\Imap;
* @category MailSo
* @package Imap
*/
-class FolderInformation
+class FolderInformation implements \JsonSerializable
{
use Traits\Status;
@@ -36,6 +36,7 @@ class FolderInformation
/**
* @var array
+ * NOTE: Empty when FolderExamine is used
*/
public $PermanentFlags = array();
@@ -57,4 +58,23 @@ class FolderInformation
\in_array($sFlag, $this->PermanentFlags) ||
\in_array($sFlag, $this->Flags);
}
+
+ public function jsonSerialize()
+ {
+ return array(
+ 'Name' => $this->FolderName,
+ 'Flags' => $this->Flags,
+ 'PermanentFlags' => $this->PermanentFlags,
+/*
+ 'Messages' => $this->MESSAGES,
+ 'Unseen' => $this->UNSEEN,
+ 'Recent' => $this->RECENT,
+ 'UidNext' => $this->UIDNEXT,
+ 'UidValidity' => $this->UIDVALIDITY,
+ 'Highestmodseq' => $this->HIGHESTMODSEQ,
+ 'Appendlimit' => $this->APPENDLIMIT,
+ 'Mailboxid' => $this->MAILBOXID,
+*/
+ );
+ }
}
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php
index 1dbde14e8..14f777b39 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/Folder.php
@@ -228,6 +228,7 @@ class Folder implements \JsonSerializable
'Selectable' => $this->IsSelectable(),
'Flags' => $this->FlagsLowerCase(),
// 'Extended' => $aExtended,
+// 'PermanentFlags' => $this->oImapFolder->PermanentFlags,
'Metadata' => $this->oImapFolder->Metadata()
);
}
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
index 3fbec55da..1e5e322ce 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
@@ -521,21 +521,19 @@ class MailClient
*/
public function FolderInformation(string $sFolderName, int $iPrevUidNext = 0, SequenceSet $oRange = null) : array
{
- $aFlags = array();
-
list($iCount, $iUnseenCount, $iUidNext, $iHighestModSeq, $iAppendLimit, $sMailboxId) = $this->initFolderValues($sFolderName);
- if ($oRange && \count($oRange))
- {
- $this->oImapClient->FolderExamine($sFolderName);
+ $aFlags = array();
+ if ($oRange && \count($oRange)) {
+ $oInfo = $this->oImapClient->FolderExamine($sFolderName);
+ // $oInfo->PermanentFlags
$aFetchResponse = $this->oImapClient->Fetch(array(
FetchType::UID,
FetchType::FLAGS
), (string) $oRange, $oRange->UID);
- foreach ($aFetchResponse as $oFetchResponse)
- {
+ foreach ($aFetchResponse as $oFetchResponse) {
$iUid = (int) $oFetchResponse->GetFetchValue(FetchType::UID);
$aLowerFlags = \array_map('strtolower', $oFetchResponse->GetFetchValue(FetchType::FLAGS));
$aFlags[] = array(
@@ -830,15 +828,19 @@ class MailClient
list($iMessageRealCount, $iMessageUnseenCount, $iUidNext, $iHighestModSeq) = $this->initFolderValues($oParams->sFolderName);
- $this->oImapClient->FolderExamine($oParams->sFolderName);
+ // Don't use FolderExamine, else PERMANENTFLAGS is empty
+ $oInfo = $this->oImapClient->FolderSelect($oParams->sFolderName);
$oMessageCollection = new MessageCollection;
$oMessageCollection->FolderName = $oParams->sFolderName;
+ $oMessageCollection->FolderInfo = $oInfo;
$oMessageCollection->Offset = $oParams->iOffset;
$oMessageCollection->Limit = $oParams->iLimit;
$oMessageCollection->Search = $sSearch;
$oMessageCollection->ThreadUid = $oParams->iThreadUid;
$oMessageCollection->Filtered = '' !== \MailSo\Config::$MessageListPermanentFilter;
+ $oMessageCollection->MessageCount = $iMessageRealCount;
+ $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
$aUids = array();
$aAllThreads = [];
@@ -934,8 +936,6 @@ class MailClient
}
}
- $oMessageCollection->MessageCount = $iMessageRealCount;
- $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
$oMessageCollection->MessageResultCount = \count($aUids);
if (\count($aUids))
@@ -954,9 +954,6 @@ class MailClient
', limit:'.\MailSo\Config::$MessageListCountLimitTrigger.')');
}
- $oMessageCollection->MessageCount = $iMessageRealCount;
- $oMessageCollection->MessageUnseenCount = $iMessageUnseenCount;
-
if (\strlen($sSearch))
{
$aUids = $this->GetUids($oParams->oCacher, $sSearch,
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php
index 428e80baa..db607939a 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MessageCollection.php
@@ -67,6 +67,9 @@ class MessageCollection extends \MailSo\Base\Collection
*/
public $ThreadUid = 0;
+ // MailSo\Imap\FolderInformation
+ public $FolderInfo = null;
+
/**
* @var array
*/
@@ -97,6 +100,7 @@ class MessageCollection extends \MailSo\Base\Collection
'MessageResultCount' => $this->MessageResultCount,
'Folder' => $this->FolderName,
'FolderHash' => $this->FolderHash,
+ 'FolderInfo' => $this->FolderInfo,
'UidNext' => $this->UidNext,
'ThreadUid' => $this->ThreadUid,
'NewMessages' => $this->NewMessages,
diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php
index 59889fdc3..be99c3c54 100644
--- a/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php
+++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Actions/Folders.php
@@ -426,13 +426,12 @@ trait Folders
);
$aInboxInformation['Flags'] = $aInboxInformation['MessagesFlags'];
unset($aInboxInformation['MessagesFlags']);
+ return $this->DefaultResponse(__FUNCTION__, $aInboxInformation);
}
catch (\Throwable $oException)
{
throw new ClientException(Notifications::MailServerError, $oException);
}
-
- return $this->DefaultResponse(__FUNCTION__, $aInboxInformation);
}
/**
From 2ea3f10cb08824f5cd77f15e881bc15187ecefac Mon Sep 17 00:00:00 2001
From: Gerald Urbas <121263+geraldurbas@users.noreply.github.com>
Date: Sun, 29 May 2022 20:19:06 +0200
Subject: [PATCH 02/20] Change Ordering of SASLMechanisms
Want bw. Needed to change the ordering for SASL Mechanism...
---
snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php
index 22ec5ff61..9c745119f 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php
@@ -120,7 +120,7 @@ class SmtpClient extends \MailSo\Net\NetClient
$sPassword = $aCredentials['Password'];
$type = '';
- $aCredentials['SASLMechanisms'][] = 'LOGIN';
+ array_unshift($aCredentials['SASLMechanisms'],'LOGIN');
foreach ($aCredentials['SASLMechanisms'] as $sasl_type) {
if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) {
$type = $sasl_type;
From 30ece4b8c8526cefeffec1a7fc4faadd1d6c6210 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Mon, 30 May 2022 08:23:59 +0200
Subject: [PATCH 03/20] Resolve #420
---
dev/View/Popup/Compose.js | 3 ++-
snappymail/v/0.0.0/app/templates/Views/User/PopupsCompose.html | 3 +++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js
index 8d67433e0..cc366ab4d 100644
--- a/dev/View/Popup/Compose.js
+++ b/dev/View/Popup/Compose.js
@@ -20,7 +20,7 @@ import { messagesDeleteHelper } from 'Common/Folders';
import { serverRequest } from 'Common/Links';
import { i18n, getNotification, getUploadErrorDescByCode, timestampToString } from 'Common/Translator';
import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
-import { Settings, SettingsGet, elementById, addShortcut } from 'Common/Globals';
+import { Settings, SettingsCapa, SettingsGet, elementById, addShortcut } from 'Common/Globals';
//import { exitFullscreen, isFullscreen, toggleFullscreen } from 'Common/Fullscreen';
import { AppUserStore } from 'Stores/User/App';
@@ -236,6 +236,7 @@ export class ComposePopupView extends AbstractViewPopup {
this.sLastFocusedField = 'to';
this.allowContacts = AppUserStore.allowContacts();
+ this.allowIdentities = SettingsCapa('Identities');
this.bSkipNextHide = false;
diff --git a/snappymail/v/0.0.0/app/templates/Views/User/PopupsCompose.html b/snappymail/v/0.0.0/app/templates/Views/User/PopupsCompose.html
index 9f17dd1c5..c5ec43f3e 100644
--- a/snappymail/v/0.0.0/app/templates/Views/User/PopupsCompose.html
+++ b/snappymail/v/0.0.0/app/templates/Views/User/PopupsCompose.html
@@ -66,7 +66,10 @@
|
+
+
+
From fe9d0da14a558624e27f2e9504d06c00296507d9 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Mon, 30 May 2022 12:58:50 +0200
Subject: [PATCH 04/20] Added Thunderbird labels colors as test for #419
---
dev/Model/Message.js | 3 +++
dev/Styles/User/MessageList.less | 11 +++++++++--
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/dev/Model/Message.js b/dev/Model/Message.js
index 276adf7a8..822b49598 100644
--- a/dev/Model/Message.js
+++ b/dev/Model/Message.js
@@ -306,6 +306,9 @@ export class MessageModel extends AbstractModel {
hasUnseenSubMessage: this.hasUnseenSubMessage(),
hasFlaggedSubMessage: this.hasFlaggedSubMessage()
}, (key, value) => value && classes.push(key));
+ this.flags().forEach(value => {
+ '\\' !== value[0] && classes.push('flag-'+value);
+ });
return classes.join(' ');
}
diff --git a/dev/Styles/User/MessageList.less b/dev/Styles/User/MessageList.less
index 81b4414e7..2e9283a7e 100644
--- a/dev/Styles/User/MessageList.less
+++ b/dev/Styles/User/MessageList.less
@@ -228,7 +228,7 @@ html:not(rl-mobile) {
}
.checkboxMessage {
- padding: 0 6px;
+ margin: 0 6px;
font-size: 16px;
}
@@ -392,7 +392,7 @@ html.rl-ctrl-key-pressed .messageListItem {
.checkboxMessage {
line-height: 12px;
- margin: 10px 0 -5px;
+ margin: 10px 6px -5px;
}
.subjectParent {
@@ -444,3 +444,10 @@ html:not(.rl-mobile):not(.rl-side-preview-pane) {
}
}
}
+
+/* Thunderbird labels */
+.flag-\$label5 .checkboxMessage { background-color: #808; }
+.flag-\$label4 .checkboxMessage { background-color: #00F; }
+.flag-\$label3 .checkboxMessage { background-color: #080; }
+.flag-\$label2 .checkboxMessage { background-color: #FA0; }
+.flag-\$label1 .checkboxMessage { background-color: #F00; }
From 5cc738e2ba925fa0cfb927c27b2cc8bbfe42e6f9 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Mon, 30 May 2022 13:12:01 +0200
Subject: [PATCH 05/20] Resolve #422
---
plugins/change-password-froxlor/driver.php | 107 +++++++++++++++++++++
plugins/change-password-froxlor/index.php | 20 ++++
2 files changed, 127 insertions(+)
create mode 100644 plugins/change-password-froxlor/driver.php
create mode 100644 plugins/change-password-froxlor/index.php
diff --git a/plugins/change-password-froxlor/driver.php b/plugins/change-password-froxlor/driver.php
new file mode 100644
index 000000000..0e26d32c3
--- /dev/null
+++ b/plugins/change-password-froxlor/driver.php
@@ -0,0 +1,107 @@
+oConfig = $oConfig;
+ $this->oLogger = $oLogger;
+ }
+
+ public static function isSupported() : bool
+ {
+ return \class_exists('PDO', false)
+ // The PHP extension PDO (mysql) must be installed to use this plugin
+ && \in_array('mysql', \PDO::getAvailableDrivers());
+ }
+
+ public static function configMapping() : array
+ {
+ return array(
+ \RainLoop\Plugins\Property::NewInstance('froxlor_dsn')->SetLabel('Froxlor PDO dsn')
+ ->SetDefaultValue('mysql:host=localhost;dbname=froxlor;charset=utf8'),
+ \RainLoop\Plugins\Property::NewInstance('froxlor_user')->SetLabel('User'),
+ \RainLoop\Plugins\Property::NewInstance('froxlor_password')->SetLabel('Password')
+ ->SetType(\RainLoop\Enumerations\PluginPropertyType::PASSWORD),
+ \RainLoop\Plugins\Property::NewInstance('froxlor_allowed_emails')->SetLabel('Allowed emails')
+ ->SetType(\RainLoop\Enumerations\PluginPropertyType::STRING_TEXT)
+ ->SetDescription('Allowed emails, space as delimiter, wildcard supported. Example: user1@domain1.net user2@domain1.net *@domain2.net')
+ ->SetDefaultValue('*')
+ );
+ }
+
+ public function ChangePassword(\RainLoop\Model\Account $oAccount, string $sPrevPassword, string $sNewPassword) : bool
+ {
+ if (!\RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->oConfig->Get('plugin', 'froxlor_allowed_emails', ''))) {
+ return false;
+ }
+
+ try
+ {
+ if ($this->oLogger) {
+ $this->oLogger->Write('froxlor: Try to change password for '.$oAccount->Email());
+ }
+
+ $oPdo = new \PDO(
+ $this->oConfig->Get('plugin', 'froxlor_dsn', ''),
+ $this->oConfig->Get('plugin', 'froxlor_user', ''),
+ $this->oConfig->Get('plugin', 'froxlor_password', ''),
+ array(
+ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION
+ )
+ );
+
+ $oStmt = $oPdo->prepare('SELECT password_enc, id FROM mail_users WHERE username = ? LIMIT 1');
+
+ if ($oStmt->execute(array($oAccount->IncLogin()))) {
+ $aFetchResult = $oStmt->fetch(\PDO::FETCH_ASSOC);
+ if (!empty($aFetchResult['id'])) {
+ $sDbPassword = $aFetchResult['password_enc'];
+ $sDbSalt = \substr($sDbPassword, 0, \strrpos($sDbPassword, '$'));
+ if (\crypt($sPrevPassword, $sDbSalt) === $sDbPassword) {
+
+ $oStmt = $oPdo->prepare('UPDATE mail_users SET password_enc = ? WHERE id = ?');
+
+ return !!$oStmt->execute(array(
+ $this->cryptPassword($sNewPassword),
+ $aFetchResult['id']
+ ));
+ }
+ }
+ }
+ }
+ catch (\Exception $oException)
+ {
+ if ($this->oLogger) {
+ $this->oLogger->WriteException($oException);
+ }
+ }
+ return false;
+ }
+
+ private function cryptPassword(string $sPassword) : string
+ {
+ if (\defined('CRYPT_SHA512') && CRYPT_SHA512) {
+ $sSalt = '$6$rounds=5000$' . \bin2hex(\random_bytes(8)) . '$';
+ } elseif (\defined('CRYPT_SHA256') && CRYPT_SHA256) {
+ $sSalt = '$5$rounds=5000$' . \bin2hex(\random_bytes(8)) . '$';
+ } else {
+ $sSalt = '$1$' . \bin2hex(\random_bytes(6)) . '$';
+ }
+ return \crypt($sPassword, $sSalt);
+ }
+}
diff --git a/plugins/change-password-froxlor/index.php b/plugins/change-password-froxlor/index.php
new file mode 100644
index 000000000..9e0bbd160
--- /dev/null
+++ b/plugins/change-password-froxlor/index.php
@@ -0,0 +1,20 @@
+
Date: Mon, 30 May 2022 13:17:15 +0200
Subject: [PATCH 06/20] Document for #423
---
snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php
index 9c745119f..1e3097e63 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Smtp/SmtpClient.php
@@ -120,7 +120,9 @@ class SmtpClient extends \MailSo\Net\NetClient
$sPassword = $aCredentials['Password'];
$type = '';
- array_unshift($aCredentials['SASLMechanisms'],'LOGIN');
+ // https://github.com/the-djmaze/snappymail/pull/423
+// $aCredentials['SASLMechanisms'][] = 'LOGIN';
+ \array_unshift($aCredentials['SASLMechanisms'], 'LOGIN');
foreach ($aCredentials['SASLMechanisms'] as $sasl_type) {
if ($this->IsAuthSupported($sasl_type) && \SnappyMail\SASL::isSupported($sasl_type)) {
$type = $sasl_type;
From 75422c73e8efdf9b9b8d41951981edca8861d8b6 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Mon, 30 May 2022 13:47:45 +0200
Subject: [PATCH 07/20] v2.16.2
---
.docker/release/files/usr/local/include/application.ini | 2 +-
integrations/cloudron/DESCRIPTION.md | 2 +-
integrations/cloudron/Dockerfile | 2 +-
integrations/nextcloud/snappymail/VERSION | 2 +-
integrations/nextcloud/snappymail/appinfo/info.xml | 2 +-
integrations/virtualmin/snappymail.pl | 2 +-
package.json | 2 +-
tasks/config.js | 1 -
8 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/.docker/release/files/usr/local/include/application.ini b/.docker/release/files/usr/local/include/application.ini
index 6d8745dce..c2e0c3cb1 100644
--- a/.docker/release/files/usr/local/include/application.ini
+++ b/.docker/release/files/usr/local/include/application.ini
@@ -307,5 +307,5 @@ dev_email = ""
dev_password = ""
[version]
-current = "2.16.1"
+current = "2.16.2"
saved = "Fri, 04 Mar 2022 08:55:26 +0000"
diff --git a/integrations/cloudron/DESCRIPTION.md b/integrations/cloudron/DESCRIPTION.md
index f496250f0..c30c07545 100644
--- a/integrations/cloudron/DESCRIPTION.md
+++ b/integrations/cloudron/DESCRIPTION.md
@@ -1,4 +1,4 @@
-This app packages SnappyMail 2.16.1.
+This app packages SnappyMail 2.16.2.
SnappyMail is a simple, modern, lightweight & fast web-based email client.
diff --git a/integrations/cloudron/Dockerfile b/integrations/cloudron/Dockerfile
index 93b3dacde..a35fd31a1 100644
--- a/integrations/cloudron/Dockerfile
+++ b/integrations/cloudron/Dockerfile
@@ -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.16.1
+VERSION=2.16.2
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 && \
diff --git a/integrations/nextcloud/snappymail/VERSION b/integrations/nextcloud/snappymail/VERSION
index 15c5c9d5b..90c94814e 100755
--- a/integrations/nextcloud/snappymail/VERSION
+++ b/integrations/nextcloud/snappymail/VERSION
@@ -1 +1 @@
-2.16.1
\ No newline at end of file
+2.16.2
\ No newline at end of file
diff --git a/integrations/nextcloud/snappymail/appinfo/info.xml b/integrations/nextcloud/snappymail/appinfo/info.xml
index a781d80fd..e7676e7f2 100644
--- a/integrations/nextcloud/snappymail/appinfo/info.xml
+++ b/integrations/nextcloud/snappymail/appinfo/info.xml
@@ -4,7 +4,7 @@
SnappyMail
SnappyMail Webmail
Simple, modern and fast web-based email client. After enabling in Nextcloud, go to Nextcloud admin panel, "Additionnal settings" and you will see a "SnappyMail webmail" section. There, click on the link to go to the SnappyMail admin panel. The default user/password is admin/12345. This version is based on SnappyMail 2.6.0 (2021-07).
- 2.16.1
+ 2.16.2
agpl
SnappyMail Team, Nextgen-Networks, Tab Fitts, Nathan Kinkade, Pierre-Alain Bandinelli
SnappyMail
diff --git a/integrations/virtualmin/snappymail.pl b/integrations/virtualmin/snappymail.pl
index 3987b5f50..894d9d24a 100644
--- a/integrations/virtualmin/snappymail.pl
+++ b/integrations/virtualmin/snappymail.pl
@@ -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.16.1" );
+return ( "2.16.2" );
}
sub script_snappymail_version_desc
diff --git a/package.json b/package.json
index 4bc01b4b0..f4b19ddc5 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"title": "SnappyMail",
"description": "Simple, modern & fast web-based email client",
"private": true,
- "version": "2.16.1",
+ "version": "2.16.2",
"homepage": "https://snappymail.eu",
"author": {
"name": "DJ Maze",
diff --git a/tasks/config.js b/tasks/config.js
index aab20f878..83b8b0173 100644
--- a/tasks/config.js
+++ b/tasks/config.js
@@ -1,6 +1,5 @@
/* SnappyMail Webmail (c) SnappyMail Team | Licensed under AGPL 3 */
const path = require('path');
-const { argv } = require('yargs');
const config = {
head: {
From bea081322e4a63feebfa1d26b8c2efcde4315047 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Mon, 30 May 2022 20:54:58 +0200
Subject: [PATCH 08/20] Resolve #425
---
.../v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php
index c2a9402e0..8dfa1dc1b 100644
--- a/snappymail/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php
+++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Config/AbstractConfig.php
@@ -187,7 +187,7 @@ abstract class AbstractConfig implements \JsonSerializable
}
$aData = \parse_ini_file($this->sFile, true);
- if ($aSubData && \count($aSubData))
+ if ($aData && \count($aData))
{
foreach ($aData as $sSectionKey => $aSectionValue)
{
From 1c267a00300a5e302f16c5f58dbe28bcf39c6b55 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Mon, 30 May 2022 21:04:08 +0200
Subject: [PATCH 09/20] v2.16.3
---
.../files/usr/local/include/application.ini | 2 +-
README.md | 24 +++++++++----------
integrations/cloudron/DESCRIPTION.md | 2 +-
integrations/cloudron/Dockerfile | 2 +-
integrations/nextcloud/snappymail/VERSION | 2 +-
.../nextcloud/snappymail/appinfo/info.xml | 2 +-
integrations/virtualmin/snappymail.pl | 2 +-
package.json | 2 +-
8 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/.docker/release/files/usr/local/include/application.ini b/.docker/release/files/usr/local/include/application.ini
index c2e0c3cb1..ea6374ee5 100644
--- a/.docker/release/files/usr/local/include/application.ini
+++ b/.docker/release/files/usr/local/include/application.ini
@@ -307,5 +307,5 @@ dev_email = ""
dev_password = ""
[version]
-current = "2.16.2"
+current = "2.16.3"
saved = "Fri, 04 Mar 2022 08:55:26 +0000"
diff --git a/README.md b/README.md
index 376cc8db7..75341a93d 100644
--- a/README.md
+++ b/README.md
@@ -140,26 +140,26 @@ RainLoop 1.15 vs SnappyMail
|js/* |RainLoop |Snappy |
|--------------- |--------: |--------: |
-|admin.js |2.158.025 | 80.335 |
-|app.js |4.215.733 | 405.051 |
+|admin.js |2.158.025 | 80.521 |
+|app.js |4.215.733 | 405.835 |
|boot.js | 672.433 | 2.050 |
|libs.js | 647.679 | 197.160 |
-|sieve.js | 0 | 86.504 |
+|sieve.js | 0 | 86.362 |
|polyfills.js | 325.908 | 0 |
|serviceworker.js | 0 | 285 |
-|TOTAL |8.019.778 | 771.385 |
+|TOTAL |8.019.778 | 772.213 |
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
-|admin.min.js | 255.514 | 40.186 | 73.899 | 13.359 | 60.674 | 11.966 |
-|app.min.js | 516.000 | 191.792 |140.430 | 61.896 |110.657 | 53.154 |
+|admin.min.js | 255.514 | 40.289 | 73.899 | 13.383 | 60.674 | 11.971 |
+|app.min.js | 516.000 | 192.189 |140.430 | 62.006 |110.657 | 53.281 |
|boot.min.js | 66.456 | 1.252 | 22.553 | 778 | 20.043 | 628 |
|libs.min.js | 574.626 | 95.110 |177.280 | 35.149 |151.855 | 31.461 |
-|sieve.min.js | 0 | 42.147 | 0 | 10.551 | 0 | 9.513 |
+|sieve.min.js | 0 | 42.091 | 0 | 10.543 | 0 | 9.511 |
|polyfills.min.js | 32.608 | 0 | 11.315 | 0 | 10.072 | 0 |
-|TOTAL user |1.189.690 | 288.154 |351.061 | 97.823 |292.627 | 85.243 |
-|TOTAL user+sieve |1.189.690 | 330.301 |351.061 |108.374 |292.627 | 94.756 |
-|TOTAL admin | 929.204 | 136.548 |285.047 | 49.286 |242.644 | 44.055 |
+|TOTAL user |1.189.690 | 288.551 |351.061 | 97.933 |292.627 | 85.370 |
+|TOTAL user+sieve |1.189.690 | 330.642 |351.061 |108.476 |292.627 | 94.881 |
+|TOTAL admin | 929.204 | 136.651 |285.047 | 49.310 |242.644 | 44.060 |
For a user its around 70% smaller and faster than traditional RainLoop.
@@ -187,8 +187,8 @@ For a user its around 70% smaller and faster than traditional RainLoop.
|css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli |
|------------ |-------: |------: |------: |------: |--------: |
-|app.css | 340.334 | 80.643 | 46.959 | 16.709 | 14.386 |
-|app.min.css | 274.791 | 64.822 | 39.618 | 14.793 | 13.044 |
+|app.css | 340.334 | 80.979 | 46.959 | 16.774 | 14.439 |
+|app.min.css | 274.791 | 65.092 | 39.618 | 14.841 | 13.085 |
|boot.css | | 1.326 | | 664 | 545 |
|boot.min.css | | 1.071 | | 590 | 474 |
|admin.css | | 29.828 | | 6.777 | 5.875 |
diff --git a/integrations/cloudron/DESCRIPTION.md b/integrations/cloudron/DESCRIPTION.md
index c30c07545..f59fbbfb9 100644
--- a/integrations/cloudron/DESCRIPTION.md
+++ b/integrations/cloudron/DESCRIPTION.md
@@ -1,4 +1,4 @@
-This app packages SnappyMail 2.16.2.
+This app packages SnappyMail 2.16.3.
SnappyMail is a simple, modern, lightweight & fast web-based email client.
diff --git a/integrations/cloudron/Dockerfile b/integrations/cloudron/Dockerfile
index a35fd31a1..0e65debbf 100644
--- a/integrations/cloudron/Dockerfile
+++ b/integrations/cloudron/Dockerfile
@@ -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.16.2
+VERSION=2.16.3
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 && \
diff --git a/integrations/nextcloud/snappymail/VERSION b/integrations/nextcloud/snappymail/VERSION
index 90c94814e..38275d2df 100755
--- a/integrations/nextcloud/snappymail/VERSION
+++ b/integrations/nextcloud/snappymail/VERSION
@@ -1 +1 @@
-2.16.2
\ No newline at end of file
+2.16.3
\ No newline at end of file
diff --git a/integrations/nextcloud/snappymail/appinfo/info.xml b/integrations/nextcloud/snappymail/appinfo/info.xml
index e7676e7f2..b6369e00a 100644
--- a/integrations/nextcloud/snappymail/appinfo/info.xml
+++ b/integrations/nextcloud/snappymail/appinfo/info.xml
@@ -4,7 +4,7 @@
SnappyMail
SnappyMail Webmail
Simple, modern and fast web-based email client. After enabling in Nextcloud, go to Nextcloud admin panel, "Additionnal settings" and you will see a "SnappyMail webmail" section. There, click on the link to go to the SnappyMail admin panel. The default user/password is admin/12345. This version is based on SnappyMail 2.6.0 (2021-07).
- 2.16.2
+ 2.16.3
agpl
SnappyMail Team, Nextgen-Networks, Tab Fitts, Nathan Kinkade, Pierre-Alain Bandinelli
SnappyMail
diff --git a/integrations/virtualmin/snappymail.pl b/integrations/virtualmin/snappymail.pl
index 894d9d24a..be2cf24bd 100644
--- a/integrations/virtualmin/snappymail.pl
+++ b/integrations/virtualmin/snappymail.pl
@@ -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.16.2" );
+return ( "2.16.3" );
}
sub script_snappymail_version_desc
diff --git a/package.json b/package.json
index f4b19ddc5..2ea4e0581 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"title": "SnappyMail",
"description": "Simple, modern & fast web-based email client",
"private": true,
- "version": "2.16.2",
+ "version": "2.16.3",
"homepage": "https://snappymail.eu",
"author": {
"name": "DJ Maze",
From 1ef7ea3f27836e884f80672d30bbc08367b70125 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Tue, 31 May 2022 10:08:31 +0200
Subject: [PATCH 10/20] Made IMAP THREAD command iterable
---
.../libraries/MailSo/Imap/Commands/Messages.php | 4 ++--
.../MailSo/Imap/Enumerations/StoreAction.php | 4 ++--
.../libraries/MailSo/Imap/Requests/THREAD.php | 6 ++----
.../app/libraries/MailSo/Mail/MailClient.php | 17 +++++++----------
4 files changed, 13 insertions(+), 18 deletions(-)
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php
index 77bb81db9..78109fe8d 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Messages.php
@@ -402,12 +402,12 @@ trait Messages
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
- public function MessageSimpleThread(string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : array
+ public function MessageSimpleThread(string $sSearchCriterias = 'ALL', bool $bReturnUid = true) : iterable
{
$oThread = new \MailSo\Imap\Requests\THREAD($this);
$oThread->sCriterias = $sSearchCriterias;
$oThread->bUid = $bReturnUid;
- return $oThread->SendRequestGetResponse();
+ yield from $oThread->SendRequestIterateResponse();
}
private function getSimpleESearchOrESortResult(bool $bReturnUid) : array
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/StoreAction.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/StoreAction.php
index 4c6d8b44e..172e0e89b 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/StoreAction.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Enumerations/StoreAction.php
@@ -18,8 +18,8 @@ namespace MailSo\Imap\Enumerations;
*/
abstract class StoreAction
{
- const SET_FLAGS = 'FLAGS';
- const SET_FLAGS_SILENT = 'FLAGS.SILENT';
+// const SET_FLAGS = 'FLAGS';
+// const SET_FLAGS_SILENT = 'FLAGS.SILENT';
const ADD_FLAGS = '+FLAGS';
const ADD_FLAGS_SILENT = '+FLAGS.SILENT';
const REMOVE_FLAGS = '-FLAGS';
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php
index 017724e5e..818258c1c 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Requests/THREAD.php
@@ -41,7 +41,7 @@ class THREAD extends Request
parent::__construct($oImapClient);
}
- public function SendRequestGetResponse() : array
+ public function SendRequestIterateResponse() : iterable
{
if (!$this->oImapClient->IsSupported(\strtoupper("THREAD={$this->sAlgorithm}"))) {
$this->oImapClient->writeLogException(
@@ -58,7 +58,6 @@ class THREAD extends Request
)
);
- $aReturn = array();
foreach ($this->oImapClient->yieldUntaggedResponses() as $oResponse) {
$iOffset = ($this->bUid && 'UID' === $oResponse->StatusOrIndex && !empty($oResponse->ResponseList[2]) && 'THREAD' === $oResponse->ResponseList[2]) ? 1 : 0;
if (('THREAD' === $oResponse->StatusOrIndex || $iOffset)
@@ -69,12 +68,11 @@ class THREAD extends Request
for ($iIndex = 2 + $iOffset; $iIndex < $iLen; ++$iIndex) {
$aNewValue = $this->validateThreadItem($oResponse->ResponseList[$iIndex]);
if (\is_array($aNewValue)) {
- $aReturn[] = $aNewValue;
+ yield $aNewValue;
}
}
}
}
- return $aReturn;
}
/**
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
index 1e5e322ce..ea778475c 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Mail/MailClient.php
@@ -618,10 +618,15 @@ class MailClient
$this->oImapClient->FolderExamine($sFolderName);
- $aThreadUids = array();
+ $aResult = array();
try
{
- $aThreadUids = $this->oImapClient->MessageSimpleThread($sSearchHash);
+ foreach ($this->oImapClient->MessageSimpleThread($sSearchHash) as $mItem) {
+ // Flatten to single level
+ $aMap = [];
+ \array_walk_recursive($mItem, function($a) use (&$aMap) { $aMap[] = $a; });
+ $aResult[] = $aMap;
+ }
}
catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
{
@@ -629,14 +634,6 @@ class MailClient
unset($oException);
}
- // Flatten to single levels
- $aResult = array();
- foreach ($aThreadUids as $mItem) {
- $aMap = [];
- \array_walk_recursive($mItem, function($a) use (&$aMap) { $aMap[] = $a; });
- $aResult[] = $aMap;
- }
-
if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
{
$oCacher->Set($sSerializedHashKey, \json_encode(array(
From f588c91570bb0b60fd905fdad52b3a11033ec53f Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Tue, 31 May 2022 10:08:56 +0200
Subject: [PATCH 11/20] Simplify IMAP QUOTA commands
---
.../libraries/MailSo/Imap/Commands/Quota.php | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Quota.php b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Quota.php
index eb8fa4223..4d91d6dfd 100644
--- a/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Quota.php
+++ b/snappymail/v/0.0.0/app/libraries/MailSo/Imap/Commands/Quota.php
@@ -28,9 +28,7 @@ trait Quota
*/
public function Quota(string $sRootName = '') : ?array
{
- return $this->IsSupported('QUOTA')
- ? $this->getQuotaResult($this->SendRequestGetResponse("GETQUOTA {$this->EscapeFolderName($sRootName)}"))
- : null;
+ return $this->getQuota(false, $sRootName);
}
/**
@@ -41,18 +39,19 @@ trait Quota
*/
public function QuotaRoot(string $sFolderName = 'INBOX') : ?array
{
- return $this->IsSupported('QUOTA')
- ? $this->getQuotaResult($this->SendRequestGetResponse("GETQUOTAROOT {$this->EscapeFolderName($sFolderName)}"))
- : null;
+ return $this->getQuota(true, $sFolderName);
}
// * QUOTA "User quota" (STORAGE 1284645 2097152)\r\n
- private function getQuotaResult(\MailSo\Imap\ResponseCollection $oResponseCollection) : array
+ private function getQuota(bool $root, string $sFolderName) : ?array
{
+ if (!$this->IsSupported('QUOTA')) {
+ return null;
+ }
+ $oResponseCollection = $this->SendRequestGetResponse(($root?'GETQUOTAROOT':'GETQUOTA') . " {$this->EscapeFolderName($sFolderName)}");
$aReturn = array(0, 0);
- foreach ($oResponseCollection as $oResponse) {
- if (\MailSo\Imap\Enumerations\ResponseType::UNTAGGED === $oResponse->ResponseType
- && 'QUOTA' === $oResponse->StatusOrIndex
+ foreach ($this->yieldUntaggedResponses() as $oResponse) {
+ if ('QUOTA' === $oResponse->StatusOrIndex
&& isset($oResponse->ResponseList[3])
&& \is_array($oResponse->ResponseList[3])
&& 2 < \count($oResponse->ResponseList[3])
From eb61563db4879deb64a46c9061779ae8289499e6 Mon Sep 17 00:00:00 2001
From: the-djmaze <>
Date: Tue, 31 May 2022 10:47:14 +0200
Subject: [PATCH 12/20] Merge all example plugins
---
plugins/change-smtp-ehlo-message/index.php | 19 ++--
.../ContactsExampleSuggestions.php | 21 -----
plugins/contacts-suggestions-example/LICENSE | 20 -----
.../contacts-suggestions-example/index.php | 35 --------
plugins/custom-admin-settings-tab/index.php | 34 --------
.../js/CustomAdminSettings.js | 44 ----------
.../custom-admin-settings-tab/langs/en.ini | 4 -
.../custom-admin-settings-tab/langs/ru.ini | 4 -
plugins/custom-auth-example/LICENSE | 20 -----
plugins/custom-auth-example/index.php | 44 ----------
plugins/custom-settings-tab/LICENSE | 20 -----
plugins/custom-settings-tab/index.php | 62 -------------
.../js/CustomUserSettings.js | 81 -----------------
plugins/custom-settings-tab/langs/en.ini | 6 --
plugins/custom-settings-tab/langs/ru.ini | 6 --
.../LICENSE | 0
plugins/example/index.php | 87 +++++++++++++++++++
plugins/example/js/ExampleAdminSettings.js | 37 ++++++++
plugins/example/js/ExampleUserSettings.js | 68 +++++++++++++++
plugins/example/langs/en.json | 15 ++++
.../templates/ExampleAdminSettingsTab.html} | 6 +-
.../templates/ExampleUserSettingsTab.html} | 10 +--
.../0.0.0/app/templates/Views/User/Login.html | 12 +--
23 files changed, 230 insertions(+), 425 deletions(-)
delete mode 100644 plugins/contacts-suggestions-example/ContactsExampleSuggestions.php
delete mode 100644 plugins/contacts-suggestions-example/LICENSE
delete mode 100644 plugins/contacts-suggestions-example/index.php
delete mode 100644 plugins/custom-admin-settings-tab/index.php
delete mode 100644 plugins/custom-admin-settings-tab/js/CustomAdminSettings.js
delete mode 100644 plugins/custom-admin-settings-tab/langs/en.ini
delete mode 100644 plugins/custom-admin-settings-tab/langs/ru.ini
delete mode 100644 plugins/custom-auth-example/LICENSE
delete mode 100644 plugins/custom-auth-example/index.php
delete mode 100644 plugins/custom-settings-tab/LICENSE
delete mode 100644 plugins/custom-settings-tab/index.php
delete mode 100644 plugins/custom-settings-tab/js/CustomUserSettings.js
delete mode 100644 plugins/custom-settings-tab/langs/en.ini
delete mode 100644 plugins/custom-settings-tab/langs/ru.ini
rename plugins/{custom-admin-settings-tab => example}/LICENSE (100%)
create mode 100644 plugins/example/js/ExampleAdminSettings.js
create mode 100644 plugins/example/js/ExampleUserSettings.js
create mode 100644 plugins/example/langs/en.json
rename plugins/{custom-admin-settings-tab/templates/PluginCustomAdminSettingsTab.html => example/templates/ExampleAdminSettingsTab.html} (64%)
rename plugins/{custom-settings-tab/templates/PluginCustomSettingsTab.html => example/templates/ExampleUserSettingsTab.html} (66%)
diff --git a/plugins/change-smtp-ehlo-message/index.php b/plugins/change-smtp-ehlo-message/index.php
index af9fd2964..093566d6c 100644
--- a/plugins/change-smtp-ehlo-message/index.php
+++ b/plugins/change-smtp-ehlo-message/index.php
@@ -9,22 +9,21 @@ class ChangeSmtpEhloMessagePlugin extends \RainLoop\Plugins\AbstractPlugin
public function Init() : void
{
- $this->addHook('smtp.credentials', 'FilterSmtpCredentials');
+ $this->addHook('smtp.before-connect', 'FilterSmtpCredentials');
}
/**
* @param \RainLoop\Model\Account $oAccount
* @param array $aSmtpCredentials
*/
- public function FilterSmtpCredentials($oAccount, &$aSmtpCredentials)
+ public function FilterSmtpCredentials(\RainLoop\Model\Account $oAccount,
+ \MailSo\Smtp\SmtpClient $oSmtpClient,
+ array &$aSmtpCredentials)
{
- if ($oAccount instanceof \RainLoop\Model\Account && \is_array($aSmtpCredentials))
- {
- // Default:
- // $aSmtpCredentials['Ehlo'] = \MailSo\Smtp\SmtpClient::EhloHelper();
- //
- // or write your custom php
- $aSmtpCredentials['Ehlo'] = 'localhost';
- }
+ // Default:
+ // $aSmtpCredentials['Ehlo'] = \MailSo\Smtp\SmtpClient::EhloHelper();
+ //
+ // or write your custom php
+ $aSmtpCredentials['Ehlo'] = 'localhost';
}
}
diff --git a/plugins/contacts-suggestions-example/ContactsExampleSuggestions.php b/plugins/contacts-suggestions-example/ContactsExampleSuggestions.php
deleted file mode 100644
index c87ed2f61..000000000
--- a/plugins/contacts-suggestions-example/ContactsExampleSuggestions.php
+++ /dev/null
@@ -1,21 +0,0 @@
-Email(), ''),
- array('email@domain.com', 'name')
- );
-
- return $aResult;
- }
-}
diff --git a/plugins/contacts-suggestions-example/LICENSE b/plugins/contacts-suggestions-example/LICENSE
deleted file mode 100644
index 4aed64b3a..000000000
--- a/plugins/contacts-suggestions-example/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 RainLoop Team
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/plugins/contacts-suggestions-example/index.php b/plugins/contacts-suggestions-example/index.php
deleted file mode 100644
index 3e505c455..000000000
--- a/plugins/contacts-suggestions-example/index.php
+++ /dev/null
@@ -1,35 +0,0 @@
-addHook('main.fabrica', 'MainFabrica');
- }
-
- /**
- * @param string $sName
- * @param mixed $mResult
- */
- public function MainFabrica($sName, &$mResult)
- {
- switch ($sName)
- {
- case 'suggestions':
-
- if (!\is_array($mResult))
- {
- $mResult = array();
- }
-
- include_once __DIR__.'/ContactsExampleSuggestions.php';
- $mResult[] = new ContactsExampleSuggestions();
- break;
- }
- }
-}
diff --git a/plugins/custom-admin-settings-tab/index.php b/plugins/custom-admin-settings-tab/index.php
deleted file mode 100644
index 306db50fa..000000000
--- a/plugins/custom-admin-settings-tab/index.php
+++ /dev/null
@@ -1,34 +0,0 @@
-UseLangs(true); // start use langs folder
-
- $this->addJs('js/CustomAdminSettings.js', true); // add js file
-
- $this->addJsonHook('JsonAdminGetData', 'JsonAdminGetData');
-
- $this->addTemplate('templates/PluginCustomAdminSettingsTab.html', true);
- }
-
- /**
- * @return array
- */
- public function JsonAdminGetData()
- {
- return $this->jsonResponse(__FUNCTION__, array(
- 'PHP' => phpversion()
- ));
- }
-}
-
diff --git a/plugins/custom-admin-settings-tab/js/CustomAdminSettings.js b/plugins/custom-admin-settings-tab/js/CustomAdminSettings.js
deleted file mode 100644
index 20bd0d6f5..000000000
--- a/plugins/custom-admin-settings-tab/js/CustomAdminSettings.js
+++ /dev/null
@@ -1,44 +0,0 @@
-
-(function () {
-
- if (!window.rl)
- {
- return;
- }
-
- /**
- * @constructor
- */
- function CustomAdminSettings()
- {
- this.php = ko.observable('');
-
- this.loading = ko.observable(false);
- }
-
- CustomAdminSettings.prototype.onBuild = function () // special function
- {
- var self = this;
-
- this.loading(true);
-
- rl.pluginRemoteRequest((iError, oData) => {
-
- self.loading(false);
-
- if (!iError) {
- self.php(oData.Result.PHP || '');
- }
-
- if (rl.Enums.StorageResultType.Abort === iError) {
- // show abort
- }
-
- }, 'JsonAdminGetData');
-
- };
-
- rl.addSettingsViewModelForAdmin(CustomAdminSettings, 'PluginCustomAdminSettingsTab',
- 'SETTINGS_CUSTOM_ADMIN_CUSTOM_TAB_PLUGIN/TAB_NAME', 'custom');
-
-}());
diff --git a/plugins/custom-admin-settings-tab/langs/en.ini b/plugins/custom-admin-settings-tab/langs/en.ini
deleted file mode 100644
index 3d81ab706..000000000
--- a/plugins/custom-admin-settings-tab/langs/en.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[SETTINGS_CUSTOM_ADMIN_CUSTOM_TAB_PLUGIN]
-TAB_NAME = "Custom Extension Tab"
-LEGEND_CUSTOM = "Custom Extension Tab (Example)"
-LABEL_PHP_VERSION = "PHP version"
diff --git a/plugins/custom-admin-settings-tab/langs/ru.ini b/plugins/custom-admin-settings-tab/langs/ru.ini
deleted file mode 100644
index 71fcee232..000000000
--- a/plugins/custom-admin-settings-tab/langs/ru.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[SETTINGS_CUSTOM_ADMIN_CUSTOM_TAB_PLUGIN]
-TAB_NAME = "Плагин"
-LEGEND_CUSTOM = "Плагин (Пример)"
-LABEL_PHP_VERSION = "PHP версия"
\ No newline at end of file
diff --git a/plugins/custom-auth-example/LICENSE b/plugins/custom-auth-example/LICENSE
deleted file mode 100644
index 271342337..000000000
--- a/plugins/custom-auth-example/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2013 RainLoop Team
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/plugins/custom-auth-example/index.php b/plugins/custom-auth-example/index.php
deleted file mode 100644
index 242443500..000000000
--- a/plugins/custom-auth-example/index.php
+++ /dev/null
@@ -1,44 +0,0 @@
-addHook('login.credentials', 'FilterLoginCredentials');
- }
-
- /**
- * @param string $sEmail
- * @param string $sLogin
- * @param string $sPassword
- *
- * @throws \RainLoop\Exceptions\ClientException
- */
- public function FilterLoginCredentials(&$sEmail, &$sLogin, &$sPassword)
- {
- // Your custom php logic
- // You may change login credentials
- if ('demo@snappymail.eu' === $sEmail)
- {
- $sEmail = 'user@snappymail.eu';
- $sLogin = 'user@snappymail.eu';
- $sPassword = 'super-puper-password';
- }
- else
- {
- // or throw auth exeption
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
- // or
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountNotAllowed);
- // or
- throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::DomainNotAllowed);
- }
- }
-}
diff --git a/plugins/custom-settings-tab/LICENSE b/plugins/custom-settings-tab/LICENSE
deleted file mode 100644
index 4aed64b3a..000000000
--- a/plugins/custom-settings-tab/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 RainLoop Team
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/plugins/custom-settings-tab/index.php b/plugins/custom-settings-tab/index.php
deleted file mode 100644
index cee8ecf12..000000000
--- a/plugins/custom-settings-tab/index.php
+++ /dev/null
@@ -1,62 +0,0 @@
-UseLangs(true); // start use langs folder
-
- $this->addJs('js/CustomUserSettings.js'); // add js file
-
- $this->addJsonHook('JsonGetCustomUserData', 'JsonGetCustomUserData');
- $this->addJsonHook('JsonSaveCustomUserData', 'JsonSaveCustomUserData');
-
- $this->addTemplate('templates/PluginCustomSettingsTab.html');
- }
-
- /**
- * @return array
- */
- public function JsonGetCustomUserData()
- {
- $aSettings = $this->getUserSettings();
-
- $sUserFacebook = isset($aSettings['UserFacebook']) ? $aSettings['UserFacebook'] : '';
- $sUserSkype = isset($aSettings['UserSkype']) ? $aSettings['UserSkype'] : '';
-
- // or get user's data from your custom storage ( DB / LDAP / ... ).
-
- \sleep(1);
- return $this->jsonResponse(__FUNCTION__, array(
- 'UserFacebook' => $sUserFacebook,
- 'UserSkype' => $sUserSkype
- ));
- }
-
- /**
- * @return array
- */
- public function JsonSaveCustomUserData()
- {
- $sUserFacebook = $this->jsonParam('UserFacebook');
- $sUserSkype = $this->jsonParam('UserSkype');
-
- // or put user's data to your custom storage ( DB / LDAP / ... ).
-
- \sleep(1);
- return $this->jsonResponse(__FUNCTION__, $this->saveUserSettings(array(
- 'UserFacebook' => $sUserFacebook,
- 'UserSkype' => $sUserSkype
- )));
- }
-
-}
-
diff --git a/plugins/custom-settings-tab/js/CustomUserSettings.js b/plugins/custom-settings-tab/js/CustomUserSettings.js
deleted file mode 100644
index 85b7f5241..000000000
--- a/plugins/custom-settings-tab/js/CustomUserSettings.js
+++ /dev/null
@@ -1,81 +0,0 @@
-
-(function () {
-
- if (!window.rl)
- {
- return;
- }
-
- /**
- * @constructor
- */
- function CustomUserSettings()
- {
- this.userSkype = ko.observable('');
- this.userFacebook = ko.observable('');
-
- this.loading = ko.observable(false);
- this.saving = ko.observable(false);
-
- this.savingOrLoading = ko.computed(function () {
- return this.loading() || this.saving();
- }, this);
- }
-
- CustomUserSettings.prototype.customJsonSaveData = function ()
- {
- var self = this;
-
- if (this.saving())
- {
- return false;
- }
-
- this.saving(true);
-
- rl.pluginRemoteRequest((iError, oData) => {
-
- self.saving(false);
-
- if (!iError)
- {
- // true
- }
- else if (rl.Enums.StorageResultType.Abort === iError) {
- // show abort
- }
- else
- {
- // false
- }
-
- }, 'JsonSaveCustomUserData', {
- 'UserSkype': this.userSkype(),
- 'UserFacebook': this.userFacebook()
- });
- };
-
- CustomUserSettings.prototype.onBuild = function () // special function
- {
- var self = this;
-
- this.loading(true);
-
- rl.pluginRemoteRequest((iError, oData) => {
-
- self.loading(false);
-
- if (!iError)
- {
- self.userSkype(oData.Result.UserSkype || '');
- self.userFacebook(oData.Result.UserFacebook || '');
- }
-
- }, 'JsonGetCustomUserData');
-
- };
-
- rl.addSettingsViewModel(CustomUserSettings, 'PluginCustomSettingsTab',
- 'SETTINGS_CUSTOM_PLUGIN/TAB_NAME', 'custom');
-
-}());
diff --git a/plugins/custom-settings-tab/langs/en.ini b/plugins/custom-settings-tab/langs/en.ini
deleted file mode 100644
index cb517b757..000000000
--- a/plugins/custom-settings-tab/langs/en.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[SETTINGS_CUSTOM_PLUGIN]
-TAB_NAME = "Custom Extension"
-LEGEND_CUSTOM = "Custom Extension (Example)"
-LABEL_SKYPE = "Skype"
-LABEL_FACEBOOK = "Facebook"
-BUTTON_SAVE = "Save"
diff --git a/plugins/custom-settings-tab/langs/ru.ini b/plugins/custom-settings-tab/langs/ru.ini
deleted file mode 100644
index 6b275600c..000000000
--- a/plugins/custom-settings-tab/langs/ru.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[SETTINGS_CUSTOM_PLUGIN]
-TAB_NAME = "Плагин"
-LEGEND_CUSTOM = "Плагин (Пример)"
-LABEL_SKYPE = "Skype"
-LABEL_FACEBOOK = "Facebook"
-BUTTON_SAVE = "Сохранить"
\ No newline at end of file
diff --git a/plugins/custom-admin-settings-tab/LICENSE b/plugins/example/LICENSE
similarity index 100%
rename from plugins/custom-admin-settings-tab/LICENSE
rename to plugins/example/LICENSE
diff --git a/plugins/example/index.php b/plugins/example/index.php
index 40741b9cc..7bb6a2b68 100644
--- a/plugins/example/index.php
+++ b/plugins/example/index.php
@@ -31,6 +31,22 @@ class ExamplePlugin extends \RainLoop\Plugins\AbstractPlugin
$this->addTemplate(string $sFile, bool $bAdminScope = false);
$this->addTemplateHook(string $sName, string $sPlace, string $sLocalTemplateName, bool $bPrepend = false);
*/
+
+// $this->addHook('login.credentials', 'FilterLoginCredentials');
+
+
+ $this->UseLangs(true); // start use langs folder
+
+ // User Settings tab
+ $this->addJs('js/ExampleUserSettings.js'); // add js file
+ $this->addJsonHook('JsonGetExampleUserData', 'JsonGetExampleUserData');
+ $this->addJsonHook('JsonSaveExampleUserData', 'JsonSaveExampleUserData');
+ $this->addTemplate('templates/ExampleUserSettingsTab.html');
+
+ // Admin Settings tab
+ $this->addJs('js/ExampleAdminSettings.js', true); // add js file
+ $this->addJsonHook('JsonAdminGetData', 'JsonAdminGetData');
+ $this->addTemplate('templates/ExampleAdminSettingsTab.html', true);
}
/**
@@ -61,6 +77,77 @@ class ExamplePlugin extends \RainLoop\Plugins\AbstractPlugin
}
}
+ public function JsonAdminGetData()
+ {
+ return $this->jsonResponse(__FUNCTION__, array(
+ 'PHP' => \phpversion()
+ ));
+ }
+
+ /**
+ * @param string $sEmail
+ * @param string $sLogin
+ * @param string $sPassword
+ *
+ * @throws \RainLoop\Exceptions\ClientException
+ */
+ public function FilterLoginCredentials(&$sEmail, &$sLogin, &$sPassword)
+ {
+ // Your custom php logic
+ // You may change login credentials
+ if ('demo@snappymail.eu' === $sEmail)
+ {
+ $sEmail = 'user@snappymail.eu';
+ $sLogin = 'user@snappymail.eu';
+ $sPassword = 'super-duper-password';
+ }
+ else
+ {
+ // or throw auth exeption
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AuthError);
+ // or
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::AccountNotAllowed);
+ // or
+ throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::DomainNotAllowed);
+ }
+ }
+
+ /**
+ * @return array
+ */
+ public function JsonGetExampleUserData()
+ {
+ $aSettings = $this->getUserSettings();
+
+ $sUserFacebook = isset($aSettings['UserFacebook']) ? $aSettings['UserFacebook'] : '';
+ $sUserSkype = isset($aSettings['UserSkype']) ? $aSettings['UserSkype'] : '';
+
+ // or get user's data from your custom storage ( DB / LDAP / ... ).
+
+ \sleep(1);
+ return $this->jsonResponse(__FUNCTION__, array(
+ 'UserFacebook' => $sUserFacebook,
+ 'UserSkype' => $sUserSkype
+ ));
+ }
+
+ /**
+ * @return array
+ */
+ public function JsonSaveExampleUserData()
+ {
+ $sUserFacebook = $this->jsonParam('UserFacebook');
+ $sUserSkype = $this->jsonParam('UserSkype');
+
+ // or put user's data to your custom storage ( DB / LDAP / ... ).
+
+ \sleep(1);
+ return $this->jsonResponse(__FUNCTION__, $this->saveUserSettings(array(
+ 'UserFacebook' => $sUserFacebook,
+ 'UserSkype' => $sUserSkype
+ )));
+ }
+
/*
public function Config() : \RainLoop\Config\Plugin
public function Description() : string
diff --git a/plugins/example/js/ExampleAdminSettings.js b/plugins/example/js/ExampleAdminSettings.js
new file mode 100644
index 000000000..5a52ecfda
--- /dev/null
+++ b/plugins/example/js/ExampleAdminSettings.js
@@ -0,0 +1,37 @@
+
+(rl => { if (rl) {
+
+ class ExampleAdminSettings
+ {
+ constructor()
+ {
+ this.php = ko.observable('');
+ this.loading = ko.observable(false);
+ }
+
+ onBuild()
+ {
+ this.loading(true);
+
+ rl.pluginRemoteRequest((iError, oData) => {
+
+ this.loading(false);
+
+ if (iError) {
+ console.error({
+ iError: iError,
+ oData: oData
+ });
+ } else {
+ this.php(oData.Result.PHP || '');
+ }
+
+ }, 'JsonAdminGetData');
+
+ }
+ }
+
+ rl.addSettingsViewModelForAdmin(ExampleAdminSettings, 'ExampleAdminSettingsTab',
+ 'SETTINGS_EXAMPLE_ADMIN_EXAMPLE_TAB_PLUGIN/TAB_NAME', 'Example');
+
+}})(window.rl);
diff --git a/plugins/example/js/ExampleUserSettings.js b/plugins/example/js/ExampleUserSettings.js
new file mode 100644
index 000000000..839e9e84a
--- /dev/null
+++ b/plugins/example/js/ExampleUserSettings.js
@@ -0,0 +1,68 @@
+
+(rl => { if (rl) {
+
+ class ExampleUserSettings
+ {
+ constructor()
+ {
+ this.userSkype = ko.observable('');
+ this.userFacebook = ko.observable('');
+
+ this.loading = ko.observable(false);
+ this.saving = ko.observable(false);
+
+ this.savingOrLoading = ko.computed(() => {
+ return this.loading() || this.saving();
+ });
+ }
+
+ exampleJsonSaveData()
+ {
+ if (!this.saving()) {
+ this.saving(true);
+
+ rl.pluginRemoteRequest((iError, oData) => {
+
+ this.saving(false);
+
+ if (iError) {
+ console.error({
+ iError: iError,
+ oData: oData
+ });
+ } else {
+ console.dir({
+ iError: iError,
+ oData: oData
+ });
+ }
+
+ }, 'JsonSaveExampleUserData', {
+ 'UserSkype': this.userSkype(),
+ 'UserFacebook': this.userFacebook()
+ });
+ }
+ }
+
+ onBuild()
+ {
+ this.loading(true);
+
+ rl.pluginRemoteRequest((iError, oData) => {
+
+ this.loading(false);
+
+ if (!iError) {
+ self.userSkype(oData.Result.UserSkype || '');
+ self.userFacebook(oData.Result.UserFacebook || '');
+ }
+
+ }, 'JsonGetExampleUserData');
+
+ }
+ }
+
+ rl.addSettingsViewModel(ExampleUserSettings, 'ExampleUserSettingsTab',
+ 'SETTINGS_EXAMPLE_PLUGIN/TAB_NAME', 'Example');
+
+}})(window.rl);
diff --git a/plugins/example/langs/en.json b/plugins/example/langs/en.json
new file mode 100644
index 000000000..9c5f0c84c
--- /dev/null
+++ b/plugins/example/langs/en.json
@@ -0,0 +1,15 @@
+{
+ "SETTINGS_EXAMPLE_ADMIN_EXAMPLE_TAB_PLUGIN": {
+ "TAB_NAME": "Example Extension Tab",
+ "LEGEND_EXAMPLE": "Example Extension Tab (Example)",
+ "LABEL_PHP_VERSION": "PHP version"
+ },
+ "SETTINGS_EXAMPLE_PLUGIN": {
+ "TAB_NAME": "Example Extension",
+ "LEGEND_EXAMPLE": "Example Extension (Example)",
+ "LABEL_PHP_VERSION": "PHP version",
+ "LABEL_SKYPE": "Skype",
+ "LABEL_FACEBOOK": "Facebook",
+ "BUTTON_SAVE": "Save"
+ }
+}
diff --git a/plugins/custom-admin-settings-tab/templates/PluginCustomAdminSettingsTab.html b/plugins/example/templates/ExampleAdminSettingsTab.html
similarity index 64%
rename from plugins/custom-admin-settings-tab/templates/PluginCustomAdminSettingsTab.html
rename to plugins/example/templates/ExampleAdminSettingsTab.html
index cab9229a7..8fc98c5fc 100644
--- a/plugins/custom-admin-settings-tab/templates/PluginCustomAdminSettingsTab.html
+++ b/plugins/example/templates/ExampleAdminSettingsTab.html
@@ -1,17 +1,17 @@
\ No newline at end of file
+
diff --git a/plugins/custom-settings-tab/templates/PluginCustomSettingsTab.html b/plugins/example/templates/ExampleUserSettingsTab.html
similarity index 66%
rename from plugins/custom-settings-tab/templates/PluginCustomSettingsTab.html
rename to plugins/example/templates/ExampleUserSettingsTab.html
index 1b688168b..3bbfad069 100644
--- a/plugins/custom-settings-tab/templates/PluginCustomSettingsTab.html
+++ b/plugins/example/templates/ExampleUserSettingsTab.html
@@ -1,13 +1,13 @@
|