-
-
Notifications
You must be signed in to change notification settings - Fork 1
Developer Documentation
⚠ Please note that this documentation is not complete yet; any help is appreciated. ⚠
Tachyon is a fork of the RainLoop Webmail Project. RainLoop was initially written by Timur Usenko who worked at the company AfterLogic and who wrote the MailSo library. In RainLoop and Tachyon, MailSo is used to handle the main part of the IMAP communication. The Tachyon fork was initiated by Kim Schulz because RainLoop did not seem to be maintained regularly and had multiple security issues. Tachyon therefore contains the code of RainLoop, but has been modified a lot to bring it to a next level.
Please have a look to https://github.com/kimusan/Tachyon/wiki/FAQ#how-do-i-enable-logging on how you can enable logging inside of Tachyon.
Developers should additionally know that the logs normally do not contain passwords and other sensitive data because MailSo\Log\Logger::Write replaces those words by *******.
If you really have to log passwords you can set the parameter bool $bSearchSecretWords of the function Logger::Write to false or modify the configuration of Tachyon by changing the switch hide_passwords inside of application.ini.
The current front-end of Tachyon is written in KnockoutJS and communicates with the back-end by JSON-format data. Tachyon tries to render the most on the clients side to reduce server load on big installations. More details on why at the moment KnockoutJS is used can be read here.
Plugins extend the functionality of Tachyon. Administrators of a Tachyon installation can activate extensions by entering in the Admin Panel of Tachyon -> menu "Extensions" and checking the checkbox "Enable extensions".
On the same menu you can find a list of plugins available for installation. This list points to the official plugin repository of Tachyon. The source code of these plugins can be found here.
The source code of installed extensions is placed on your webserver inside the Tachyon folder under _data_/_default_/plugins/. Therefore you can also install "non official" extensions or plugins in development by copying their code into a subfolder of this folder; keep in mind to set the correct access rights on these new files.
The following shall describe how Tachyon initializes the activated extensions. All files can be found in the Tachyon repository under tachyon/v/3.0.12/ and the following paths are relative to that folder.
-
include.phpcallsTachyon\Service::Handle()inside ofapp/libraries/Tachyon/Service.php -
Service.phpcallsApi::Actions()inside ofapp/libraries/Tachyon/Api.php.- Additional info: Service.php afterwards goes ahead initializing for example the caching functions etc. and ends with a launch of the function BootEnd() in Actions.php
-
Api.phpcreates the object$oActionsby the classapp/libraries/Tachyon/Actions.php. - The constructor of
Actions.phpcreates an object$oPluginsby the classapp/libraries/Tachyon/Plugins/Manager.php. - The constructor of
Manager.phpsearches for active plugins. It then calls theInit()function of every active plugin.
Because the Init() function of every plugin is called by Manager.php inside this function, each plugin can register itself to be launched (=callback function) at various points in the code of Tachyon (=hooks).
Hooks and therefore your registered functions of the plugin are called on multiple points inside the source of Tachyon by launching the function RunHook of app/libraries/Tachyon/Plugins/Manager.php.
Plugins always extend the AbstractPlugin class.
To get an idea what is possible see the example plugin and the other plugins in the plugin repository.
Your plugin class inside the index.php of your plugin first should declare some information about it. This info will be shown inside the Admin Panel -> Extensions Menu and lets the user know what the plugin is intended for or if a new version of your plugin is available.
const
NAME = 'Avatars',
AUTHOR = 'Tachyon',
URL = 'https://snappymail.eu/',
VERSION = '1.5',
RELEASE = '2022-12-15',
REQUIRED = '2.23.0',
CATEGORY = 'Contacts',
LICENSE = 'MIT',
DESCRIPTION = 'Show graphic of sender in message and messages list (supports BIMI, Gravatar and identicon, Contacts is still TODO)';
In many cases your plugin will also need some configuration. For example the administrator could insert credentials for a database connection that your plugin needs to work properly. All these text fields, dropdown etc. are defined inside your plugin class inside protected function configMapping(): array. See for example this plugin to get an idea what you need to define inside configMapping(). Tachyon will take this definitions and create a configuration dialog that is reachable inside the Extensions menu of the Admin Panel (little cogwheel beside the name of your plugin).
The list of available PluginPropertyType (text fields, dropdown boxes...) can be found here.
The Init() function of a plugin can register one or more functions to be called when Tachyon hits a specific hook inside the code. This can happen for example when a user inserts his credentials, an IMAP connection was successful or a message is going to be saved.
To register the function myCallbackFunction inside of your index.php of your extension to the hook login.success you have to add the following to your Init() function:
$this->addHook('login.success', 'myCallbackFunction');If in Tachyon the hook login.success is executed, Tachyon will pass an array with parameters to the function RunHook defined in tachyon/v/3.0.12/app/libraries/Tachyon/Plugins/Manager.php. The length and content of the array with parameters depends on the specific hook. The function RunHook takes the array and passes the content as single parameters to your function myCallbackFunction; it will not hand over the array.
Therefore the example function myCallbackFunction should be defined to handle one parameter Account $oAccount because login.success passes you over the object of the account that was logged on.
A possible way to find an ideal hook for your extension is to do a fulltext search for the string RunHook( over the Tachyon source code. This returns every active hook and his circumstances like parameters that are passed to your callback function.
Also, this is the only way to make sure that your plugin is called at the moment you need.
For a complete list of available hooks inside of Tachyon see https://github.com/kimusan/Tachyon/blob/master/plugins/README.md#hooks. Here we will describe some hooks to let you get an idea what in detail is described inside the README.md.
Hook will run before the checks if the given username (=mail address) of a user is valid and contains a domain-part. This hook can modify the mail address before other checks are done if this is necessary.
Parameters passed to the plugins:
string &$sEmailHook will run after the checks described in login.credentials.step-1 when also the password of the users who tries to log in is available.
Parameters passed to the plugins:
string &$sEmail
string &$sPasswordYour plugin can use the function addJs (definition) to inject JavaScript to Tachyon. Inside this JavaScript code you could for example react on JavaScript Events.
Tachyon uses templates to define how for example the SystemDropDown menu (see image below) has to look like.
If your plugin needs to modify something inside this templates (for example add an additional button to the UI or modify the list of available functions inside the SystemDropDown) you can add JavaScript code to your plugin that modifies this template in the right moment. Detailed information on this topic can be found here: https://github.com/kimusan/Tachyon/issues/733#issuecomment-1333725216.