├── .azure ├── linux.yml ├── macos.yml ├── web.yaml ├── windows.yml └── wx.yml ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── stale.yml ├── .gitignore ├── .pylintrc ├── .vscode ├── cspell.json ├── launch.json ├── settings.json └── tasks.json ├── BUILD.md ├── CAPABILITIES.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── FAQ.md ├── LICENSE.md ├── LICENSING_INFO.md ├── README.md ├── ROADMAP.md ├── crowdin.yml ├── docs └── update.json ├── eslint.config.mjs ├── gulp ├── gulpfile.app.mjs ├── gulpfile.common.https.mjs ├── gulpfile.common.mjs ├── gulpfile.testing.mjs ├── gulpfile.web.mjs └── gulpfile.wx.mjs ├── gulpfile.mjs ├── package-lock.json ├── package.json ├── src ├── TODO.md ├── app │ ├── app.html │ ├── app.mjs │ ├── css │ │ └── navbar-top-fixed.css │ ├── libs │ │ ├── libManageSieve │ │ │ ├── README.md │ │ │ ├── SieveAutoConfig.mjs │ │ │ ├── SieveBase64.mjs │ │ │ ├── SieveClient.mjs │ │ │ ├── SieveSession.mjs │ │ │ ├── SieveSessions.mjs │ │ │ └── SieveTimer.mjs │ │ └── managesieve.ui │ │ │ ├── accounts.html │ │ │ ├── accounts.mjs │ │ │ ├── accounts │ │ │ ├── SieveAccountCreateUI.mjs │ │ │ ├── SieveAccountUI.mjs │ │ │ ├── SieveAccounts.mjs │ │ │ ├── account.dialog.create.html │ │ │ ├── account.settings.html │ │ │ └── accounts.html │ │ │ ├── importer │ │ │ ├── logic │ │ │ │ └── SieveThunderbirdProfile.mjs │ │ │ ├── tests │ │ │ │ ├── SieveThunderbirdProfileTest.mjs │ │ │ │ └── Thunderbird │ │ │ │ │ ├── empty.ini │ │ │ │ │ ├── prefs.js │ │ │ │ │ └── profiles.ini │ │ │ └── ui │ │ │ │ ├── SieveImportUI.mjs │ │ │ │ ├── account.import.html │ │ │ │ └── account.import.item.html │ │ │ ├── settings │ │ │ ├── logic │ │ │ │ ├── SieveAccount.mjs │ │ │ │ ├── SieveAccounts.mjs │ │ │ │ ├── SieveAuthentication.mjs │ │ │ │ ├── SieveAuthorization.mjs │ │ │ │ ├── SieveHost.mjs │ │ │ │ ├── SievePrefManager.mjs │ │ │ │ └── SieveSecurity.mjs │ │ │ └── ui │ │ │ │ ├── SieveCredentialSettingsUI.mjs │ │ │ │ ├── SieveServerSettingsUI.mjs │ │ │ │ ├── settings.credentials.html │ │ │ │ └── settings.server.html │ │ │ ├── tabs │ │ │ ├── SieveTabsUI.mjs │ │ │ ├── editor.content.html │ │ │ └── editor.tab.html │ │ │ ├── updater │ │ │ ├── SieveUpdater.mjs │ │ │ ├── SieveUpdaterUI.mjs │ │ │ ├── tests │ │ │ │ └── SieveUpdaterTest.mjs │ │ │ └── update.html │ │ │ └── utils │ │ │ └── SieveIpcClient.mjs │ ├── main_esm.js │ └── sieve.mjs ├── common │ ├── appImage │ │ ├── AppRun │ │ ├── sieve.desktop │ │ └── sieve.png │ ├── icons │ │ ├── linux.png │ │ ├── mac.icns │ │ └── win.ico │ ├── libManageSieve │ │ ├── SieveAbstractBase64.mjs │ │ ├── SieveAbstractClient.mjs │ │ ├── SieveAbstractSession.mjs │ │ ├── SieveAbstractTimer.mjs │ │ ├── SieveCompatibility.mjs │ │ ├── SieveCrypto.mjs │ │ ├── SieveExceptions.mjs │ │ ├── SieveLogger.mjs │ │ ├── SieveRequest.mjs │ │ ├── SieveRequestBuilder.mjs │ │ ├── SieveResponse.mjs │ │ ├── SieveResponseCodes.mjs │ │ ├── SieveResponseParser.mjs │ │ ├── SieveUrl.mjs │ │ ├── doc │ │ │ ├── HMAC │ │ │ │ ├── rfc2104.txt │ │ │ │ └── rfc4086.txt │ │ │ ├── IMAP4 Referrals │ │ │ │ └── rfc2221.txt │ │ │ ├── Manage Sieve │ │ │ │ ├── draft-martin-managesieve-06.txt │ │ │ │ ├── draft-martin-managesieve-08.txt │ │ │ │ └── rfc5804.txt │ │ │ ├── SASL CRAM │ │ │ │ └── rfc2195.txt │ │ │ ├── SASL LOGIN │ │ │ │ └── draft-murchison-sasl-login-00.txt │ │ │ ├── SASL PLAIN │ │ │ │ └── rfc4616.txt │ │ │ ├── SASL SCRAM │ │ │ │ ├── PKCS #5 │ │ │ │ │ ├── rfc2898.txt │ │ │ │ │ └── rfc6070.txt │ │ │ │ ├── draft-melnikov-scram-sha-512-01.txt │ │ │ │ ├── rfc5802.txt │ │ │ │ └── rfc7677.txt │ │ │ └── rfc6234.txt │ │ └── tests │ │ │ ├── SieveBase64Test.mjs │ │ │ ├── SieveCryptoTest.mjs │ │ │ ├── SieveSaslRequestTest.mjs │ │ │ └── SieveUrl.mjs │ ├── libSieve │ │ ├── README.md │ │ ├── SieveGui.html │ │ ├── SieveGui.mjs │ │ ├── TODO.md │ │ ├── extensions │ │ │ ├── RFC5228 │ │ │ │ ├── logic │ │ │ │ │ ├── SieveActions.mjs │ │ │ │ │ ├── SieveAddressParts.mjs │ │ │ │ │ ├── SieveBlocks.mjs │ │ │ │ │ ├── SieveComparators.mjs │ │ │ │ │ ├── SieveConditions.mjs │ │ │ │ │ ├── SieveImports.mjs │ │ │ │ │ ├── SieveMatchTypes.mjs │ │ │ │ │ ├── SieveNumbers.mjs │ │ │ │ │ ├── SieveOperators.mjs │ │ │ │ │ ├── SieveStrings.mjs │ │ │ │ │ ├── SieveTests.mjs │ │ │ │ │ └── SieveWhiteSpaces.mjs │ │ │ │ ├── rfc5228.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveAddressPartAll.html │ │ │ │ │ ├── SieveAddressPartDomain.html │ │ │ │ │ ├── SieveAddressPartLocal.html │ │ │ │ │ ├── SieveAddressTestUI.html │ │ │ │ │ ├── SieveAllOfAnyOfOperator.html │ │ │ │ │ ├── SieveBooleanTest.html │ │ │ │ │ ├── SieveComparatorAsciiCasemap.html │ │ │ │ │ ├── SieveComparatorAsciiNumeric.html │ │ │ │ │ ├── SieveComparatorOctet.html │ │ │ │ │ ├── SieveDiscardActionUI.html │ │ │ │ │ ├── SieveEnvelopeTestUI.html │ │ │ │ │ ├── SieveExistsTestUI.html │ │ │ │ │ ├── SieveFileIntoActionUI.html │ │ │ │ │ ├── SieveHeaderTestUI.html │ │ │ │ │ ├── SieveKeepActionUI.html │ │ │ │ │ ├── SieveMatchTypeContainsUI.html │ │ │ │ │ ├── SieveMatchTypeIsUI.html │ │ │ │ │ ├── SieveMatchTypeMatchesUI.html │ │ │ │ │ ├── SieveRedirectActionUI.html │ │ │ │ │ ├── SieveSizeTestUI.html │ │ │ │ │ └── SieveStopActionUI.html │ │ │ │ ├── tests │ │ │ │ │ ├── SieveMatchTypeTest.mjs │ │ │ │ │ ├── SieveRFC5228AtomsTest.mjs │ │ │ │ │ ├── SieveRFC5228ScriptTest.mjs │ │ │ │ │ └── SieveRFC5228SnippetTest.mjs │ │ │ │ └── widgets │ │ │ │ │ ├── SieveActionsUI.mjs │ │ │ │ │ ├── SieveAddressPartUI.mjs │ │ │ │ │ ├── SieveBlocksUI.mjs │ │ │ │ │ ├── SieveComparatorsUI.mjs │ │ │ │ │ ├── SieveConditionsUI.mjs │ │ │ │ │ ├── SieveMatchTypesUI.mjs │ │ │ │ │ ├── SieveOperatorsUI.mjs │ │ │ │ │ └── SieveTestsUI.mjs │ │ │ ├── body │ │ │ │ ├── logic │ │ │ │ │ └── SieveBody.mjs │ │ │ │ ├── rfc5173.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveBodyTestUI.html │ │ │ │ │ ├── SieveBodyTransformContent.html │ │ │ │ │ ├── SieveBodyTransformRaw.html │ │ │ │ │ └── SieveBodyTransformText.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveBodyTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveBodyUI.mjs │ │ │ ├── convert │ │ │ │ ├── logic │ │ │ │ │ └── SieveConvert.mjs │ │ │ │ ├── rfc6558.txt │ │ │ │ ├── templates │ │ │ │ │ └── SieveConvertUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveConvertTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveConvertUI.mjs │ │ │ ├── copy │ │ │ │ ├── logic │ │ │ │ │ └── SieveCopy.mjs │ │ │ │ ├── rfc3894.txt │ │ │ │ ├── templates │ │ │ │ │ └── SieveCopyTag.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveCopyTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveCopyUI.mjs │ │ │ ├── date │ │ │ │ ├── logic │ │ │ │ │ └── SieveDate.mjs │ │ │ │ ├── rfc5260.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveCurrentDateTestUI.html │ │ │ │ │ ├── SieveDateTestUI.html │ │ │ │ │ ├── SieveZoneCustom.html │ │ │ │ │ └── SieveZoneOriginal.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveDateTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveDateUI.mjs │ │ │ ├── duplicate │ │ │ │ ├── logic │ │ │ │ │ └── SieveDuplicate.mjs │ │ │ │ ├── rfc7352.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveDuplicateTestUI.html │ │ │ │ │ ├── SieveUniqueDefault.html │ │ │ │ │ ├── SieveUniqueHeader.html │ │ │ │ │ └── SieveUniqueId.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveDuplicateTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveDuplicateUI.mjs │ │ │ ├── editheader │ │ │ │ ├── logic │ │ │ │ │ └── SieveEditheader.mjs │ │ │ │ ├── rfc5293.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveAddHeaderActionUI.html │ │ │ │ │ └── SieveDeleteHeaderActionUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveEditheaderTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveEditheaderUI.mjs │ │ │ ├── environment │ │ │ │ ├── logic │ │ │ │ │ └── SieveEnvironment.mjs │ │ │ │ ├── rfc5183.txt │ │ │ │ ├── templates │ │ │ │ │ └── SieveEnvironmentUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveEnvironmentTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveEnvironmentUI.mjs │ │ │ ├── extensions.mjs │ │ │ ├── imapflags │ │ │ │ ├── logic │ │ │ │ │ └── SieveImapFlags.mjs │ │ │ │ ├── rfc5232.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveAddFlagActionUI.html │ │ │ │ │ ├── SieveFlagsTag.html │ │ │ │ │ ├── SieveHasFlagTestUI.html │ │ │ │ │ ├── SieveRemoveFlagActionUI.html │ │ │ │ │ └── SieveSetFlagActionUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveImapFlagsTest.mjs │ │ │ │ ├── widgets │ │ │ │ │ └── SieveImapFlagsUI.mjs │ │ │ │ └── work.txt │ │ │ ├── include │ │ │ │ ├── logic │ │ │ │ │ └── SieveInclude.mjs │ │ │ │ ├── rfc6609.txt │ │ │ │ ├── template │ │ │ │ │ ├── SieveGlobalActionUI.html │ │ │ │ │ ├── SieveIncludeActionUI.html │ │ │ │ │ └── SieveReturnActionUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveIncludeTest.mjs │ │ │ │ └── widget │ │ │ │ │ └── SieveIncludeUI.mjs │ │ │ ├── mailbox │ │ │ │ ├── logic │ │ │ │ │ └── SieveMailbox.mjs │ │ │ │ ├── rfc5490.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveCreateTag.html │ │ │ │ │ ├── SieveMailboxExistsTest.html │ │ │ │ │ ├── SieveMetaDataExistsTest.html │ │ │ │ │ ├── SieveMetaDataTest.html │ │ │ │ │ ├── SieveServerMetaDataExistsTest.html │ │ │ │ │ └── SieveServerMetaDataTest.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveMailboxTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveMailboxUI.mjs │ │ │ ├── mime │ │ │ │ ├── logic │ │ │ │ │ └── SieveMime.mjs │ │ │ │ ├── rfc5703.txt │ │ │ │ └── tests │ │ │ │ │ └── SieveMimeTest.mjs │ │ │ ├── notify │ │ │ │ ├── logic │ │ │ │ │ └── SieveNotify.mjs │ │ │ │ ├── rfc5435.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveEncodeUrlUI.html │ │ │ │ │ ├── SieveNotifyActionUI.html │ │ │ │ │ ├── SieveNotifyMethodCapabilityTestUI.html │ │ │ │ │ └── SieveValidNotifyMethodTestUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveNotifyTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveNotifyUI.mjs │ │ │ ├── pipe │ │ │ │ ├── logic │ │ │ │ │ └── SievePipe.mjs │ │ │ │ ├── spec-bosch-sieve-extprograms.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveExecuteUI.html │ │ │ │ │ ├── SieveFilterUI.html │ │ │ │ │ └── SievePipeUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SievePipeTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SievePipeUI.mjs │ │ │ ├── regex │ │ │ │ ├── draft-ieft-sieve-regex-01.txt │ │ │ │ ├── logic │ │ │ │ │ └── SieveRegularExpression.mjs │ │ │ │ ├── templates │ │ │ │ │ └── SieveMatchTypeRegExUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveRegExTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveRegularExpressionUI.mjs │ │ │ ├── reject │ │ │ │ ├── logic │ │ │ │ │ └── SieveReject.mjs │ │ │ │ ├── rfc5429.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveExtendedRejectActionUI.html │ │ │ │ │ └── SieveRejectActionUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveRejectTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveRejectUI.mjs │ │ │ ├── relational │ │ │ │ ├── logic │ │ │ │ │ └── SieveRelational.mjs │ │ │ │ ├── rfc5231.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveMatchTypeCountUI.html │ │ │ │ │ └── SieveMatchTypeValueUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveRelationalTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveRelationalUI.mjs │ │ │ ├── spamtest │ │ │ │ ├── logic │ │ │ │ │ └── SieveSpamtest.mjs │ │ │ │ ├── rfc5235.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveSpamtestPlusValue.html │ │ │ │ │ ├── SieveSpamtestUI.html │ │ │ │ │ ├── SieveSpamtestValue.html │ │ │ │ │ └── SieveVirustestUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SpamtestTests.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveSpamtestUI.mjs │ │ │ ├── subaddress │ │ │ │ ├── logic │ │ │ │ │ └── SieveSubaddress.mjs │ │ │ │ ├── rfc5233.txt │ │ │ │ ├── templates │ │ │ │ │ ├── SieveAddressPartDetail.html │ │ │ │ │ └── SieveAddressPartUser.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveSubaddressTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveSubaddressUI.mjs │ │ │ ├── vacation-seconds │ │ │ │ ├── logic │ │ │ │ │ └── SieveVacationSeconds.mjs │ │ │ │ ├── rfc6131.txt │ │ │ │ ├── template │ │ │ │ │ └── SieveVacationIntervalSecondsUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveVacationSecondsTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveVacationSecondsUI.mjs │ │ │ ├── vacation │ │ │ │ ├── logic │ │ │ │ │ └── SieveVacation.mjs │ │ │ │ ├── rfc5230.txt │ │ │ │ ├── template │ │ │ │ │ ├── SieveVacationIntervalDaysUI.html │ │ │ │ │ ├── SieveVacationIntervalDefaultUI.html │ │ │ │ │ └── SieveVacationUI.html │ │ │ │ ├── tests │ │ │ │ │ └── SieveVacationTest.mjs │ │ │ │ └── widgets │ │ │ │ │ └── SieveVacationUI.mjs │ │ │ └── variables │ │ │ │ ├── logic │ │ │ │ └── SieveVariables.mjs │ │ │ │ ├── rfc5229.txt │ │ │ │ ├── templates │ │ │ │ ├── SieveCaseFirstUI.html │ │ │ │ ├── SieveCaseUI.html │ │ │ │ ├── SieveLengthUI.html │ │ │ │ ├── SieveQuotewildcardUI.html │ │ │ │ ├── SieveSetActionUI.html │ │ │ │ └── SieveStringTestUI.html │ │ │ │ ├── tests │ │ │ │ └── SieveVariablesTest.mjs │ │ │ │ └── widgets │ │ │ │ └── SieveVariablesUI.mjs │ │ ├── i18n │ │ │ ├── af-ZA.json │ │ │ ├── ar-SA.json │ │ │ ├── ca-ES.json │ │ │ ├── cs-CZ.json │ │ │ ├── da-DK.json │ │ │ ├── de-DE.json │ │ │ ├── el-GR.json │ │ │ ├── en-US.json │ │ │ ├── es-ES.json │ │ │ ├── fi-FI.json │ │ │ ├── fr-FR.json │ │ │ ├── he-IL.json │ │ │ ├── hu-HU.json │ │ │ ├── id-ID.json │ │ │ ├── it-IT.json │ │ │ ├── ja-JP.json │ │ │ ├── ko-KR.json │ │ │ ├── nl-NL.json │ │ │ ├── no-NO.json │ │ │ ├── pl-PL.json │ │ │ ├── pt-BR.json │ │ │ ├── pt-PT.json │ │ │ ├── ro-RO.json │ │ │ ├── ru-RU.json │ │ │ ├── sk-SK.json │ │ │ ├── sr-SP.json │ │ │ ├── sv-SE.json │ │ │ ├── tr-TR.json │ │ │ ├── uk-UA.json │ │ │ ├── vi-VN.json │ │ │ ├── zh-CN.json │ │ │ └── zh-TW.json │ │ ├── templates │ │ │ ├── debug.html │ │ │ └── sidebar.html │ │ ├── tests │ │ │ ├── ScriptValidator.mjs │ │ │ ├── SieveDovecotTest.mjs │ │ │ ├── SieveFastMailTest.mjs │ │ │ └── SieveTty1Test.mjs │ │ └── toolkit │ │ │ ├── SieveDesigner.mjs │ │ │ ├── SieveLexer.mjs │ │ │ ├── SieveParser.mjs │ │ │ ├── SieveScriptDOM.mjs │ │ │ ├── events │ │ │ ├── DataTransfer.mjs │ │ │ ├── DragHandler.mjs │ │ │ └── DropHandler.mjs │ │ │ ├── gramar.txt │ │ │ ├── logic │ │ │ ├── AbstractElements.mjs │ │ │ ├── GenericAtoms.mjs │ │ │ ├── GenericCapabilities.mjs │ │ │ └── GenericElements.mjs │ │ │ ├── style │ │ │ ├── hline.png │ │ │ ├── layout.css │ │ │ ├── style.css │ │ │ ├── trash-full.png │ │ │ ├── trash.png │ │ │ ├── vline.png │ │ │ └── vline2.png │ │ │ ├── templates │ │ │ ├── SieveDropDownWidget.html │ │ │ ├── SieveNumericWidget.html │ │ │ ├── SieveStringListWidget.html │ │ │ └── SieveStringWidget.html │ │ │ ├── utils │ │ │ ├── SieveI18n.mjs │ │ │ ├── SieveLogger.mjs │ │ │ └── SieveTemplate.mjs │ │ │ └── widgets │ │ │ ├── Boxes.mjs │ │ │ └── Widgets.mjs │ └── managesieve.ui │ │ ├── accounts │ │ ├── SieveAbstractAccountUI.mjs │ │ ├── SieveAbstractAccounts.mjs │ │ ├── SieveCapabilities.mjs │ │ ├── SieveScriptUI.html │ │ ├── SieveScriptUI.mjs │ │ ├── account.capabilities.html │ │ ├── account.connecting.html │ │ ├── account.disconnected.html │ │ ├── account.disconnecting.html │ │ ├── account.empty.html │ │ └── account.html │ │ ├── dialogs │ │ ├── SieveDialogUI.mjs │ │ ├── dialog.account.authorization.html │ │ ├── dialog.account.cert.html │ │ ├── dialog.account.delete.html │ │ ├── dialog.account.password.html │ │ ├── dialog.error.html │ │ ├── dialog.script.busy.html │ │ ├── dialog.script.create.html │ │ ├── dialog.script.delete.html │ │ ├── dialog.script.rename.html │ │ └── dialog.script.save.html │ │ ├── editor.html │ │ ├── editor.mjs │ │ ├── editor │ │ ├── SieveAbstractEditor.mjs │ │ ├── SieveEditor.mjs │ │ ├── SieveEditorController.mjs │ │ ├── editor.error.save.html │ │ ├── editor.html │ │ ├── editor.settings.defaults.html │ │ ├── graphical │ │ │ └── SieveGraphicalEditor.mjs │ │ └── text │ │ │ ├── SieveTextEditor.mjs │ │ │ ├── editor.plaintext.html │ │ │ ├── editor.plaintext.toolbar.html │ │ │ ├── editor.settings.indentation.html │ │ │ └── editor.settings.syntax.html │ │ ├── i18n │ │ ├── af-ZA.json │ │ ├── ar-SA.json │ │ ├── ca-ES.json │ │ ├── cs-CZ.json │ │ ├── da-DK.json │ │ ├── de-DE.json │ │ ├── el-GR.json │ │ ├── en-US.json │ │ ├── es-ES.json │ │ ├── fi-FI.json │ │ ├── fr-FR.json │ │ ├── he-IL.json │ │ ├── hu-HU.json │ │ ├── id-ID.json │ │ ├── it-IT.json │ │ ├── ja-JP.json │ │ ├── ko-KR.json │ │ ├── nl-NL.json │ │ ├── no-NO.json │ │ ├── pl-PL.json │ │ ├── pt-BR.json │ │ ├── pt-PT.json │ │ ├── ro-RO.json │ │ ├── ru-RU.json │ │ ├── sk-SK.json │ │ ├── sr-SP.json │ │ ├── sv-SE.json │ │ ├── tr-TR.json │ │ ├── uk-UA.json │ │ ├── vi-VN.json │ │ ├── zh-CN.json │ │ └── zh-TW.json │ │ ├── settings │ │ ├── logic │ │ │ ├── SieveAbstractAccount.mjs │ │ │ ├── SieveAbstractAccounts.mjs │ │ │ ├── SieveAbstractAuthentication.mjs │ │ │ ├── SieveAbstractAuthorization.mjs │ │ │ ├── SieveAbstractHost.mjs │ │ │ ├── SieveAbstractMechanism.mjs │ │ │ ├── SieveAbstractPrefManager.mjs │ │ │ ├── SieveAbstractSecurity.mjs │ │ │ ├── SieveAccountSettings.mjs │ │ │ └── SieveEditorSettings.mjs │ │ └── ui │ │ │ ├── SieveDebugSettingsUI.mjs │ │ │ └── settings.debug.html │ │ └── utils │ │ ├── SieveAbstractIpcClient.mjs │ │ ├── SieveI18n.mjs │ │ ├── SieveLogger.mjs │ │ ├── SieveTemplate.mjs │ │ └── SieveUniqueId.mjs ├── web │ ├── README.md │ ├── config.template.ini │ ├── doc │ │ └── rfc6455.txt │ ├── main.py │ ├── script │ │ ├── __init__.py │ │ ├── config │ │ │ └── config.py │ │ ├── handler │ │ │ ├── config.py │ │ │ ├── file.py │ │ │ └── websocket.py │ │ ├── http.py │ │ ├── messagepump.py │ │ ├── sieve │ │ │ ├── __init__.py │ │ │ ├── __main__.py │ │ │ ├── parser.py │ │ │ ├── request.py │ │ │ └── sievesocket.py │ │ ├── webserver.py │ │ └── websocket.py │ └── static │ │ ├── app.html │ │ ├── app.mjs │ │ └── libs │ │ ├── libManageSieve │ │ ├── SieveClient.mjs │ │ ├── SieveSession.mjs │ │ ├── SieveSessions.mjs │ │ └── SieveWebSocketUrl.mjs │ │ └── managesieve.ui │ │ ├── accounts.html │ │ ├── accounts.mjs │ │ ├── accounts │ │ ├── SieveAccountUI.mjs │ │ ├── SieveAccounts.mjs │ │ └── account.settings.html │ │ └── settings │ │ └── logic │ │ ├── SieveAccount.mjs │ │ ├── SieveAccounts.mjs │ │ ├── SieveAuthentication.mjs │ │ ├── SieveAuthorization.mjs │ │ ├── SieveHost.mjs │ │ ├── SievePrefManager.mjs │ │ └── SieveSecurity.mjs └── wx │ ├── _locales │ ├── af_ZA │ │ └── messages.json │ ├── ar_SA │ │ └── messages.json │ ├── ca_ES │ │ └── messages.json │ ├── cs_CZ │ │ └── messages.json │ ├── da_DK │ │ └── messages.json │ ├── de_DE │ │ └── messages.json │ ├── el_GR │ │ └── messages.json │ ├── en_US │ │ └── messages.json │ ├── es_ES │ │ └── messages.json │ ├── fi_FI │ │ └── messages.json │ ├── fr_FR │ │ └── messages.json │ ├── he_IL │ │ └── messages.json │ ├── hu_HU │ │ └── messages.json │ ├── id_ID │ │ └── messages.json │ ├── it_IT │ │ └── messages.json │ ├── ja_JP │ │ └── messages.json │ ├── ko_KR │ │ └── messages.json │ ├── nl_NL │ │ └── messages.json │ ├── no_NO │ │ └── messages.json │ ├── pl_PL │ │ └── messages.json │ ├── pt_BR │ │ └── messages.json │ ├── pt_PT │ │ └── messages.json │ ├── ro_RO │ │ └── messages.json │ ├── ru_RU │ │ └── messages.json │ ├── sk_SK │ │ └── messages.json │ ├── sr_SP │ │ └── messages.json │ ├── sv_SE │ │ └── messages.json │ ├── tr_TR │ │ └── messages.json │ ├── uk_UA │ │ └── messages.json │ ├── vi_VN │ │ └── messages.json │ ├── zh_CN │ │ └── messages.json │ └── zh_TW │ │ └── messages.json │ ├── api │ └── sieve │ │ ├── SieveAccountsApi.js │ │ ├── SieveAccountsApi.json │ │ ├── SieveMenuApi.js │ │ ├── SieveMenuApi.json │ │ ├── SieveSocketApi.js │ │ └── SieveSocketApi.json │ ├── background.html │ ├── background.mjs │ ├── libs │ ├── libManageSieve │ │ ├── SieveBase64.mjs │ │ ├── SieveClient.mjs │ │ ├── SieveSession.mjs │ │ └── SieveTimer.mjs │ └── managesieve.ui │ │ ├── accounts.html │ │ ├── accounts.mjs │ │ ├── accounts │ │ ├── SieveAccountUI.mjs │ │ ├── SieveAccounts.mjs │ │ └── account.settings.html │ │ ├── settings │ │ └── logic │ │ │ ├── SieveAccounts.mjs │ │ │ ├── SieveAuthentication.mjs │ │ │ ├── SieveAuthorization.mjs │ │ │ ├── SieveHost.mjs │ │ │ ├── SievePrefManager.mjs │ │ │ └── SieveSecurity.mjs │ │ └── utils │ │ └── SieveIpcClient.js │ └── manifest.json ├── tests ├── index.html ├── index.js ├── js │ ├── browser │ │ ├── BrowserTestReport.js │ │ ├── BrowserTestSuite.js │ │ ├── index.js │ │ └── sandbox │ │ │ ├── Sandbox.mjs │ │ │ └── sandbox.html │ ├── common │ │ ├── AbstractTestReport.js │ │ ├── AbstractTestSuite.js │ │ └── sandbox │ │ │ └── AbstractSandboxedFixture.mjs │ ├── exporter │ │ └── JUnitExporter.js │ ├── node │ │ ├── NodeTestReport.js │ │ ├── NodeTestSuite.js │ │ └── sandbox │ │ │ └── Sandbox.mjs │ └── style.css └── tests │ └── tests.js └── tools ├── .gitignore ├── Docker └── dovecot │ ├── README.md │ ├── dockerfile │ ├── dovecot-openssl.conf │ └── local.conf ├── GSSAPI Proxy └── gssapi-sieve-proxy.pl └── Server └── Server.js /.azure/macos.yml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js project with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript 5 | 6 | jobs: 7 | - job: macOS 8 | pool: 9 | vmImage: 'macOS-latest' 10 | steps: 11 | - task: NodeTool@0 12 | inputs: 13 | versionSpec: '>=16.x' 14 | 15 | - script: npm install 16 | displayName: "Install Dependencies" 17 | 18 | - script: npm run gulp clean 19 | displayName: "Clean Workspace" 20 | 21 | - script: npm run lint 22 | displayName: "Running ESLint" 23 | 24 | - script: npm run test 25 | displayName: "Running Unit Tests" 26 | 27 | - task: PublishTestResults@2 28 | inputs: 29 | testResultsFormat: 'JUnit' 30 | testResultsFiles: '**/TEST-*.xml' 31 | 32 | - script: npm run gulp "app:package-macos" 33 | displayName: "Package macOS Artifacts" 34 | 35 | - script: npm run gulp "app:zip-macos" 36 | displayName: "Package and Zip macOS Artifacts" 37 | 38 | - task: CopyFiles@2 39 | inputs: 40 | Contents: 'build/*.zip' 41 | TargetFolder: '$(build.artifactstagingdirectory)/app' 42 | OverWrite: true 43 | 44 | - task: PublishBuildArtifacts@1 45 | inputs: 46 | pathtoPublish: '$(Build.ArtifactStagingDirectory)/app' 47 | artifactName: "Zip - macOS Application" 48 | -------------------------------------------------------------------------------- /.azure/web.yaml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js project with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript 5 | 6 | jobs: 7 | - job: WebApplication 8 | pool: 9 | vmImage: 'ubuntu-latest' 10 | steps: 11 | 12 | - task: NodeTool@0 13 | inputs: 14 | versionSpec: '>=16.x' 15 | 16 | - script: npm install 17 | displayName: "Install Dependencies" 18 | 19 | - script: npm run gulp clean 20 | displayName: "Clean Workspace" 21 | 22 | - script: npm run lint 23 | displayName: "Running ESLint" 24 | 25 | - script: npm run test 26 | displayName: "Running Unit Tests" 27 | 28 | - task: PublishTestResults@2 29 | inputs: 30 | testResultsFormat: 'JUnit' 31 | testResultsFiles: '**/TEST-*.xml' 32 | 33 | - script: npm run gulp "web:package-zip" 34 | displayName: "Package and Zip Web Application Artifact" 35 | 36 | - task: CopyFiles@2 37 | inputs: 38 | Contents: 'build/*' 39 | TargetFolder: '$(build.artifactstagingdirectory)' 40 | OverWrite: true 41 | CleanTargetFolder: true 42 | 43 | - task: PublishBuildArtifacts@1 44 | inputs: 45 | pathtoPublish: '$(Build.ArtifactStagingDirectory)/build' 46 | artifactName: "Zip - Web Application" 47 | 48 | -------------------------------------------------------------------------------- /.azure/windows.yml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js project with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript 5 | 6 | jobs: 7 | - job: Windows 8 | pool: 9 | vmImage: 'windows-latest' 10 | steps: 11 | 12 | - task: NodeTool@0 13 | inputs: 14 | versionSpec: '>=16.x' 15 | 16 | - script: npm install 17 | displayName: "Install Dependencies" 18 | 19 | - script: npm run gulp "clean" 20 | displayName: "Clean Workspace" 21 | 22 | - script: npm run lint 23 | displayName: "Running ESLint" 24 | 25 | - script: npm run test 26 | displayName: "Running Unit Tests" 27 | 28 | - task: PublishTestResults@2 29 | inputs: 30 | testResultsFormat: 'JUnit' 31 | testResultsFiles: '**/TEST-*.xml' 32 | 33 | - script: npm run gulp "app:zip-win32" 34 | displayName: "Package and Zip Windows Artifact" 35 | 36 | - task: CopyFiles@2 37 | inputs: 38 | Contents: 'build/*' 39 | TargetFolder: '$(build.artifactstagingdirectory)' 40 | OverWrite: true 41 | 42 | - task: PublishBuildArtifacts@1 43 | inputs: 44 | pathtoPublish: '$(Build.ArtifactStagingDirectory)' 45 | artifactName: "Zip - Windows Application" 46 | -------------------------------------------------------------------------------- /.azure/wx.yml: -------------------------------------------------------------------------------- 1 | # Node.js 2 | # Build a general Node.js project with npm. 3 | # Add steps that analyze code, save build artifacts, deploy, and more: 4 | # https://docs.microsoft.com/azure/devops/pipelines/languages/javascript 5 | 6 | jobs: 7 | - job: WebExtension 8 | pool: 9 | vmImage: 'ubuntu-latest' 10 | steps: 11 | 12 | - task: NodeTool@0 13 | inputs: 14 | versionSpec: '>=16.x' 15 | 16 | - script: npm install 17 | displayName: "Install Dependencies" 18 | 19 | - script: npm run gulp clean 20 | displayName: "Clean Workspace" 21 | 22 | - script: npm run lint 23 | displayName: "Running ESLint" 24 | 25 | - script: npm run test 26 | displayName: "Running Unit Tests" 27 | 28 | - task: PublishTestResults@2 29 | inputs: 30 | testResultsFormat: 'JUnit' 31 | testResultsFiles: '**/TEST-*.xml' 32 | 33 | - script: npm run gulp "wx:package-xpi" 34 | displayName: "Package and Zip WebExtension Artifact" 35 | 36 | - task: CopyFiles@2 37 | inputs: 38 | Contents: 'build/*' 39 | TargetFolder: '$(build.artifactstagingdirectory)' 40 | OverWrite: true 41 | CleanTargetFolder: true 42 | 43 | - task: PublishBuildArtifacts@1 44 | inputs: 45 | pathtoPublish: '$(Build.ArtifactStagingDirectory)/build' 46 | artifactName: "XPI - Thunderbird WebExtension" 47 | 48 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js text eol=lf 2 | *.jsm text eol=lf 3 | *.mjs text eol=lf 4 | *.html text eol=lf 5 | *.tpl text eol=lf -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | custom: ["https://paypal.me/thsmi"] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Prerequisites 11 | * [ ] Tried the most recent nightly build 12 | * [ ] Checked if your issue is already reported. 13 | * [ ] Answered all the questions in this template (Or provide a working crystal ball). 14 | 15 | ### What happened? 16 | A clear and concise description of what the bug is. 17 | 18 | "X is broken" is not a good bug report. What did you expect to happen? What happened instead? If possible describe the exact steps how to reproduce the issue. 19 | 20 | 1. [First Step] 21 | 2. [Second Step] 22 | 3. [and so on...] 23 | 24 | ### What did you expect to happen? 25 | 26 | #### Logs and Traces 27 | If applicable, include a debug log/trace with your issue. Just go to the extensions settings and enable debugging options in the debug tab. Dumping "byte arrays" is usually not necessary. Keep in mind the line starting with "AUTHENTICATE" contains your password. So scramble this line. 28 | 29 | Detailed instructions how to access traces and enable logging can be found in the wiki: 30 | * https://github.com/thsmi/sieve/wiki/FAQ---Application#app-logging-and-debugging 31 | * https://github.com/thsmi/sieve/wiki/FAQ---WebExtension#logging--debugging 32 | 33 | If applicable and possible, include information and logs from your mail server. 34 | 35 | #### Screenshots 36 | If applicable, add screenshots to help explain your problem. 37 | 38 | ### Which Version 39 | Include information about your system, server and most important if it is about the app or webextension. 40 | 41 | - Standalone app or addon version 42 | - Operating system e.g. Windows, Linux 43 | - Sieve/Mail Server 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Prerequisites 11 | * [ ] Tried the most recent nightly build 12 | * [ ] Checked if your issue is already reported. 13 | 14 | ### Is your feature request related to a problem? 15 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 16 | 17 | ### Describe the solution you'd like 18 | A clear and concise description of what you want to happen. 19 | 20 | ### Describe alternatives you've considered 21 | A clear and concise description of any alternative solutions or features you've considered. 22 | 23 | ### Additional context 24 | Add any other context or screenshots about the feature request here. 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 14 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | 6 | # Issues with these labels will never be considered stale 7 | exemptLabels: 8 | - bug 9 | - enhancement 10 | - dependencies 11 | - wip 12 | 13 | # Label to use when marking an issue as stale 14 | staleLabel: stale 15 | 16 | # Comment to post when marking an issue as stale. Set to `false` to disable 17 | markComment: > 18 | This issue has been automatically marked as stale because it has not had 19 | recent activity. It will be closed if no further activity occurs. Thank you 20 | for your contributions. 21 | 22 | # Comment to post when closing a stale issue. Set to `false` to disable 23 | closeComment: false 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ 3 | __pycache__/ 4 | .venv/ 5 | src/web/config.ini 6 | -------------------------------------------------------------------------------- /.vscode/cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2", 3 | "language": "en", 4 | "words": [ 5 | "addflag", 6 | "addresspart", 7 | "allof", 8 | "anyof", 9 | "authorizable", 10 | "backlisted", 11 | "bodytransform", 12 | "Casemap", 13 | "CHECKSCRIPT", 14 | "codemirror", 15 | "currentdate", 16 | "DELETESCRIPT", 17 | "everytime", 18 | "fileinto", 19 | "GETSCRIPT", 20 | "Giga", 21 | "gulpfile", 22 | "HAVESPACE", 23 | "IMAP", 24 | "Keytar", 25 | "LISTSCRIPTS", 26 | "localpart", 27 | "loggable", 28 | "macos", 29 | "managesieve", 30 | "matchtype", 31 | "multary", 32 | "prefs", 33 | "promisify", 34 | "PUTSCRIPT", 35 | "RENAMESCRIPT", 36 | "Sandboxed", 37 | "sasl", 38 | "Schmid", 39 | "SETACTIVE", 40 | "setflag", 41 | "spamtest", 42 | "spamtestplus", 43 | "STARTTLS", 44 | "stateful", 45 | "subaddress", 46 | "transcoding", 47 | "untrusted", 48 | "upperfirst", 49 | "virustest", 50 | "webextension", 51 | "yazl" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "name": "Python: Debug Sources", 10 | "type": "python", 11 | "request": "launch", 12 | "program": "${workspaceFolder}/src/web/main.py", 13 | "args": ["--config=D:\\projekte\\sieve\\core\\src\\web\\config.ini"], 14 | "console": "integratedTerminal" 15 | }, 16 | { 17 | "name": "Python: Debug Build ", 18 | "type": "python", 19 | "request": "launch", 20 | "program": "${workspaceFolder}/build/web/main.py", 21 | "args": ["--config=D:\\projekte\\sieve\\core\\src\\web\\config.ini"], 22 | "console": "integratedTerminal" 23 | }, 24 | { 25 | "name": "Python: Current File", 26 | "type": "python", 27 | "request": "launch", 28 | "program": "${file}", 29 | "console": "integratedTerminal" 30 | }, 31 | { 32 | "type": "node", 33 | "request": "launch", 34 | "name": "Run Unit Tests", 35 | "program": "${workspaceFolder}/tests/index.js", 36 | "skipFiles": [ 37 | "/**" 38 | ] 39 | }, 40 | { 41 | "type": "node", 42 | "request": "launch", 43 | "name": "Launch Program", 44 | "skipFiles": [ 45 | "/**" 46 | ], 47 | "program": "${workspaceFolder}\\build\\electron\\resources\\" 48 | } 49 | ] 50 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "diffEditor.ignoreTrimWhitespace": true, 3 | "files.trimTrailingWhitespace": true, 4 | "files.exclude": { 5 | "**/.git": true, 6 | "**/node_modules": true, 7 | "build/**": true 8 | }, 9 | "files.eol": "\n", 10 | "editor.tabSize": 2, 11 | "editor.insertSpaces": true, 12 | "editor.useTabStops": false, 13 | "editor.rulers": [ 14 | 80 15 | ], 16 | "[json]": { 17 | "editor.wordWrap": "on" 18 | }, 19 | "python.linting.enabled": true, 20 | "python.linting.pylintEnabled": true, 21 | "python.pythonPath": ".venv\\Scripts\\python.exe" 22 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "Run eslint", 8 | "type": "shell", 9 | "windows": { 10 | "command": ".\\node_modules\\.bin\\eslint" 11 | }, 12 | "linux": { 13 | "command": "./node_modules/.bin/eslint" 14 | }, 15 | "osx": { 16 | "command": "./node_modules/.bin/eslint" 17 | }, 18 | "promptOnClose": false, 19 | "presentation": { 20 | "echo": true, 21 | "reveal": "silent", 22 | "focus": false, 23 | "panel": "shared" 24 | }, 25 | "problemMatcher": "$eslint-stylish" 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /CAPABILITIES.md: -------------------------------------------------------------------------------- 1 | [Moved to the wiki](https://github.com/thsmi/sieve/wiki/Capabilities) -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | [Moved to the wiki](https://github.com/thsmi/sieve/wiki) -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | [Moved to the wiki](https://github.com/thsmi/sieve/wiki/Roadmap) -------------------------------------------------------------------------------- /crowdin.yml: -------------------------------------------------------------------------------- 1 | "commit_message": "[ci skip]" 2 | 3 | files: 4 | - source: /src/common/managesieve.ui/i18n/en-US.json 5 | translation: /src/common/managesieve.ui/i18n/%locale%.json 6 | - source: /src/common/libSieve/i18n/en-US.json 7 | translation: /src/common/libSieve/i18n/%locale%.json 8 | - source: /src/wx/_locales/en_US/messages.json 9 | translation: /src/wx/_locales/%locale_with_underscore%/%original_file_name% 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sieve", 3 | "version": "0.6.1", 4 | "description": "Configures server-side sieve email filters", 5 | "main": "main_esm.js", 6 | "directories": { 7 | "doc": "docs", 8 | "test": "tests" 9 | }, 10 | "devDependencies": { 11 | "electron": "^35.0.1", 12 | "@electron/packager": "^18.3.6", 13 | 14 | "bootstrap": "^5.3.3", 15 | "codemirror": "^5.65.4", 16 | 17 | "@eslint/js": "^9.22.0", 18 | "eslint-plugin-jsdoc": "^50.6.6", 19 | "globals": "^16.0.0", 20 | 21 | "gulp": "^5.0.0", 22 | "yazl": "^3.3.1" 23 | }, 24 | "scripts": { 25 | "start-win32": "gulp \"app:package-win32\" && cd ./build/electron/out/sieve-win32-x64/ && sieve.exe", 26 | "start": "cd node_modules/.bin && electron ./../../build/electron/resources", 27 | "debug": "cd node_modules/.bin && electron ./../../build/electron/resources --debug", 28 | "test": "gulp \"test:package\" && node ./tests/index.js ./build/test/app", 29 | "server": "node ./tools/Server/Server.js", 30 | "gulp": "gulp", 31 | "lint": "eslint" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "git+https://github.com/thsmi/sieve.git" 36 | }, 37 | "author": "Thomas Schmid ", 38 | "license": "AGPL-3.0", 39 | "bugs": { 40 | "url": "https://github.com/thsmi/sieve/issues" 41 | }, 42 | "homepage": "https://github.com/thsmi/sieve#readme" 43 | } 44 | -------------------------------------------------------------------------------- /src/TODO.md: -------------------------------------------------------------------------------- 1 | # TODOs 2 | 3 | ## Capabilities 4 | 5 | We should log and display the SASL capabilities before and after the start tls 6 | Because it is in the meantime common that server do not allow authetnication 7 | unless beeing on a secure channel. 8 | 9 | ## Resolve disconnect race 10 | 11 | A disconnect race is started on referals which makes it randomly fail. 12 | 13 | ## Show error when deleting active script 14 | No error is displayed when deleting active script 15 | 16 | ## Trim host name and port in settings 17 | Trim the input fileds otherwise it is too easy that a space sneaks in 18 | 19 | ## New Script Dialog 20 | Accepts an empty name. The input field need a validator. 21 | 22 | ## Make exception localizable 23 | throw new SieveClientException("No compatible SASL Mechanism (error.sasl)"); 24 | 25 | ## Connection timeouts not working 26 | 27 | ## Add scram unit test for escaped username/authorization 28 | // ;; UTF8-char except NUL, "=", and "," 29 | // "=" is escaped by =2C and "," by =3D 30 | -------------------------------------------------------------------------------- /src/app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Manage Sieve Scripts 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 34 | 35 |
36 | 37 |
38 | 39 |
40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/app/css/navbar-top-fixed.css: -------------------------------------------------------------------------------- 1 | 2 | html, 3 | body { 4 | height: 100%; 5 | overflow: hidden; 6 | } 7 | 8 | #ctx { 9 | display: inline-flex; 10 | height: 100%; 11 | width: 100%; 12 | flex-direction: column; 13 | } 14 | 15 | #tabs-content > * { 16 | height: 100%; 17 | width: 100%; 18 | border: 0; 19 | } 20 | 21 | #tabs-content { 22 | display: inline-flex; 23 | height: 100%; 24 | width: 100%; 25 | } 26 | 27 | #tabs-container { 28 | height: 50px; 29 | padding: 0; 30 | background-color: var(--bs-body-color) !important; 31 | } 32 | 33 | html[data-bs-theme=dark] #tabs-container { 34 | background-color: rgba(var(--bs-body-color-rgb), 0.03) !important; 35 | } 36 | 37 | #tabs-scroll-left { 38 | position: absolute; 39 | bottom: 0; 40 | left: 0; 41 | width: 20px; 42 | padding-top: 0.5rem; 43 | padding-bottom: 0.5rem; 44 | 45 | text-align: center; 46 | border-bottom: var(--bs-border-width) solid var(--bs-border-color-translucent) !important; 47 | 48 | cursor: pointer; 49 | } 50 | 51 | #tabs-scroll-right { 52 | position: absolute; 53 | bottom: 0; 54 | right: 0; 55 | width: 20px; 56 | padding-top: 0.5rem; 57 | padding-bottom: 0.5rem; 58 | 59 | text-align: center; 60 | border-bottom: var(--bs-border-width) solid var(--bs-border-color-translucent) !important; 61 | 62 | cursor: pointer; 63 | } 64 | 65 | #tabs-scroll-box { 66 | position: absolute; 67 | bottom: 0; 68 | left: 20px; 69 | right: 20px; 70 | 71 | overflow: hidden; 72 | white-space: nowrap; 73 | } 74 | 75 | #tabs-items { 76 | position: relative; 77 | border-bottom: none; 78 | display: block; 79 | 80 | border-bottom: var(--bs-border-width) solid var(--bs-border-color-translucent) !important; 81 | } 82 | 83 | #tabs-items > li { 84 | display: inline-block; 85 | } 86 | -------------------------------------------------------------------------------- /src/app/libs/libManageSieve/README.md: -------------------------------------------------------------------------------- 1 | Implements a wrapper for the sieve library with node's network implementation. -------------------------------------------------------------------------------- /src/app/libs/libManageSieve/SieveBase64.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { 13 | SieveAbstractBase64Decoder, 14 | SieveAbstractBase64Encoder 15 | } from "./SieveAbstractBase64.mjs"; 16 | 17 | /** 18 | * 19 | */ 20 | class SieveNodeBase64Encoder extends SieveAbstractBase64Encoder { 21 | 22 | /** 23 | * @inheritdoc 24 | */ 25 | toUtf8() { 26 | return Buffer.from(this.decoded).toString('base64'); 27 | } 28 | 29 | /** 30 | * @inheritdoc 31 | */ 32 | toArray() { 33 | return (new TextEncoder()).encode(this.toUtf8()); 34 | } 35 | } 36 | 37 | /** 38 | * Node implements a native base64 decoder which supports UTF-8 39 | * This simplifies decoding dramatically. 40 | */ 41 | class SieveNodeBase64Decoder extends SieveAbstractBase64Decoder { 42 | 43 | /** 44 | * @inheritdoc 45 | */ 46 | toArray() { 47 | return new Uint8Array(Buffer.from(this.encoded, 'base64')); 48 | } 49 | 50 | } 51 | 52 | export { 53 | SieveNodeBase64Decoder as SieveBase64Decoder, 54 | SieveNodeBase64Encoder as SieveBase64Encoder 55 | }; 56 | -------------------------------------------------------------------------------- /src/app/libs/libManageSieve/SieveSession.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractSession } from "./SieveAbstractSession.mjs"; 13 | import { TLS_SECURITY_EXPLICIT } from "./SieveAbstractClient.mjs"; 14 | 15 | /** 16 | * @inheritdoc 17 | */ 18 | class SieveNodeSession extends SieveAbstractSession { 19 | 20 | /** 21 | * @inheritdoc 22 | */ 23 | async connect(url) { 24 | 25 | const options = { 26 | security : this.getOption("security", TLS_SECURITY_EXPLICIT), 27 | fingerprints : this.getOption("certFingerprints"), 28 | ignoreCertErrors : this.getOption("certIgnoreError") 29 | }; 30 | 31 | await super.connect(url, options); 32 | } 33 | 34 | } 35 | 36 | export { SieveNodeSession as SieveSession }; 37 | -------------------------------------------------------------------------------- /src/app/libs/libManageSieve/SieveTimer.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractTimer } from "./SieveAbstractTimer.mjs"; 13 | 14 | /** 15 | * By default node does not inject a timer into the standard context. 16 | * 17 | * Your need to include it via require. All in all it is almost identical 18 | * with the timer used by a javascript window object. But it lives in a 19 | * different namespace. 20 | */ 21 | class SieveNodeTimer extends SieveAbstractTimer { 22 | 23 | /** 24 | * @inheritdoc 25 | */ 26 | start(callback, ms) { 27 | this.cancel(); 28 | 29 | if (ms === 0) 30 | return; 31 | 32 | this.timer = setTimeout(callback, ms); 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | cancel() { 39 | if (!this.timer) 40 | return; 41 | 42 | clearTimeout(this.timer); 43 | this.timer = null; 44 | } 45 | } 46 | 47 | export { SieveNodeTimer as SieveTimer }; 48 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/accounts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Manage Sieve Scripts 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/accounts/accounts.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 |

7 |

8 | 9 | 10 | 11 |
12 |
13 |
-------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/importer/tests/Thunderbird/empty.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/app/libs/managesieve.ui/importer/tests/Thunderbird/empty.ini -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/importer/tests/Thunderbird/prefs.js: -------------------------------------------------------------------------------- 1 | // Here would be preferences 2 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/importer/tests/Thunderbird/profiles.ini: -------------------------------------------------------------------------------- 1 | [Profile1] 2 | Name=default 3 | IsRelative=1 4 | Path=Profiles/12345 5 | Default=1 6 | 7 | [Profile0] 8 | Name=default-nightly 9 | IsRelative=1 10 | Path=Profiles/7890 11 | 12 | [General] 13 | StartWithLastProfile=1 14 | Version=2 15 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/importer/ui/account.import.html: -------------------------------------------------------------------------------- 1 | 2 | 37 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/importer/ui/account.import.item.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | () 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | 13 |
14 |
15 |
16 | 17 |
18 |
19 |
20 | 21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/settings/logic/SieveAccount.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | 13 | import { SieveAbstractAccount } from "./SieveAbstractAccount.mjs"; 14 | 15 | /** 16 | * Manages the account specific settings 17 | */ 18 | class SieveAccount extends SieveAbstractAccount { 19 | } 20 | 21 | export { SieveAccount }; 22 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/tabs/editor.content.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/tabs/editor.tab.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/updater/SieveUpdaterUI.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveTemplate } from "./../utils/SieveTemplate.mjs"; 13 | import { SieveIpcClient } from "./../utils/SieveIpcClient.mjs"; 14 | 15 | /** 16 | * Checks for new updates and display a new message if a newer version is available 17 | **/ 18 | class SieveUpdaterUI { 19 | 20 | /** 21 | * Checks for new updates and display a new message if a newer version is available 22 | */ 23 | async check() { 24 | const status = await SieveIpcClient.sendMessage("core", "update-check"); 25 | 26 | if (status !== true) 27 | return; 28 | 29 | const template = await (new SieveTemplate()).load("./updater/update.html"); 30 | template.querySelector(".sieve-update-msg").addEventListener("click", () => { 31 | SieveIpcClient.sendMessage("core", "update-goto-url"); 32 | }); 33 | 34 | const parent = document.querySelector("#ctx"); 35 | parent.insertBefore(template, parent.firstChild); 36 | } 37 | } 38 | 39 | export { SieveUpdaterUI }; 40 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/updater/update.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/app/libs/managesieve.ui/utils/SieveIpcClient.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveLogger } from "./SieveLogger.mjs"; 13 | import { SieveAbstractIpcClient } from "./SieveAbstractIpcClient.mjs"; 14 | 15 | /** 16 | * Implements a IPC based on the postMessage interface. 17 | */ 18 | class SieveIpcClient extends SieveAbstractIpcClient { 19 | 20 | /** 21 | * @inheritdoc 22 | */ 23 | static getLogger() { 24 | return SieveLogger.getInstance(); 25 | } 26 | 27 | /** 28 | * @inheritdoc 29 | */ 30 | static parseMessageFromEvent(e) { 31 | return JSON.parse(e.data); 32 | } 33 | 34 | /** 35 | * @inheritdoc 36 | */ 37 | static dispatch(message, target, origin) { 38 | if (origin === undefined) 39 | origin = "*"; 40 | 41 | if (target === undefined) 42 | target = parent; 43 | 44 | if (typeof (message) !== 'string') { 45 | message = JSON.stringify(message); 46 | } 47 | 48 | this.getLogger().logIpcMessage(`Sending message ${message}`); 49 | 50 | target.postMessage(message, origin); 51 | 52 | // In case the target is the current window, we also notify 53 | // all child frames. 54 | if (target !== window) 55 | return; 56 | 57 | for (let idx = 0; idx < frames.length; idx++) 58 | frames[idx].postMessage(message, origin); 59 | } 60 | 61 | } 62 | 63 | window.addEventListener("message", (ev) => { SieveIpcClient.onMessage(ev); }, false); 64 | 65 | export { SieveIpcClient }; 66 | 67 | -------------------------------------------------------------------------------- /src/app/main_esm.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | (async () => { 13 | try { 14 | await (await import('./sieve.mjs')).main(); 15 | } catch (ex) { 16 | // eslint-disable-next-line no-console 17 | console.log(ex); 18 | } 19 | })(); 20 | -------------------------------------------------------------------------------- /src/common/appImage/AppRun: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | SELF=$(readlink -f "$0") 3 | HERE=${SELF%/*} 4 | export PATH="${HERE}:${HERE}/usr/bin/:${HERE}/usr/sbin/:${HERE}/usr/games/:${HERE}/bin/:${HERE}/sbin/${PATH:+:$PATH}" 5 | export LD_LIBRARY_PATH="${HERE}/usr/lib/:${HERE}/usr/lib/i386-linux-gnu/:${HERE}/usr/lib/x86_64-linux-gnu/:${HERE}/usr/lib32/:${HERE}/usr/lib64/:${HERE}/lib/:${HERE}/lib/i386-linux-gnu/:${HERE}/lib/x86_64-linux-gnu/:${HERE}/lib32/:${HERE}/lib64/${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" 6 | EXEC=$(grep -e '^Exec=.*' "${HERE}"/*.desktop | head -n 1 | cut -d "=" -f 2 | cut -d " " -f 1) 7 | exec "${EXEC}" "$@" 8 | -------------------------------------------------------------------------------- /src/common/appImage/sieve.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=sieve 3 | Exec=sieve 4 | Icon=sieve 5 | Type=Application 6 | Categories=Utility; 7 | Terminal=false 8 | Comment=Tool to Manage Sieve Message Filters 9 | -------------------------------------------------------------------------------- /src/common/appImage/sieve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/appImage/sieve.png -------------------------------------------------------------------------------- /src/common/icons/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/icons/linux.png -------------------------------------------------------------------------------- /src/common/icons/mac.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/icons/mac.icns -------------------------------------------------------------------------------- /src/common/icons/win.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/icons/win.ico -------------------------------------------------------------------------------- /src/common/libManageSieve/SieveAbstractTimer.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | /** 13 | * Implements an abstract interface for a simple single shot timer. 14 | */ 15 | class SieveAbstractTimer { 16 | 17 | /** 18 | * Starts the timer. In case the timer is already running it will be restarted 19 | * @abstract 20 | * 21 | * @param {Function} callback 22 | * the callback to be invoked when the timer fires. 23 | * @param {int} ms 24 | * the ms after which the timer should fire 25 | */ 26 | start(callback, ms) { 27 | throw new Error(`Override SieveAbstractTimer::start(${callback},${ms})`); 28 | } 29 | 30 | /** 31 | * Stops the timer. It will fail silently in case the timer is already stopped. 32 | */ 33 | cancel() { 34 | throw new Error(`Override SieveAbstractTimer::cancel()`); 35 | } 36 | } 37 | 38 | export { SieveAbstractTimer }; 39 | -------------------------------------------------------------------------------- /src/common/libManageSieve/tests/SieveCryptoTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | /* eslint-disable no-magic-numbers */ 14 | 15 | /* global net */ 16 | const suite = net.tschmid.yautt.test; 17 | 18 | if (!suite) 19 | throw new Error("Could not initialize test suite"); 20 | 21 | import { SieveCrypto } from "./../SieveCrypto.mjs"; 22 | 23 | const DEFAULT_PASSWORD = new Uint8Array([112, 101, 110, 99, 105, 108]); 24 | const DEFAULT_SALT = new Uint8Array([65, 37, 194, 71, 228, 58, 177, 233, 60, 109, 255, 118]); 25 | 26 | const DEFAULT_SALTED_PASSWORD = [ 27 | 29, 150, 238, 58, 82, 155, 90, 95, 158, 71, 28 | 192, 31, 34, 154, 44, 184, 166, 225, 95, 125]; 29 | 30 | suite.description( 31 | "Testing Cryptographic functions..."); 32 | 33 | suite.add("Crypto SHA1 Hi()", async function () { 34 | 35 | const crypto = new SieveCrypto("SHA-1"); 36 | 37 | const password = DEFAULT_PASSWORD; 38 | const iter = "4096"; 39 | const salt = DEFAULT_SALT; 40 | 41 | 42 | const saltedPassword = await (crypto.Hi(password, salt, iter)); 43 | 44 | suite.assertEquals(20, saltedPassword.length); 45 | 46 | suite.assertEquals(saltedPassword.toString(), DEFAULT_SALTED_PASSWORD.toString()); 47 | }); 48 | 49 | suite.add("Normalize(str)", function () { 50 | }); 51 | -------------------------------------------------------------------------------- /src/common/libSieve/README.md: -------------------------------------------------------------------------------- 1 | # Implements a Drag&Drop UI for the Sieve Language -------------------------------------------------------------------------------- /src/common/libSieve/TODO.md: -------------------------------------------------------------------------------- 1 | # Todo 2 | 3 | - Body - ContentTransfrom :content - type feld fehlt. 4 | 5 | - Collect requiremetns does not work properly 6 | 7 | - imap flags -> varlist ignores requires 8 | - has flags needs to implement support for dependent elements 9 | 10 | variable's defered elements should be added via extend... 11 | 12 | 13 | - Create A Sieve DropdownGroupWidget 14 | 15 | - Convert date selector to real dropdown 16 | 17 | - globals beschreibung fehlt 18 | 19 | dependen (varlist) in imapflags needs to be implemented 20 | 21 | - Fixme spamtestplus shoudl be used when :precent is specified otherwise spamtest should be used. 22 | 23 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/logic/SieveActions.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | SieveGrammar.addAction({ 16 | node: "action/discard", 17 | type: "action", 18 | token: "discard" 19 | }); 20 | 21 | SieveGrammar.addAction({ 22 | node: "action/stop", 23 | type: "action", 24 | token: "stop" 25 | }); 26 | 27 | SieveGrammar.addAction({ 28 | node: "action/keep", 29 | type: "action", 30 | token: "keep" 31 | }); 32 | 33 | SieveGrammar.addAction({ 34 | node: "action/redirect", 35 | type: "action", 36 | token: "redirect", 37 | 38 | properties: [{ 39 | id: "parameters", 40 | 41 | elements: [{ 42 | id: "address", 43 | 44 | type: "string", 45 | value: "\"username@example.com\"" 46 | }] 47 | }] 48 | }); 49 | 50 | // <"fileinto"> <";"> 51 | SieveGrammar.addAction({ 52 | node: "action/fileinto", 53 | type: "action", 54 | token: "fileinto", 55 | 56 | requires: "fileinto", 57 | 58 | properties: [{ 59 | id: "parameters", 60 | 61 | elements: [{ 62 | id: "path", 63 | 64 | type: "string", 65 | value: "\"INBOX\"" 66 | }] 67 | }] 68 | }); 69 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/logic/SieveAddressParts.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | SieveGrammar.addTag({ 16 | node: "address-part/domain", 17 | type: "address-part/", 18 | 19 | token: ":domain" 20 | }); 21 | 22 | 23 | SieveGrammar.addTag({ 24 | node: "address-part/local", 25 | type: "address-part/", 26 | 27 | token: ":localpart" 28 | }); 29 | 30 | SieveGrammar.addTag({ 31 | node: "address-part/all", 32 | type: "address-part/", 33 | 34 | token: ":all" 35 | }); 36 | 37 | 38 | SieveGrammar.addGroup({ 39 | node: "address-part", 40 | type: "address-part", 41 | 42 | value: ":all", 43 | 44 | items: ["address-part/"] 45 | }); 46 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/logic/SieveMatchTypes.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | // TODO match-type items (matchtype/) should not eat trailing whitespaces... 16 | // they this should be done my the match-type group 17 | 18 | SieveGrammar.addTag({ 19 | node: "match-type/is", 20 | type: "match-type/", 21 | 22 | token: ":is" 23 | }); 24 | 25 | SieveGrammar.addTag({ 26 | node: "match-type/matches", 27 | type: "match-type/", 28 | 29 | token: ":matches" 30 | }); 31 | 32 | SieveGrammar.addTag({ 33 | node: "match-type/contains", 34 | type: "match-type/", 35 | 36 | token: ":contains" 37 | }); 38 | 39 | SieveGrammar.addGroup({ 40 | node: "match-type", 41 | type: "match-type", 42 | 43 | value: ":is", 44 | 45 | items: ["match-type/"] 46 | }); 47 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveAddressPartAll.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveAddressPartDomain.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveAddressPartLocal.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveAllOfAnyOfOperator.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveBooleanTest.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 10 |
11 | 12 |
13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 | 22 | 23 |
24 |
25 | 27 | 28 |
29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveComparatorAsciiCasemap.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |
7 | 8 |
9 |
10 | 11 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveComparatorAsciiNumeric.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 6 | 8 |
9 | 10 |
11 |
12 | 13 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveComparatorOctet.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 | 7 |
8 |
9 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveDiscardActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 |
7 | 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveExistsTestUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 10 |
11 | 12 |
13 |
14 |
15 |

16 |
17 |
18 |
19 | 20 |
21 | 28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveFileIntoActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 |
15 | 16 |
17 | 18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveKeepActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 |
7 | 8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveMatchTypeContainsUI.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveMatchTypeIsUI.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveMatchTypeMatchesUI.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveRedirectActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 |
15 |
16 | 17 | 21 |
22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveSizeTestUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 | 20 | 21 |
22 |
23 | 24 | 25 |
26 |
27 | 28 |
29 | 30 |
31 | 32 |
33 |
34 | 35 | 36 |
37 |
38 |
39 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/templates/SieveStopActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 |
7 | 8 |
9 |
10 |
12 |
13 |
14 |
15 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/tests/SieveMatchTypeTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | /* global net */ 14 | 15 | const suite = net.tschmid.yautt.test; 16 | 17 | if (!suite) 18 | throw new Error("Could not initialize test suite"); 19 | 20 | suite.description("Match-type unit tests..."); 21 | 22 | suite.add("Parse :is match-type", () => { 23 | 24 | const script = 25 | 'if header :is "Sender" "owner-ietf-mta-filters@imc.org" \r\n' 26 | + '{\r\n' 27 | + ' keep;\r\n' 28 | + '}\r\n'; 29 | 30 | suite.expectValidScript(script); 31 | }); 32 | 33 | 34 | suite.add("Parse :matches match-type", () => { 35 | 36 | const script = 37 | 'if header :matches "Sender" "owner-ietf-mta-filters@imc.org" \r\n' 38 | + '{\r\n' 39 | + ' keep; \r\n' 40 | + '}\r\n'; 41 | 42 | suite.expectValidScript(script); 43 | }); 44 | 45 | 46 | suite.add("Parse :contains match-type", () => { 47 | 48 | const script = 49 | 'if header :contains "Sender" "owner-ietf-mta-filters@imc.org" \r\n' 50 | + '{\r\n' 51 | + ' keep; \r\n' 52 | + '}\r\n'; 53 | 54 | suite.expectValidScript(script); 55 | }); 56 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/RFC5228/tests/SieveRFC5228SnippetTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | 14 | /* global net */ 15 | 16 | const suite = net.tschmid.yautt.test; 17 | 18 | if (!suite) 19 | throw new Error("Could not initialize test suite"); 20 | 21 | suite.description("RFC5228 unit tests..."); 22 | 23 | suite.add("Test header constructors", () => { 24 | 25 | const snippet = 'header "Subject" "Example"'; 26 | suite.expectValidSnippet("test/header", snippet); 27 | }); 28 | 29 | // :comparator "i;ascii-casemap" 30 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/body/templates/SieveBodyTestUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 10 | 13 | 16 |
17 | 18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 | 26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 |
41 |
42 |
43 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/body/templates/SieveBodyTransformContent.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 6 | 7 |
8 | 9 |
10 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/body/templates/SieveBodyTransformRaw.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/body/templates/SieveBodyTransformText.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 6 |
7 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/convert/logic/SieveConvert.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | // Usage: convert 16 | // 17 | // 18 | // 19 | // can be either a test or an action... 20 | 21 | const properties = [{ 22 | id: "parameters", 23 | 24 | elements: [{ 25 | id: "from", 26 | type: "string", 27 | value: '"image/tiff"' 28 | }, { 29 | id: "to", 30 | type: "string", 31 | value: '"image/jpeg"' 32 | }, { 33 | id: "transcoding", 34 | type: "stringlist", 35 | value: '["pix-x=320","pix-y=240"]' 36 | }] 37 | }]; 38 | 39 | SieveGrammar.addTest({ 40 | node: "test/convert", 41 | type: "test", 42 | 43 | requires: "convert", 44 | 45 | token: "convert", 46 | 47 | properties: properties 48 | }); 49 | 50 | SieveGrammar.addAction({ 51 | node: "action/convert", 52 | type: "action", 53 | 54 | requires: "convert", 55 | 56 | token: "convert", 57 | 58 | properties: properties 59 | }); 60 | 61 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/copy/logic/SieveCopy.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | // "fileinto" [":copy"] 16 | const fileintocopy = { 17 | node: "action/fileinto/copy", 18 | type: "action/fileinto/", 19 | 20 | requires: "copy", 21 | 22 | token: ":copy" 23 | }; 24 | 25 | SieveGrammar.addTag(fileintocopy); 26 | 27 | const fileinto = { 28 | extends: "action/fileinto", 29 | 30 | properties: [{ 31 | id: "tags", 32 | optional: true, 33 | 34 | elements: [{ 35 | id: "copy", 36 | type: "action/fileinto/copy", 37 | requires: "copy" 38 | }] 39 | }] 40 | }; 41 | 42 | SieveGrammar.extendAction(fileinto); 43 | 44 | // "redirect" [":copy"] 45 | const redirectcopy = { 46 | node: "action/redirect/copy", 47 | type: "action/redirect/", 48 | 49 | requires: "copy", 50 | 51 | token: ":copy" 52 | }; 53 | 54 | SieveGrammar.addTag(redirectcopy); 55 | 56 | const redirect = { 57 | extends: "action/redirect", 58 | 59 | properties: [{ 60 | id: "tags", 61 | optional: true, 62 | 63 | elements: [{ 64 | id: "copy", 65 | type: "action/redirect/copy", 66 | requires: "copy" 67 | }] 68 | }] 69 | }; 70 | 71 | SieveGrammar.extendAction(redirect); 72 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/copy/templates/SieveCopyTag.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 9 |
10 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/copy/tests/SieveCopyTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | 14 | /* global net */ 15 | 16 | const suite = net.tschmid.yautt.test; 17 | 18 | if (!suite) 19 | throw new Error("Could not initialize test suite"); 20 | 21 | suite.description("Copy Unit Tests..."); 22 | 23 | suite.add("RFC 3894 - Example I", () => { 24 | 25 | const script = "" 26 | + 'require ["copy", "fileinto"];\r\n' 27 | + 'fileinto :copy "incoming";\r\n'; 28 | 29 | suite.expectValidScript(script, ["copy", "fileinto"]); 30 | }); 31 | 32 | suite.add("RFC 3894 - Example Ia", () => { 33 | 34 | const script = "" 35 | + 'require ["fileinto"];\r\n' 36 | + 'fileinto :copy "incoming";\r\n'; 37 | 38 | suite.expectInvalidScript(script, 'Error: Unknown or incompatible type >>string/<< at >>:copy "inc', ["fileinto"]); 39 | }); 40 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/date/templates/SieveZoneCustom.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

6 |

7 |
8 |
9 | 11 |
12 |
13 |
14 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/date/templates/SieveZoneOriginal.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

6 |
7 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/duplicate/templates/SieveUniqueDefault.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

6 |
7 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/duplicate/templates/SieveUniqueHeader.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

6 | 7 | 8 |
9 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/duplicate/templates/SieveUniqueId.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |

6 | 7 | 8 | 9 |
10 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/environment/logic/SieveEnvironment.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | // Usage: environment [COMPARATOR] [MATCH-TYPE] 16 | 17 | const _environment = { 18 | node: "test/environment", 19 | type: "test", 20 | 21 | requires: "environment", 22 | 23 | token: "environment", 24 | 25 | properties: [{ 26 | id: "tags", 27 | optional: true, 28 | 29 | elements: [{ 30 | id: "match-type", 31 | type: "match-type" 32 | }, { 33 | id: "comparator", 34 | type: "comparator" 35 | 36 | }] 37 | }, { 38 | id: "parameters", 39 | elements: [{ 40 | id: "name", 41 | type: "string", 42 | value: '"domain"' 43 | }, { 44 | id: "keys", 45 | type: "stringlist", 46 | value: '"imap.example.com"' 47 | }] 48 | }] 49 | }; 50 | 51 | SieveGrammar.addTest(_environment); 52 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/environment/tests/SieveEnvironmentTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | /* global net */ 14 | 15 | const suite = net.tschmid.yautt.test; 16 | 17 | if (!suite) 18 | throw new Error("Could not initialize test suite"); 19 | 20 | suite.description("Environment Tests..."); 21 | 22 | suite.add("Example 1", () => { 23 | 24 | const script = '' 25 | + 'require "environment";\r\n' 26 | + 'if environment :contains "item" "" { keep; }'; 27 | 28 | suite.expectValidScript(script, ["environment"]); 29 | }); 30 | 31 | suite.add("Example 2", () => { 32 | 33 | const script = '' 34 | + 'require "environment";\r\n' 35 | + 'if environment :matches "remote-host" "*.example.com" { keep; }'; 36 | 37 | suite.expectValidScript(script, ["environment"]); 38 | }); 39 | 40 | suite.add("Validate environment test constructor", () => { 41 | 42 | const snippet = 'environment "domain" "imap.example.com"'; 43 | suite.expectValidSnippet("test/environment", snippet, ["environment"]); 44 | }); 45 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/extensions.mjs: -------------------------------------------------------------------------------- 1 | // RFC 5232 - ImapFlags 2 | import "./imapflags/widgets/SieveImapFlagsUI.mjs"; 3 | 4 | // RFC 5429 - Reject 5 | import "./reject/widgets/SieveRejectUI.mjs"; 6 | 7 | // RFC Draft for RegEx 8 | import "./regex/widgets/SieveRegularExpressionUI.mjs"; 9 | 10 | // RFC5173 - Body 11 | import "./body/widgets/SieveBodyUI.mjs"; 12 | 13 | // RFC5230 - Vacation 14 | import "./vacation/widgets/SieveVacationUI.mjs"; 15 | 16 | // RFC5229 - Variables 17 | import "./variables/widgets/SieveVariablesUI.mjs"; 18 | 19 | // RFC6609 - Include 20 | import "./include/widget/SieveIncludeUI.mjs"; 21 | 22 | // RFC5233 - Subaddress 23 | import "./subaddress/widgets/SieveSubaddressUI.mjs"; 24 | 25 | // RFC5490 - Mailbox 26 | import "./mailbox/widgets/SieveMailboxUI.mjs"; 27 | 28 | // RFC55293 - Editheader 29 | import "./editheader/widgets/SieveEditheaderUI.mjs"; 30 | 31 | // RFC3894 - Copy 32 | import "./copy/widgets/SieveCopyUI.mjs"; 33 | 34 | // RFC5231 - Relational 35 | import "./relational/widgets/SieveRelationalUI.mjs"; 36 | 37 | import "./date/widgets/SieveDateUI.mjs"; 38 | 39 | // RCF5435 - Duplicate 40 | import "./duplicate/widgets/SieveDuplicateUI.mjs"; 41 | 42 | // RCF5235 - Spamtest 43 | import "./spamtest/widgets/SieveSpamtestUI.mjs"; 44 | 45 | // RCF5183 - Environment 46 | import "./environment/widgets/SieveEnvironmentUI.mjs"; 47 | 48 | // RCF6131 - Vacation Seconds 49 | import "./vacation-seconds/widgets/SieveVacationSecondsUI.mjs"; 50 | 51 | // RFC6558 - Convert 52 | import "./convert/widgets/SieveConvertUI.mjs"; 53 | 54 | // RFC5435 - Notify 55 | import "./notify/widgets/SieveNotifyUI.mjs"; 56 | 57 | // vnd.dovecot.pipe - pipe 58 | import "./pipe/widgets/SievePipeUI.mjs"; 59 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/imapflags/templates/SieveFlagsTag.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 |
7 | 8 | 9 | 10 |

11 | 12 |
13 |
14 | 15 |
16 | 29 |
30 |
31 |
32 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/include/template/SieveGlobalActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 |
11 |
12 |
13 |
14 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/include/template/SieveReturnActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/mailbox/templates/SieveCreateTag.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 |
7 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/mailbox/templates/SieveMailboxExistsTest.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/mailbox/templates/SieveMetaDataExistsTest.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 | 19 | 20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/mailbox/templates/SieveMetaDataTest.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 11 | 14 |
15 | 16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 | 24 |
25 | 26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 |
40 |
41 |
42 |
43 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/mailbox/templates/SieveServerMetaDataExistsTest.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 |
22 |
23 |
24 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/mailbox/templates/SieveServerMetaDataTest.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 | 12 |
13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 | 21 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/notify/templates/SieveEncodeUrlUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 9 |
10 |
11 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/notify/templates/SieveValidNotifyMethodTestUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 |
10 | 11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/pipe/templates/SieveFilterUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 10 |
11 | 12 |
13 |
14 |
15 |
16 | 17 |
18 | 20 |
21 |
22 | 23 |
24 | 25 |
26 | 27 | 28 | 29 |

30 | 31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/regex/logic/SieveRegularExpression.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | SieveGrammar.addTag({ 16 | node: "match-type/regex", 17 | type: "match-type/", 18 | 19 | requires: "regex", 20 | 21 | token: ":regex" 22 | }); 23 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/regex/templates/SieveMatchTypeRegExUI.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/regex/tests/SieveRegExTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | /* global net */ 14 | 15 | const suite = net.tschmid.yautt.test; 16 | 17 | if (!suite) 18 | throw new Error("Could not initialize test suite"); 19 | 20 | suite.description("Reg Ex unit tests..."); 21 | 22 | suite.add("Parse :regex match-type with single import", () => { 23 | 24 | const script = 25 | 'require "regex";\r\n' 26 | + 'if header :regex "Sender" "owner-ietf-mta-filters@imc.org" \r\n' 27 | + '{\r\n' 28 | + ' keep; \r\n' 29 | + '}\r\n'; 30 | 31 | suite.expectValidScript(script, ["regex"]); 32 | }); 33 | 34 | suite.add("Parse :regex match-type with multiple import", () => { 35 | 36 | const script = 37 | 'require ["regex", "fileinto"];\r\n' 38 | + 'if address :comparator "i;ascii-casemap" :regex ["to", "cc"] "j(i|la).*@mydomain.com"\r\n' 39 | + '{\r\n' 40 | + ' fileinto "INBOX";\r\n' 41 | + ' stop;\r\n' 42 | + '}\r\n'; 43 | 44 | suite.expectValidScript(script, ["regex", "fileinto"]); 45 | }); 46 | 47 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/regex/widgets/SieveRegularExpressionUI.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import "./../logic/SieveRegularExpression.mjs"; 14 | 15 | import { SieveDesigner } from "./../../../toolkit/SieveDesigner.mjs"; 16 | import { SieveAbstractMatchTypeUI } from "./../../../extensions/RFC5228/widgets/SieveMatchTypesUI.mjs"; 17 | 18 | /** 19 | * Provides an UI for the RegEx match type. 20 | */ 21 | class SieveRegExMatchUI extends SieveAbstractMatchTypeUI { 22 | 23 | /** 24 | * @inheritdoc 25 | */ 26 | static nodeName() { 27 | return "match-type/regex"; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | */ 33 | static isCapable(capabilities) { 34 | return capabilities.hasCapability("regex"); 35 | } 36 | 37 | /** 38 | * @inheritdoc 39 | */ 40 | getTemplate() { 41 | return "./extensions/regex/templates/SieveMatchTypeRegExUI.html"; 42 | } 43 | } 44 | 45 | SieveDesigner.register2(SieveRegExMatchUI); 46 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/reject/logic/SieveReject.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | const reject = { 16 | node: "action/reject", 17 | type: "action", 18 | token: "reject", 19 | 20 | requires: "reject", 21 | 22 | properties: [{ 23 | id: "parameters", 24 | 25 | elements: [{ 26 | id: "reason", 27 | type: "string", 28 | value: "text:\r\n.\r\n" 29 | }] 30 | }] 31 | }; 32 | 33 | SieveGrammar.addAction(reject); 34 | 35 | 36 | const ereject = { 37 | node: "action/ereject", 38 | type: "action", 39 | token: "ereject", 40 | 41 | requires: "ereject", 42 | 43 | properties: [{ 44 | id: "parameters", 45 | 46 | elements: [{ 47 | id: "reason", 48 | type: "string", 49 | value: "text:\r\n.\r\n" 50 | }] 51 | }] 52 | }; 53 | 54 | SieveGrammar.addAction(ereject); 55 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/reject/templates/SieveExtendedRejectActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 10 |
11 | 12 |
13 |
14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 |
23 |
24 |
25 |
26 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/reject/templates/SieveRejectActionUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 10 |
11 | 12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 | 20 | 21 |
22 | 23 |
24 |
26 |
27 |
28 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/reject/tests/SieveRejectTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | /* global net */ 14 | 15 | const suite = net.tschmid.yautt.test; 16 | 17 | if (!suite) 18 | throw new Error("Could not initialize test suite"); 19 | 20 | suite.description("Sieve Reject (RFC5429) unit tests..."); 21 | 22 | suite.add("Example 1", () => { 23 | 24 | const script = 25 | 'require ["ereject"];\r\n' 26 | + '\r\n' 27 | + 'if address "from" "someone@example.com" {\r\n' 28 | + ' ereject "I no longer accept mail from this address";\r\n' 29 | + '}\r\n'; 30 | 31 | suite.expectValidScript(script, ["ereject"]); 32 | }); 33 | 34 | suite.add("Example 2", () => { 35 | 36 | const script = 37 | 'require ["reject"];\r\n' 38 | + '\r\n' 39 | + 'if size :over 100K {\r\n' 40 | + ' reject text:\r\n' 41 | + 'Your message is too big. If you want to send me a big attachment,\r\n' 42 | + 'put it on a public web site and send me a URL.\r\n' 43 | + '.\r\n' 44 | + ';\r\n' 45 | + '}\r\n'; 46 | 47 | 48 | suite.expectValidScript(script, ["reject"]); 49 | }); 50 | 51 | 52 | suite.add("Example 3", () => { 53 | 54 | const script = 55 | 'require ["reject"];\r\n' 56 | + '\r\n' 57 | + 'if header :contains "from" "coyote@desert.example.org" {\r\n' 58 | + ' reject text:\r\n' 59 | + 'I am not taking mail from you, and I don\'t\r\n' 60 | + 'want your birdseed, either!\r\n' 61 | + '.\r\n' 62 | + ';\r\n' 63 | + '}\r\n'; 64 | 65 | 66 | suite.expectValidScript(script, ["reject"]); 67 | }); 68 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/relational/templates/SieveMatchTypeCountUI.html: -------------------------------------------------------------------------------- 1 |
2 | 20 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/relational/templates/SieveMatchTypeValueUI.html: -------------------------------------------------------------------------------- 1 |
2 | 20 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/spamtest/templates/SieveSpamtestUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 6 | 9 | 12 |
13 | 14 |
15 |
16 |
17 | 18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 | 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/spamtest/templates/SieveSpamtestValue.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 | 26 |
27 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/subaddress/logic/SieveSubaddress.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | // :user "+" :detail "@" :domain 16 | // \----:local-part----/ 17 | 18 | const userpart = { 19 | node: "address-part/user", 20 | type: "address-part/", 21 | 22 | requires: "subaddress", 23 | 24 | token: ":user" 25 | }; 26 | 27 | SieveGrammar.addTag(userpart); 28 | 29 | 30 | const detailpart = { 31 | node: "address-part/detail", 32 | type: "address-part/", 33 | 34 | requires: "subaddress", 35 | 36 | token: ":detail" 37 | }; 38 | 39 | SieveGrammar.addTag(detailpart); 40 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/subaddress/templates/SieveAddressPartDetail.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/subaddress/templates/SieveAddressPartUser.html: -------------------------------------------------------------------------------- 1 |
2 | 6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/subaddress/tests/SieveSubaddressTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | 14 | /* global net */ 15 | 16 | const suite = net.tschmid.yautt.test; 17 | 18 | if (!suite) 19 | throw new Error("Could not initialize test suite"); 20 | 21 | suite.description("Subaddress Unit Tests..."); 22 | 23 | suite.add("Parse Subaddress Example 1", () => { 24 | 25 | const script = '' 26 | + 'require ["envelope", "subaddress", "fileinto"];\r\n' 27 | + '\r\n' 28 | + '\r\n' 29 | + '# In this example the same user account receives mail for both\r\n' 30 | + '# "ken@example.com" and "postmaster@example.com"\r\n' 31 | + '\r\n' 32 | + '# File all messages to postmaster into a single mailbox,\r\n' 33 | + '# ignoring the :detail part.\r\n' 34 | + 'if envelope :user "to" "postmaster" {\r\n' 35 | + ' fileinto "inbox.postmaster";\r\n' 36 | + ' stop;\r\n' 37 | + '}\r\n' 38 | + '\r\n' 39 | + '# File mailing list messages (subscribed as "ken+mta-filters").\r\n' 40 | + 'if envelope :detail "to" "mta-filters" {\r\n' 41 | + ' fileinto "inbox.ietf-mta-filters";\r\n' 42 | + '}\r\n' 43 | + '\r\n' 44 | + '# Redirect all mail sent to "ken+foo".\r\n' 45 | + 'if envelope :detail "to" "foo" {\r\n' 46 | + ' redirect "ken@example.net";\r\n' 47 | + '}\r\n'; 48 | 49 | suite.expectValidScript(script, ["subaddress", "envelope", "fileinto"]); 50 | }); 51 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/vacation-seconds/logic/SieveVacationSeconds.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | import { SieveGrammar } from "./../../../toolkit/logic/GenericElements.mjs"; 14 | 15 | const vacationSeconds = { 16 | extends: "action/vacation", 17 | requires: { any: ["vacation-seconds", "vacation"] } 18 | }; 19 | 20 | SieveGrammar.extendAction(vacationSeconds); 21 | 22 | SieveGrammar.addTag({ 23 | node: "action/vacation/interval/seconds", 24 | type: "action/vacation/interval/", 25 | 26 | token: ":seconds", 27 | 28 | requires: "vacation-seconds", 29 | 30 | properties: [{ 31 | id: "parameters", 32 | 33 | elements: [{ 34 | id: "seconds", 35 | type: "number", 36 | value: '1800' 37 | }] 38 | }] 39 | }); 40 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/vacation-seconds/template/SieveVacationIntervalSecondsUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 10 |
11 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/vacation-seconds/tests/SieveVacationSecondsTest.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file are licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | * 11 | */ 12 | 13 | /* global net */ 14 | 15 | const suite = net.tschmid.yautt.test; 16 | 17 | if (!suite) 18 | throw new Error("Could not initialize test suite"); 19 | 20 | 21 | suite.description("Vacation Seconds Unit Tests..."); 22 | 23 | suite.add("Parse Vacation Seconds Example 1", () => { 24 | 25 | const script = '' 26 | + 'require ["vacation-seconds"];\r\n' 27 | + 'vacation :addresses ["tjs@example.edu", "ts4z@landru.example.edu"]\r\n' 28 | + ' :seconds 1800\r\n' 29 | + ' "I am in a meeting, and do not have access to email.";\r\n'; 30 | 31 | suite.expectValidScript(script, ["vacation-seconds"]); 32 | }); 33 | 34 | suite.add("Parse Vacation Seconds Example 2", () => { 35 | 36 | const script = '' 37 | + 'require ["vacation-seconds"];\r\n' 38 | + '\r\n' 39 | + 'vacation :handle "auto-resp" :seconds 0\r\n' 40 | + ' "Your request has been received. A service\r\n' 41 | + ' representative will contact you as soon as\r\n' 42 | + ' possible, usually within one business day.";\r\n'; 43 | 44 | suite.expectValidScript(script, ["vacation-seconds"]); 45 | }); 46 | -------------------------------------------------------------------------------- /src/common/libSieve/extensions/vacation/template/SieveVacationIntervalDaysUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 9 |
10 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/vacation/template/SieveVacationIntervalDefaultUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 |
6 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/variables/templates/SieveCaseFirstUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | 10 | 11 |
12 |
13 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 |
23 | 24 |
25 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/variables/templates/SieveCaseUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | 6 | 10 | 11 |
12 |
13 | 15 | 16 |
17 |
18 | 19 | 20 |
21 |
22 |
23 | 24 |
25 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/variables/templates/SieveLengthUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 9 |
10 |
11 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/variables/templates/SieveQuotewildcardUI.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 6 | 10 |
11 |
12 |
-------------------------------------------------------------------------------- /src/common/libSieve/extensions/variables/templates/SieveStringTestUI.html: -------------------------------------------------------------------------------- 1 |
2 |
    3 | 7 | 11 | 14 |
15 | 16 |
17 |
18 |
19 | 20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
37 |
38 |
39 |
40 |
-------------------------------------------------------------------------------- /src/common/libSieve/toolkit/gramar.txt: -------------------------------------------------------------------------------- 1 | Sieve Gramar: 2 | 3 | Separators : Whitespace, Brackets, Comma and Semicolon. 4 | 5 | Tags are Optional, and have no fixed order 6 | Parameters are non optional an have a fixed order 7 | 8 | First tags then parameters 9 | 10 | 11 | Parameters: 12 | 13 | "token" 14 | 15 | Tags 16 | "" 17 | 18 | Testlists: 19 | "("+WS?+element+WS?+","+WS?+element+WS?+"," ... ")" 20 | 21 | Action 22 | token + WS + tags + WS + parameters + WS";" 23 | 24 | Test 25 | token + tags parameters 26 | 27 | Operators: 28 | "not" + WS + test 29 | anyof +WS + testlist 30 | 31 | Conditional 32 | 33 | "if ("+test | operator+")" Block 34 | "elsif ("+test | operator+")" Block 35 | "else" Block 36 | 37 | Block 38 | "{"+Block2+"}" 39 | 40 | Block2 41 | (WS | Action | Conditional) -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/style/hline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/libSieve/toolkit/style/hline.png -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/style/layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | 5 | #content { 6 | padding: 0 10px; 7 | margin-left: 180px; 8 | } 9 | 10 | #toolbar { 11 | position: fixed; 12 | width: 170px; 13 | overflow-x: hidden; 14 | } 15 | 16 | #toolbar .SivElement { 17 | width: 140px; 18 | } 19 | 20 | #sivTrash .sivTrashBin { 21 | height: 80px; 22 | min-width: 80px; 23 | background-color: transparent; 24 | background-image: url('trash.png'); 25 | background-repeat: no-repeat; 26 | background-position: center center; 27 | } 28 | 29 | #sivTrash .sivTrashBin[data-sieve-dragging] { 30 | background-image: url('trash-full.png'); 31 | } 32 | -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/style/trash-full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/libSieve/toolkit/style/trash-full.png -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/style/trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/libSieve/toolkit/style/trash.png -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/style/vline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/libSieve/toolkit/style/vline.png -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/style/vline2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/common/libSieve/toolkit/style/vline2.png -------------------------------------------------------------------------------- /src/common/libSieve/toolkit/templates/SieveDropDownWidget.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 | 9 | 11 |
12 |
-------------------------------------------------------------------------------- /src/common/libSieve/toolkit/templates/SieveNumericWidget.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 5 | 7 | 22 |
23 |
-------------------------------------------------------------------------------- /src/common/libSieve/toolkit/templates/SieveStringListWidget.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 8 | 11 |
12 | 13 |
14 | 15 |
16 | 17 |
-------------------------------------------------------------------------------- /src/common/libSieve/toolkit/templates/SieveStringWidget.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 8 |
9 |
-------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/SieveAbstractAccounts.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAccountUI } from "./SieveAccountUI.mjs"; 13 | import { SieveIpcClient } from "./../utils/SieveIpcClient.mjs"; 14 | import { SieveLogger } from "./../utils/SieveLogger.mjs"; 15 | 16 | /** 17 | * A UI renderer for a list of sieve accounts 18 | **/ 19 | class SieveAbstractAccounts { 20 | 21 | /** 22 | * Gets an instance to the logger. 23 | * 24 | * @returns {SieveLogger} 25 | * an reference to the logger instance. 26 | **/ 27 | getLogger() { 28 | return SieveLogger.getInstance(); 29 | } 30 | 31 | /** 32 | * Renders the UI for this component. 33 | * 34 | * @param {string} [account] 35 | * the optional account id which should be rendered. If omitted all 36 | * account will be updated. 37 | */ 38 | async render(account) { 39 | 40 | if ((typeof(account) !== "undefined") && (account !== null)) { 41 | this.getLogger().logWidget(` + Rendering Accounts ${account}`); 42 | await ((new SieveAccountUI(this, account)).render()); 43 | return; 44 | } 45 | 46 | this.getLogger().logWidget("Rendering Accounts..."); 47 | 48 | const items = document.querySelector(".siv-accounts-items"); 49 | while (items.firstChild) 50 | items.firstChild.remove(); 51 | 52 | const accounts = await SieveIpcClient.sendMessage("core", "accounts-list"); 53 | 54 | for (const item of accounts) { 55 | await this.render(item); 56 | } 57 | } 58 | } 59 | 60 | export { SieveAbstractAccounts }; 61 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/SieveScriptUI.html: -------------------------------------------------------------------------------- 1 |
  • 2 |
    3 | 4 | 5 |
    6 |
    7 | 8 | 9 | 10 | 11 | 12 |
    13 |
  • -------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/account.capabilities.html: -------------------------------------------------------------------------------- 1 | 37 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/account.connecting.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |

    4 |
    5 |
    6 |
    7 |
    8 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/account.disconnected.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |

    4 |

    5 | 7 |
    8 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/account.disconnecting.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |

    4 |
    5 |
    6 |
    7 |
    8 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/accounts/account.empty.html: -------------------------------------------------------------------------------- 1 |
    2 |

    3 |

    4 | 6 |
    -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.account.authorization.html: -------------------------------------------------------------------------------- 1 | 2 | 30 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.account.cert.html: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.account.delete.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.error.html: -------------------------------------------------------------------------------- 1 | 19 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.script.busy.html: -------------------------------------------------------------------------------- 1 | 2 | 23 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.script.create.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.script.delete.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.script.rename.html: -------------------------------------------------------------------------------- 1 | 2 | 19 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/dialogs/dialog.script.save.html: -------------------------------------------------------------------------------- 1 | 2 | 24 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/editor/editor.error.save.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/editor/editor.settings.defaults.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |

    5 |
    6 | 7 | 8 |
    9 |
    -------------------------------------------------------------------------------- /src/common/managesieve.ui/editor/graphical/SieveGraphicalEditor.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractEditorUI } from "./../SieveAbstractEditor.mjs"; 13 | 14 | // FIXME should use an IPC instead of talking directly to the iframe... 15 | 16 | /** 17 | * 18 | */ 19 | class SieveGraphicalEditorUI extends SieveAbstractEditorUI { 20 | 21 | /** 22 | * Creates a new graphical editor UI. 23 | * 24 | * @param {SieveEditorController} controller 25 | * The controller which is assigned to this editor. 26 | */ 27 | constructor(controller) { 28 | super(controller); 29 | this.id = "sieve-widget-editor"; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | */ 35 | async render() { 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | async setScript(script) { 42 | 43 | const capabilities = await this.getController().getCapabilities(); 44 | // set script content... 45 | document.querySelector(`#${this.id}`) 46 | .contentWindow 47 | .setSieveScript(script, JSON.stringify(capabilities.extensions)); 48 | } 49 | 50 | /** 51 | * @inheritdoc 52 | */ 53 | getScript() { 54 | return document.querySelector(`#${this.id}`) 55 | .contentWindow 56 | .getSieveScript(); 57 | } 58 | } 59 | 60 | export { SieveGraphicalEditorUI }; 61 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/editor/text/editor.plaintext.html: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    -------------------------------------------------------------------------------- /src/common/managesieve.ui/editor/text/editor.settings.syntax.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |

    5 | 6 |

    7 | 8 |
    9 | 10 | 11 |
    12 |
    -------------------------------------------------------------------------------- /src/common/managesieve.ui/settings/logic/SieveAbstractAuthentication.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | /** 13 | * An base class common for all authentication mechanisms 14 | **/ 15 | class SieveAbstractAuthentication { 16 | 17 | /** 18 | * Create a new instance. 19 | * 20 | * @param {SieveAccount} account 21 | * a reference to the parent sieve account. 22 | */ 23 | constructor(account) { 24 | this.account = account; 25 | } 26 | 27 | /** 28 | * Returns the password for the chosen mechanism. 29 | * 30 | * Not all mechanisms require a password. 31 | * Others e.g. when prompting do not always return a password. 32 | * 33 | * @abstract 34 | * 35 | * @returns {string | null} 36 | * the password or null e.g. when the password prompt was dismissed. 37 | **/ 38 | async getPassword() { 39 | throw new Error("Implement getPassword()"); 40 | } 41 | 42 | /** 43 | * Returns the username for the account. 44 | * 45 | * @abstract 46 | * 47 | * @returns {string} 48 | * the username as string. 49 | **/ 50 | async getUsername() { 51 | throw new Error("Implement getUsername()"); 52 | } 53 | } 54 | 55 | export { SieveAbstractAuthentication }; 56 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/settings/logic/SieveAbstractSecurity.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | const SECURITY_NONE = 0; 13 | const SECURITY_EXPLICIT = 1; 14 | const SECURITY_IMPLICIT = 2; 15 | 16 | /** 17 | * Defines the security related settings for an account. 18 | * It is a minimal, mozilla specific implementation. 19 | */ 20 | class SieveAbstractSecurity { 21 | 22 | /** 23 | * Creates a new instance. 24 | * 25 | * @param {SieveAccount} account 26 | * the account with is associated with this account. 27 | */ 28 | constructor(account) { 29 | this.account = account; 30 | } 31 | 32 | /** 33 | * Gets the connection security. 34 | * 35 | * @returns {int} 36 | * the current connection security. 37 | * 38 | * 0 for no connection security 39 | * 1 for implicit tls 40 | * 2 for explicit tls 41 | */ 42 | async getTLS() { 43 | return await SECURITY_EXPLICIT; 44 | } 45 | 46 | /** 47 | * Gets the currently configured sasl mechanism. 48 | * 49 | * @returns {string} 50 | * the sasl mechanism 51 | **/ 52 | async getMechanism() { 53 | return await "default"; 54 | } 55 | } 56 | 57 | export { 58 | SieveAbstractSecurity, 59 | SECURITY_NONE, 60 | SECURITY_EXPLICIT, 61 | SECURITY_IMPLICIT 62 | }; 63 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/settings/logic/SieveAccountSettings.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | const CONFIG_DEBUG_ACCOUNT = "debug"; 13 | const DEFAULT_LOG_LEVEL = 0; 14 | 15 | /** 16 | * Manages the accounts common settings. 17 | */ 18 | class SieveAccountSettings { 19 | 20 | /** 21 | * Creates a new instance. 22 | * 23 | * @param {SieveAccount} account 24 | * a reference to the parent sieve account. 25 | */ 26 | constructor(account) { 27 | this.account = account; 28 | } 29 | 30 | /** 31 | * Gets the log levels for the given account. 32 | * 33 | * @returns {int} 34 | * the current log level 35 | */ 36 | async getLogLevel() { 37 | return await this.account.getConfig() 38 | .getInteger(CONFIG_DEBUG_ACCOUNT, DEFAULT_LOG_LEVEL); 39 | } 40 | 41 | /** 42 | * Sets the log level for the given account. 43 | * 44 | * @param {int} level 45 | * the new log level 46 | * 47 | * @returns {SieveAccountSettings} 48 | * a self reference. 49 | */ 50 | async setLogLevel(level) { 51 | await this.account.getConfig().setInteger(CONFIG_DEBUG_ACCOUNT, level); 52 | return this; 53 | } 54 | 55 | } 56 | 57 | export { SieveAccountSettings }; 58 | -------------------------------------------------------------------------------- /src/common/managesieve.ui/utils/SieveUniqueId.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via email 4 | * from the author. Do not remove or change this comment. 5 | * 6 | * The initial author of the code is: 7 | * Thomas Schmid 8 | * 9 | */ 10 | 11 | const ASCII = 36; 12 | const SEED_OFFSET = 2; 13 | const SEED_LENGTH = 16; 14 | /** 15 | * Generates a poor mans unique id. 16 | * It simply combines the current time with a random number. 17 | * Which should be more than sufficient for us. 18 | */ 19 | class SieveUniqueId { 20 | 21 | /** 22 | * Creates a pseudo random alpha numerical id. 23 | * @returns {string} 24 | * the generated id. 25 | */ 26 | generate() { 27 | // "" + Math.floor(Math.random() * 10000000).toString(16) + Date.now().toString(16) 28 | return Date.now().toString(ASCII) 29 | + "-" + Math.random().toString(ASCII).substr(SEED_OFFSET, SEED_LENGTH); 30 | } 31 | } 32 | 33 | export { SieveUniqueId }; 34 | -------------------------------------------------------------------------------- /src/web/script/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/web/script/__init__.py -------------------------------------------------------------------------------- /src/web/script/handler/config.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | 4 | from ..http import HttpResponse 5 | 6 | class ConfigHandler: 7 | 8 | def __init__(self, config): 9 | self.__config = config 10 | 11 | def can_handle_request(self, request) -> bool: 12 | if request.method != "GET": 13 | return False 14 | 15 | if request.path != "/config.json": 16 | return False 17 | 18 | return True 19 | 20 | def handle_request(self, context, request) -> None: 21 | 22 | data = {} 23 | 24 | for account in self.__config.get_accounts(): 25 | 26 | try: 27 | 28 | data[account.get_id()] = { 29 | 'displayname' : account.get_name(), 30 | 'username' : account.get_auth_username(request), 31 | 'authenticate' : account.can_authenticate(), 32 | 'authorize' : account.can_authorize(), 33 | 'endpoint' : f"websocket/{account.get_id()}" 34 | } 35 | 36 | except Exception as ex: 37 | logging.warning(f"Skipping invalid account configuration {account.get_name()}, cause {ex}") 38 | 39 | # if config from request 40 | # Reverse proxy default header 41 | #username = request.get_header("REMOTE_USER") 42 | # else 43 | # username = config.read() 44 | # hostname = config.read() 45 | 46 | # config.read("authentication") 47 | # config.port 48 | 49 | # for account ins config: 50 | 51 | response = HttpResponse() 52 | response.add_headers({ 53 | 'Content-Type': "application/json", 54 | 'Connection': 'close' 55 | }) 56 | response.send(context, json.dumps(data)) 57 | -------------------------------------------------------------------------------- /src/web/script/handler/websocket.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from ..websocket import WebSocket 4 | from ..sieve.sievesocket import SieveSocket 5 | from ..messagepump import MessagePump 6 | 7 | class WebSocketHandler: 8 | 9 | def __init__(self, config): 10 | self.__config = config 11 | 12 | def can_handle_request(self, request) -> bool: 13 | if request.method != "GET": 14 | return False 15 | 16 | if not request.path.startswith("/websocket/"): 17 | return False 18 | 19 | return True 20 | 21 | def handle_request(self, context, request) -> None: 22 | 23 | logging.info(f"Websocket Request for {request.path}") 24 | 25 | account = self.__config.get_account_by_id( 26 | request.path[len("/websocket/"):]) 27 | 28 | host = account.get_sieve_host() 29 | port = int(account.get_sieve_port()) 30 | 31 | # Websocket is read 32 | with WebSocket(request, context) as websocket: 33 | with SieveSocket(host, port) as sievesocket: 34 | 35 | sievesocket.start_tls() 36 | 37 | if not account.can_authenticate(): 38 | logging.info(f"Do Proxy authentication for {account.get_name()}") 39 | sievesocket.authenticate( 40 | account.get_sieve_user(request), 41 | account.get_sieve_password(request), 42 | account.get_auth_username(request)) 43 | 44 | # Publish capabilities to client... 45 | websocket.send( 46 | sievesocket.capabilities) 47 | 48 | MessagePump().run(websocket, sievesocket) 49 | -------------------------------------------------------------------------------- /src/web/script/messagepump.py: -------------------------------------------------------------------------------- 1 | import select 2 | import logging 3 | 4 | class MessagePump: 5 | 6 | 7 | def wait(self, server, client): 8 | 9 | ready_to_read, _ready_to_write, in_error \ 10 | = select.select([server, client], [], [server, client]) 11 | 12 | if server in in_error: 13 | raise Exception("Reading server connection failed") 14 | 15 | if client in in_error: 16 | raise Exception("Reading client connection failed") 17 | 18 | return ready_to_read 19 | 20 | def run(self, server, client) -> None: 21 | 22 | while True: 23 | sockets = self.wait(server, client) 24 | 25 | if server in sockets: 26 | data = server.recv() 27 | 28 | if data == b'': 29 | logging.info("Server terminated") 30 | return 31 | 32 | logging.debug(data) 33 | client.send(data) 34 | 35 | if client in sockets: 36 | data = client.recv() 37 | 38 | if data == b'': 39 | logging.info(" Client terminated") 40 | return 41 | 42 | logging.debug(data) 43 | server.send(data) 44 | -------------------------------------------------------------------------------- /src/web/script/sieve/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thsmi/sieve/4bcefba15314177521a45a833e53969b50f4351e/src/web/script/sieve/__init__.py -------------------------------------------------------------------------------- /src/web/script/sieve/__main__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from argparse import ArgumentParser 4 | from getpass import getpass 5 | 6 | from .sievesocket import SieveSocket 7 | 8 | parser = ArgumentParser(description='Tests the connection to a sieve server.') 9 | parser.add_argument("host", help="The sieve server's hostname") 10 | parser.add_argument("--port", help="The server's port", type=int, default=4190) 11 | parser.add_argument("--username", help="The username to be used for authentication") 12 | parser.add_argument("--password", help="The password to be used for authentication") 13 | 14 | args = parser.parse_args() 15 | 16 | if args.username is None: 17 | #args.username = getpass.getuser() 18 | args.username = input("Username: ") 19 | 20 | if args.password is None: 21 | args.password = getpass() 22 | 23 | with SieveSocket(args.host, args.port) as socket: 24 | logging.debug(socket.capabilities) 25 | socket.start_tls() 26 | 27 | socket.authenticate(args.username, args.password, "") 28 | 29 | socket.send(b"LISTSCRIPTS\r\n") 30 | logging.debug(socket.recv()) 31 | -------------------------------------------------------------------------------- /src/web/static/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Manage Sieve Scripts 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
    21 | 22 | 36 | 37 |
    38 | 39 |
    40 | 41 |
    42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/web/static/libs/libManageSieve/SieveSession.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractSession } from "./SieveAbstractSession.mjs"; 13 | 14 | /** 15 | * A mozilla specific session implementation. 16 | */ 17 | class SieveWebSession extends SieveAbstractSession { 18 | 19 | } 20 | 21 | export { SieveWebSession as SieveSession }; 22 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/accounts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Manage Sieve Scripts 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/accounts/SieveAccountUI.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | 13 | import { SieveAbstractAccountUI } from "./SieveAbstractAccountUI.mjs"; 14 | 15 | /** 16 | * A UI renderer for a sieve account 17 | */ 18 | class SieveWebAccountUI extends SieveAbstractAccountUI{ 19 | 20 | } 21 | 22 | export { SieveWebAccountUI as SieveAccountUI }; 23 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/accounts/SieveAccounts.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractAccounts } from "./SieveAbstractAccounts.mjs"; 13 | 14 | /** 15 | * @inheritdoc 16 | */ 17 | class SieveWebAccounts extends SieveAbstractAccounts { 18 | 19 | } 20 | 21 | export { SieveWebAccounts as SieveAccounts }; 22 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/accounts/account.settings.html: -------------------------------------------------------------------------------- 1 |
    2 |

    3 |
    4 |
    5 | : 6 | 7 | 8 |
    9 |
    10 |
    11 |
    12 |
    13 |
    14 | 17 |
    18 |
    -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/settings/logic/SieveAccount.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractAccount } from "./SieveAbstractAccount.mjs"; 13 | 14 | /** 15 | * Manages the account specific settings 16 | */ 17 | class SieveWebAccount extends SieveAbstractAccount { 18 | 19 | /** 20 | * Creates a new instance. 21 | * 22 | * @param {string} id 23 | * the account's unique id. 24 | * @param {object} serverConfig 25 | * the server's configuration as json object. 26 | */ 27 | constructor(id, serverConfig) { 28 | super(id); 29 | this.serverConfig = serverConfig; 30 | } 31 | 32 | /** 33 | * Returns the configuration retrieved from the server. 34 | * @returns {object} 35 | * the current configuration. 36 | */ 37 | getServerConfig() { 38 | return this.serverConfig; 39 | } 40 | 41 | 42 | } 43 | 44 | 45 | export { SieveWebAccount as SieveAccount}; 46 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/settings/logic/SieveAccounts.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAccount } from "./SieveAccount.mjs"; 13 | import { SieveAbstractAccounts } from "./SieveAbstractAccounts.mjs"; 14 | 15 | /** 16 | * Manages the configuration for sieve accounts. 17 | * It queries thunderbird's account and extracts all needed information. 18 | * 19 | * Global settings are stored in the addons persistence. 20 | */ 21 | class SieveAccounts extends SieveAbstractAccounts { 22 | 23 | /** 24 | * @inheritdoc 25 | */ 26 | async load() { 27 | 28 | const items = await (await fetch("./config.json")).json(); 29 | 30 | const accounts = {}; 31 | 32 | for (const key of Object.keys(items)) { 33 | accounts[key] = new SieveAccount(key, items[key]); 34 | } 35 | 36 | this.accounts = accounts; 37 | return this; 38 | } 39 | 40 | } 41 | 42 | export { SieveAccounts }; 43 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/settings/logic/SieveAuthentication.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractAuthentication } from "./SieveAbstractAuthentication.mjs"; 13 | 14 | import { SieveIpcClient } from "./../../utils/SieveIpcClient.mjs"; 15 | 16 | /** 17 | * Uses the IMAP accounts credentials. 18 | */ 19 | class SieveWebSocketAuthentication extends SieveAbstractAuthentication { 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | async getPassword() { 25 | 26 | const request = { 27 | "username": await this.getUsername(), 28 | "displayname": await (await this.account.getHost()).getDisplayName(), 29 | "remember": false 30 | }; 31 | 32 | const credentials = await SieveIpcClient.sendMessage( 33 | "accounts", "account-show-authentication", request); 34 | 35 | return credentials.password; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | */ 41 | hasPassword() { 42 | return this.account.getServerConfig().authenticate; 43 | } 44 | 45 | /** 46 | * @inheritdoc 47 | */ 48 | async getUsername() { 49 | return this.account.getServerConfig().username; 50 | } 51 | } 52 | 53 | export { SieveWebSocketAuthentication as SieveAuthentication }; 54 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/settings/logic/SieveAuthorization.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | 13 | const AUTHORIZATION_TYPE_USERNAME = 1; 14 | const CONFIG_AUTHORIZATION_TYPE = "authorization.type"; 15 | 16 | import { SieveAbstractMechanism } from "./SieveAbstractMechanism.mjs"; 17 | import { SieveDefaultAuthorization } from "./SieveAbstractAuthorization.mjs"; 18 | 19 | /** 20 | * Manages the authorization settings. 21 | */ 22 | class SieveAuthorization extends SieveAbstractMechanism { 23 | 24 | /** 25 | * @inheritdoc 26 | **/ 27 | getDefault() { 28 | return AUTHORIZATION_TYPE_USERNAME; 29 | } 30 | 31 | /** 32 | * @inheritdoc 33 | **/ 34 | getKey() { 35 | return CONFIG_AUTHORIZATION_TYPE; 36 | } 37 | 38 | /** 39 | * @inheritdoc 40 | **/ 41 | hasMechanism(type) { 42 | switch (type) { 43 | case AUTHORIZATION_TYPE_USERNAME: 44 | return true; 45 | 46 | default: 47 | return false; 48 | } 49 | } 50 | 51 | /** 52 | * @inheritdoc 53 | */ 54 | async getMechanism() { 55 | return new SieveDefaultAuthorization(AUTHORIZATION_TYPE_USERNAME, this.account); 56 | } 57 | 58 | /** 59 | * @inheritdoc 60 | **/ 61 | getMechanismById() { 62 | return new SieveDefaultAuthorization(AUTHORIZATION_TYPE_USERNAME, this.account); 63 | } 64 | } 65 | 66 | export { SieveAuthorization }; 67 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/settings/logic/SievePrefManager.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractPrefManager } from "./SieveAbstractPrefManager.mjs"; 13 | 14 | /** 15 | * Manages preferences. 16 | * It uses the WebExtension's local storage interface 17 | */ 18 | class SieveWebSocketPrefManager extends SieveAbstractPrefManager { 19 | 20 | /** 21 | * @inheritdoc 22 | */ 23 | async getValue(key) { 24 | 25 | key = `${this.getNamespace()}.${key}`; 26 | return await (window.localStorage.getItem(key)); 27 | } 28 | 29 | /** 30 | * @inheritdoc 31 | */ 32 | async setValue(key, value) { 33 | 34 | key = `${this.getNamespace()}.${key}`; 35 | await (window.localStorage.setItem(key, value)); 36 | return this; 37 | } 38 | } 39 | 40 | export { SieveWebSocketPrefManager as SievePrefManager }; 41 | -------------------------------------------------------------------------------- /src/web/static/libs/managesieve.ui/settings/logic/SieveSecurity.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractSecurity } from "./SieveAbstractSecurity.mjs"; 13 | 14 | export { SieveAbstractSecurity as SieveSecurity }; 15 | -------------------------------------------------------------------------------- /src/wx/_locales/af_ZA/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/ar_SA/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/ca_ES/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/cs_CZ/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Spravuje Sieve filtry zpráv", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve filtry zpráv", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/da_DK/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/de_DE/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Verwaltet Sieve Filter", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Filter", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/el_GR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/en_US/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | 7 | "menuTitle": { 8 | "message": "Sieve Message Filters", 9 | "description": "The menu item's name." 10 | }, 11 | 12 | "menuAccessKey": { 13 | "message": "S", 14 | "description": "The menu item's access key." 15 | } 16 | } -------------------------------------------------------------------------------- /src/wx/_locales/es_ES/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/fi_FI/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/fr_FR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/he_IL/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/hu_HU/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Szita üzenetszűrők kezelése", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Szita üzenetszűrők", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/id_ID/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/it_IT/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/ja_JP/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/ko_KR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/nl_NL/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/no_NO/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/pl_PL/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/pt_BR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/pt_PT/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/ro_RO/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/ru_RU/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/sk_SK/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/sr_SP/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/sv_SE/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/tr_TR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/uk_UA/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/vi_VN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/zh_CN/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/_locales/zh_TW/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionDescription": { 3 | "message": "Manages Sieve Message Filters", 4 | "description": "Description of the extension." 5 | }, 6 | "menuTitle": { 7 | "message": "Sieve Message Filters", 8 | "description": "The menu item's name." 9 | }, 10 | "menuAccessKey": { 11 | "message": "S", 12 | "description": "The menu item's access key." 13 | } 14 | } -------------------------------------------------------------------------------- /src/wx/api/sieve/SieveAccountsApi.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "namespace": "sieve.accounts", 4 | "description": "Sieve Account Management", 5 | "functions": [ 6 | { 7 | "name": "getPassword", 8 | "type": "function", 9 | "description": "Gets a password from the password store", 10 | "async": true, 11 | "parameters": [ 12 | { 13 | "name": "id", 14 | "type": "string", 15 | "description": "The server's id" 16 | } 17 | ] 18 | }, 19 | { 20 | "name": "getPrettyName", 21 | "type": "function", 22 | "description": "Gets a password from the password store", 23 | "async": true, 24 | "parameters": [ 25 | { 26 | "name": "id", 27 | "type": "string", 28 | "description": "The account key" 29 | } 30 | ] 31 | }, 32 | { 33 | "name": "getUsername", 34 | "type": "function", 35 | "description": "Gets a password from the password store", 36 | "async": true, 37 | "parameters": [ 38 | { 39 | "name": "id", 40 | "type": "string", 41 | "description": "The account key" 42 | } 43 | ] 44 | }, 45 | { 46 | "name": "getHostname", 47 | "type": "function", 48 | "description": "Gets a password from the password store", 49 | "async": true, 50 | "parameters": [ 51 | { 52 | "name": "id", 53 | "type": "string", 54 | "description": "The account key" 55 | } 56 | ] 57 | } 58 | ] 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /src/wx/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/wx/libs/libManageSieve/SieveSession.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractSession } from "./SieveAbstractSession.mjs"; 13 | 14 | /** 15 | * A mozilla specific session implementation. 16 | */ 17 | class SieveMozSession extends SieveAbstractSession { 18 | } 19 | 20 | export { SieveMozSession as SieveSession }; 21 | -------------------------------------------------------------------------------- /src/wx/libs/libManageSieve/SieveTimer.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | 13 | import { SieveAbstractTimer } from "./SieveAbstractTimer.mjs"; 14 | 15 | /** 16 | * Uses JavaScript's setTimeout() method to implement a timer. 17 | */ 18 | class SieveWebTimer extends SieveAbstractTimer { 19 | 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | cancel() { 25 | if (!this.timer) 26 | return; 27 | 28 | window.clearTimeout(this.timer); 29 | this.timer = null; 30 | } 31 | 32 | /** 33 | * @inheritdoc 34 | */ 35 | start(callback, ms) { 36 | this.cancel(); 37 | 38 | if (ms === 0) 39 | return; 40 | 41 | this.timer = window.setTimeout(callback, ms); 42 | } 43 | } 44 | 45 | export { SieveWebTimer as SieveTimer }; 46 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/accounts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
    16 |
    17 |
    18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/accounts/SieveAccountUI.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractAccountUI } from "./SieveAbstractAccountUI.mjs"; 13 | 14 | 15 | /** 16 | * A UI renderer for a sieve account 17 | */ 18 | class SieveMozAccountUI extends SieveAbstractAccountUI { 19 | } 20 | 21 | export { SieveMozAccountUI as SieveAccountUI }; 22 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/accounts/SieveAccounts.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | 13 | import { SieveAbstractAccounts } from "./SieveAbstractAccounts.mjs"; 14 | 15 | /** 16 | * @inheritdoc 17 | */ 18 | class SieveWxAccounts extends SieveAbstractAccounts { 19 | 20 | } 21 | 22 | export { SieveWxAccounts as SieveAccounts }; 23 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/accounts/account.settings.html: -------------------------------------------------------------------------------- 1 |
    2 |

    3 |
    4 |
    5 | : 6 | 7 | 8 |
    9 | 13 |
    14 |
    15 |
    16 |
    17 | 21 |
    22 | 24 | 27 |
    28 |
    -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/settings/logic/SieveAccounts.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | /* global browser */ 13 | import { SieveAbstractAccount } from "./SieveAbstractAccount.mjs"; 14 | import { SieveAbstractAccounts } from "./SieveAbstractAccounts.mjs"; 15 | 16 | /** 17 | * Manages the configuration for sieve accounts. 18 | * It queries thunderbird's account and extracts all needed information. 19 | * 20 | * Global settings are stored in the addons persistence. 21 | */ 22 | class SieveAccounts extends SieveAbstractAccounts { 23 | 24 | /** 25 | * @inheritdoc 26 | */ 27 | async load() { 28 | 29 | const items = await (browser.accounts.list()); 30 | 31 | const accounts = {}; 32 | 33 | if (!items) 34 | return this; 35 | 36 | for (const item of items) { 37 | 38 | if (item.type !== "imap" && item.type !== "pop3") 39 | continue; 40 | 41 | accounts[item.id] = new SieveAbstractAccount(item.id); 42 | } 43 | 44 | this.accounts = accounts; 45 | return this; 46 | } 47 | 48 | } 49 | 50 | export { SieveAccounts }; 51 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/settings/logic/SieveAuthentication.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | import { SieveAbstractAuthentication } from "./SieveAbstractAuthentication.mjs"; 13 | 14 | /* global browser */ 15 | 16 | /** 17 | * Uses the IMAP accounts credentials. 18 | */ 19 | class SieveMozAuthentication extends SieveAbstractAuthentication { 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | async getPassword() { 25 | return await browser.sieve.accounts.getPassword(this.account.getId()); 26 | } 27 | 28 | /** 29 | * @inheritdoc 30 | */ 31 | async getUsername() { 32 | return await browser.sieve.accounts.getUsername(this.account.getId()); 33 | } 34 | } 35 | 36 | export { SieveMozAuthentication as SieveAuthentication }; 37 | 38 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/settings/logic/SieveAuthorization.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | const AUTHORIZATION_TYPE_USERNAME = 1; 13 | const CONFIG_AUTHORIZATION_TYPE = "authorization.type"; 14 | 15 | import { SieveAbstractMechanism } from "./SieveAbstractMechanism.mjs"; 16 | import { SieveDefaultAuthorization } from "./SieveAbstractAuthorization.mjs"; 17 | 18 | /** 19 | * Manages the authorization settings. 20 | */ 21 | class SieveAuthorization extends SieveAbstractMechanism { 22 | 23 | /** 24 | * @inheritdoc 25 | **/ 26 | getDefault() { 27 | return AUTHORIZATION_TYPE_USERNAME; 28 | } 29 | 30 | /** 31 | * @inheritdoc 32 | **/ 33 | getKey() { 34 | return CONFIG_AUTHORIZATION_TYPE; 35 | } 36 | 37 | /** 38 | * @inheritdoc 39 | **/ 40 | hasMechanism(type) { 41 | switch (type) { 42 | case AUTHORIZATION_TYPE_USERNAME: 43 | return true; 44 | 45 | default: 46 | return false; 47 | } 48 | } 49 | 50 | /** 51 | * @inheritdoc 52 | **/ 53 | getMechanismById(type) { 54 | switch (type) { 55 | case AUTHORIZATION_TYPE_USERNAME: 56 | return new SieveDefaultAuthorization(AUTHORIZATION_TYPE_USERNAME, this.account); 57 | 58 | default: 59 | throw new Error("Unknown authorization mechanism"); 60 | } 61 | } 62 | } 63 | 64 | export { SieveAuthorization }; 65 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/settings/logic/SieveHost.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | /* global browser */ 13 | 14 | import { SieveCustomHost } from "./SieveAbstractHost.mjs"; 15 | 16 | const CONFIG_KEEP_ALIVE_INTERVAL = "keepalive"; 17 | // eslint-disable-next-line no-magic-numbers 18 | const ONE_MINUTE = 60 * 1000; 19 | // eslint-disable-next-line no-magic-numbers 20 | const FIVE_MINUTES = 5 * ONE_MINUTE; 21 | 22 | /** 23 | * This class loads the hostname from an IMAP account. The hostname is not 24 | * cached it. This ensures that always the most recent settings are used. 25 | */ 26 | class SieveMozHost extends SieveCustomHost { 27 | 28 | /** 29 | * @inheritdoc 30 | */ 31 | async getDisplayName() { 32 | return await browser.sieve.accounts.getPrettyName(this.account.getId()); 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | async getHostname() { 39 | return await browser.sieve.accounts.getHostname(this.account.getId()); 40 | } 41 | 42 | /** 43 | * @inheritdoc 44 | */ 45 | async getKeepAlive() { 46 | return await this.account.getConfig().getInteger(CONFIG_KEEP_ALIVE_INTERVAL, FIVE_MINUTES); 47 | } 48 | } 49 | 50 | export { SieveMozHost as SieveHost }; 51 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/settings/logic/SievePrefManager.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | /* global browser */ 13 | import { SieveAbstractPrefManager } from "./SieveAbstractPrefManager.mjs"; 14 | 15 | /** 16 | * Manages preferences. 17 | * It uses the WebExtension's local storage interface 18 | */ 19 | class SieveMozPrefManager extends SieveAbstractPrefManager { 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | async getValue(key) { 25 | key = `${this.getNamespace()}.${key}`; 26 | 27 | const pair = await browser.storage.local.get(key); 28 | 29 | if (pair[key] === undefined) 30 | return undefined; 31 | 32 | return pair[key]; 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | async setValue(key, value) { 39 | 40 | const item = {}; 41 | item[`${this.getNamespace()}.${key}`] = value; 42 | 43 | await browser.storage.local.set(item); 44 | return this; 45 | } 46 | } 47 | 48 | 49 | export { SieveMozPrefManager as SievePrefManager }; 50 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/settings/logic/SieveSecurity.mjs: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | 13 | import { SieveAbstractSecurity } from "./SieveAbstractSecurity.mjs"; 14 | 15 | export { SieveAbstractSecurity as SieveSecurity }; 16 | 17 | -------------------------------------------------------------------------------- /src/wx/libs/managesieve.ui/utils/SieveIpcClient.js: -------------------------------------------------------------------------------- 1 | /* 2 | * The content of this file is licensed. You may obtain a copy of 3 | * the license at https://github.com/thsmi/sieve/ or request it via 4 | * email from the author. 5 | * 6 | * Do not remove or change this comment. 7 | * 8 | * The initial author of the code is: 9 | * Thomas Schmid 10 | */ 11 | 12 | /* global browser */ 13 | import { SieveLogger } from "./SieveLogger.mjs"; 14 | import { SieveAbstractIpcClient } from "./SieveAbstractIpcClient.mjs"; 15 | 16 | /** 17 | * An abstract implementation for a inter process/frame communication. 18 | */ 19 | class SieveWxIpcClient extends SieveAbstractIpcClient { 20 | 21 | /** 22 | * @inheritdoc 23 | */ 24 | static getLogger() { 25 | return SieveLogger.getInstance(); 26 | } 27 | 28 | /** 29 | * @inheritdoc 30 | */ 31 | static parseMessageFromEvent(e) { 32 | return JSON.parse(e.data); 33 | } 34 | 35 | /** 36 | * @inheritdoc 37 | */ 38 | // eslint-disable-next-line no-unused-vars 39 | static dispatch(message, target) { 40 | 41 | if (typeof (message) !== 'string') { 42 | message = JSON.stringify(message); 43 | } 44 | 45 | browser.runtime.sendMessage(message); 46 | } 47 | } 48 | 49 | browser.runtime.onMessage.addListener((request, sender) => { 50 | SieveWxIpcClient.onMessage({ data: request, source: sender }); 51 | }); 52 | 53 | export { SieveWxIpcClient as SieveIpcClient }; 54 | -------------------------------------------------------------------------------- /src/wx/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Sieve", 3 | "description": "__MSG_extensionDescription__", 4 | "version": "0.6.1", 5 | "icons": { 6 | "64": "libs/icons/linux.png" 7 | }, 8 | "background": { 9 | "page": "background.html" 10 | }, 11 | "manifest_version": 2, 12 | "default_locale": "en_US", 13 | "browser_specific_settings": { 14 | "gecko": { 15 | "id": "sieve@mozdev.org", 16 | "update_url": "https://thsmi.github.io/sieve/update.json", 17 | "strict_min_version": "68.0a1" 18 | } 19 | }, 20 | "permissions": [ 21 | "accountsRead", 22 | "tabs", 23 | "storage" 24 | ], 25 | "experiment_apis": { 26 | "SieveAccountsApi": { 27 | "schema": "api/sieve/SieveAccountsApi.json", 28 | "parent": { 29 | "scopes": [ 30 | "addon_parent" 31 | ], 32 | "script": "api/sieve/SieveAccountsApi.js", 33 | "paths": [ 34 | [ 35 | "sieve", 36 | "accounts" 37 | ] 38 | ] 39 | } 40 | }, 41 | "SieveSocketApi": { 42 | "schema": "api/sieve/SieveSocketApi.json", 43 | "parent": { 44 | "scopes": [ 45 | "addon_parent" 46 | ], 47 | "script": "api/sieve/SieveSocketApi.js", 48 | "paths": [ 49 | [ 50 | "sieve", 51 | "socket" 52 | ] 53 | ] 54 | } 55 | }, 56 | "SieveMenuApi": { 57 | "schema": "api/sieve/SieveMenuApi.json", 58 | "parent": { 59 | "scopes": [ 60 | "addon_parent" 61 | ], 62 | "script": "api/sieve/SieveMenuApi.js", 63 | "paths": [ 64 | [ 65 | "sieve", 66 | "menu" 67 | ] 68 | ] 69 | } 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | YaUTT - Yet Another Unit Test Tool 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
    22 | 36 | 37 |
    38 | 41 | 42 | 43 |
    44 |
    45 |
    46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | 2 | const { tests } = require("./tests/tests.js"); 3 | const { NodeTestSuite } = require("./js/node/NodeTestSuite.js"); 4 | const { NodeTestReport } = require("./js/node//NodeTestReport.js"); 5 | 6 | const { JUnitExporter } = require("./js/exporter/JUnitExporter.js"); 7 | 8 | const { writeFile } = require('fs').promises; 9 | 10 | const EXIT_CODE_ERROR = 1; 11 | const JUNIT_EXPORT_FILE = "./TEST-sieve.xml"; 12 | 13 | /** 14 | * The entry point 15 | */ 16 | async function main() { 17 | 18 | const suite = new NodeTestSuite(); 19 | const report = new NodeTestReport("Test"); 20 | 21 | await suite.load(tests).run(report); 22 | 23 | await writeFile(JUNIT_EXPORT_FILE, (new JUnitExporter()).export(report)); 24 | 25 | report.summary(); 26 | 27 | if (report.hasFailed()) 28 | process.exitCode = EXIT_CODE_ERROR; 29 | 30 | } 31 | 32 | main(); 33 | -------------------------------------------------------------------------------- /tests/js/browser/sandbox/sandbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/js/style.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | height: 100%; 4 | margin: 0; 5 | padding: 0; 6 | font-family: Arial, Helvetica, sans-serif; 7 | } 8 | 9 | #content { 10 | flex: 1; 11 | flex-grow: 1; 12 | height: 100%; 13 | overflow: scroll; 14 | padding-left: 10px; 15 | } 16 | 17 | #sidebar { 18 | flex-grow: 0; 19 | flex-basis: 250px; 20 | background-color: #f5f5f5; 21 | padding-left: 10px; 22 | } 23 | 24 | #container { 25 | display: flex; 26 | height: 100%; 27 | } 28 | 29 | .success { 30 | color: green; 31 | } 32 | 33 | .failure { 34 | color: red; 35 | } 36 | 37 | .logInfo { 38 | white-space: pre; 39 | } 40 | 41 | .logTrace { 42 | white-space: pre; 43 | color: gray; 44 | display: none; 45 | } 46 | 47 | #divOutput.showTrace .logTrace { 48 | display: inherit !important; 49 | } 50 | 51 | .logHeader { 52 | font-size: 1.2em; 53 | border-bottom: 1px solid lightgray; 54 | margin-bottom: 10px; 55 | margin-top: 20px; 56 | } 57 | 58 | .logError { 59 | white-space: pre; 60 | color: red; 61 | } 62 | 63 | .logFailure { 64 | white-space: pre; 65 | color: red; 66 | padding-top: 10px; 67 | } 68 | 69 | .logSuccess { 70 | white-space: pre; 71 | color: green; 72 | padding-top: 10px; 73 | } 74 | 75 | .logWarning { 76 | white-space: pre; 77 | color: orange; 78 | padding-top: 10px; 79 | } 80 | 81 | #tests div span { 82 | cursor: pointer; 83 | } 84 | -------------------------------------------------------------------------------- /tools/.gitignore: -------------------------------------------------------------------------------- 1 | /.metadata/ 2 | /.recommenders/ 3 | -------------------------------------------------------------------------------- /tools/Docker/dovecot/README.md: -------------------------------------------------------------------------------- 1 | # Simplistic Dovecot Docker Container 2 | 3 | Provides a docker container to simplify testing and debugging the sieve addon 4 | and webextension against a real mail server. 5 | 6 | Dovecot is configured to provide IMAP and Sieve. Only a single user "user" is 7 | configured the password is "pencil" and configured in "/etc/dovecot/users" 8 | 9 | Authentication logging is set to verbose to allow debugging problems and 10 | bugs during authentication. 11 | -------------------------------------------------------------------------------- /tools/Docker/dovecot/dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | RUN apk add dovecot dovecot-pigeonhole-plugin 4 | #RUN apk add bash mc 5 | 6 | RUN adduser vmail -D 7 | 8 | COPY local.conf /etc/dovecot/local.conf 9 | COPY dovecot-openssl.conf /etc/dovecot/dovecot-openssl.conf 10 | 11 | RUN echo "user:{plain}pencil::::::" > /etc/dovecot/users && \ 12 | echo "user2:{plain}€äöü§²³::::::" >> /etc/dovecot/users 13 | 14 | RUN mkdir -p /etc/ssl/private && \ 15 | openssl req -new -x509 -nodes -days 365 \ 16 | -config "/etc/dovecot/dovecot-openssl.conf" \ 17 | -out "/etc/ssl/certs/dovecot.pem" \ 18 | -keyout "/etc/ssl/private/dovecot.pem" && \ 19 | chmod 0600 "/etc/ssl/private/dovecot.pem" 20 | 21 | EXPOSE 143 993 4190 22 | 23 | CMD /usr/sbin/dovecot && tail -f /var/log/dovecot.log 24 | -------------------------------------------------------------------------------- /tools/Docker/dovecot/dovecot-openssl.conf: -------------------------------------------------------------------------------- 1 | [ req ] 2 | default_bits = 2048 3 | encrypt_key = yes 4 | distinguished_name = req_dn 5 | x509_extensions = cert_type 6 | prompt = no 7 | 8 | [ req_dn ] 9 | # country (2 letter code) 10 | #C=FI 11 | 12 | # State or Province Name (full name) 13 | #ST= 14 | 15 | # Locality Name (eg. city) 16 | #L=Helsinki 17 | 18 | # Organization (eg. company) 19 | #O=Dovecot 20 | 21 | # Organizational Unit Name (eg. section) 22 | OU=IMAP server 23 | 24 | # Common Name (*.example.com is also possible) 25 | CN=localhost 26 | 27 | # E-mail contact 28 | emailAddress=postmaster@localhost 29 | 30 | [ cert_type ] 31 | nsCertType = server 32 | 33 | [ alternate_names ] 34 | DNS.1 = localhost 35 | DNS.2 = localhost.localdomain 36 | IP.1 = 127.0.0.1 37 | IP.2 = ::1 -------------------------------------------------------------------------------- /tools/Docker/dovecot/local.conf: -------------------------------------------------------------------------------- 1 | #mail_home=/srv/mail/%Lu 2 | #mail_location=sdbox:~/Mail 3 | 4 | ## this is sometimes needed 5 | #first_valid_uid = uid-of-vmail-user 6 | 7 | 8 | #userdb { 9 | # driver = passwd 10 | # args = blocking=no 11 | # override_fields = uid=vmail gid=vmail 12 | #} 13 | 14 | # Uncomment these these lines to activate implicite TLS 15 | #service managesieve-login { 16 | # inet_listener sieve { 17 | # port = 4190 18 | # ssl = yes 19 | # } 20 | #} 21 | 22 | ssl=required 23 | ssl_verify_client_cert = no 24 | ssl_cert=