mirror of
https://github.com/EGroupware/egroupware.git
synced 2025-01-03 04:29:28 +01:00
WIP push for mail (currently only Dovecot with further configuration!)
This commit is contained in:
parent
6d9dfc6364
commit
bf44ee753a
@ -210,25 +210,67 @@ var AppJS = (function(){ "use strict"; return Class.extend(
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push method receives push notification about updates to entries from the application
|
* Handle a push notification about entry changes from the websocket
|
||||||
*
|
*
|
||||||
* It can use the extra _data parameter to determine if the client has read access to
|
* Get's called for data of all apps, but should only handle data of apps it displays,
|
||||||
* the entry - if an update of the list is necessary.
|
* which is by default only it's own, but can be for multiple apps eg. for calendar.
|
||||||
*
|
*
|
||||||
* @param {string} _type either 'update', 'edit', 'delete', 'add' or null
|
* @param pushData
|
||||||
|
* @param {string} pushData.app application name
|
||||||
|
* @param {(string|number)} pushData.id id of entry to refresh or null
|
||||||
|
* @param {string} pushData.type either 'update', 'edit', 'delete', 'add' or null
|
||||||
* - update: request just modified data from given rows. Sorting is not considered,
|
* - update: request just modified data from given rows. Sorting is not considered,
|
||||||
* so if the sort field is changed, the row will not be moved.
|
* so if the sort field is changed, the row will not be moved.
|
||||||
* - edit: rows changed, but sorting may be affected. Requires full reload.
|
* - edit: rows changed, but sorting may be affected. Requires full reload.
|
||||||
* - delete: just delete the given rows clientside (no server interaction neccessary)
|
* - delete: just delete the given rows clientside (no server interaction neccessary)
|
||||||
* - add: requires full reload for proper sorting
|
* - add: requires full reload for proper sorting
|
||||||
* @param {string} _app application name
|
* @param {object|null} pushData.acl Extra data for determining relevance. eg: owner or responsible to decide if update is necessary
|
||||||
* @param {(string|number)} _id id of entry to refresh or null
|
* @param {number} pushData.account_id User that caused the notification
|
||||||
* @param {mixed} _data eg. owner or responsible to decide if update is necessary
|
|
||||||
* @returns {undefined}
|
|
||||||
*/
|
*/
|
||||||
push: function(_type, _app, _id, _data)
|
push: function(pushData)
|
||||||
{
|
{
|
||||||
|
// don't care about other apps data, reimplement if your app does care eg. calendar
|
||||||
|
if (pushData.app !== this.appname) return;
|
||||||
|
|
||||||
|
// only handle delete by default, for simple case of uid === "$app::$id"
|
||||||
|
if (pushData.type === 'delete')
|
||||||
|
{
|
||||||
|
egw.dataStoreUID(this.uid(pushData), null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get (possible) app-specific uid
|
||||||
|
*
|
||||||
|
* @param {object} pushData see push method for individual attributes
|
||||||
|
*/
|
||||||
|
uid(pushData)
|
||||||
|
{
|
||||||
|
return pushData.app + '::' + pushData.id;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method called after apps push implementation checked visibility
|
||||||
|
*
|
||||||
|
* @param {et2_nextmatch} nm
|
||||||
|
* @param pushData see push method for individual attributes
|
||||||
|
* @todo implement better way to update nextmatch widget without disturbing the user / state
|
||||||
|
* @todo show indicator that an update has happend
|
||||||
|
* @todo rate-limit update frequency
|
||||||
|
*/
|
||||||
|
updateList: function(nm, pushData)
|
||||||
|
{
|
||||||
|
switch (pushData.type)
|
||||||
|
{
|
||||||
|
case 'add':
|
||||||
|
case 'unknown':
|
||||||
|
nm.applyFilters();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
egw.dataRefreshUID(this.uid(pushData));
|
||||||
|
break;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,6 +14,7 @@ namespace EGroupware\Api\Mail\Imap;
|
|||||||
|
|
||||||
use EGroupware\Api;
|
use EGroupware\Api;
|
||||||
use EGroupware\Api\Mail;
|
use EGroupware\Api\Mail;
|
||||||
|
use EGroupware\SwoolePush\Tokens;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages connection to Dovecot IMAP server
|
* Manages connection to Dovecot IMAP server
|
||||||
@ -24,7 +25,7 @@ use EGroupware\Api\Mail;
|
|||||||
* --> require by webserver writable user_home to be configured, otherwise deleting get ignored like with defaultimap
|
* --> require by webserver writable user_home to be configured, otherwise deleting get ignored like with defaultimap
|
||||||
* - quota can be read, but not set
|
* - quota can be read, but not set
|
||||||
*/
|
*/
|
||||||
class Dovecot extends Mail\Imap
|
class Dovecot extends Mail\Imap implements Mail\Imap\PushIface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Label shown in EMailAdmin
|
* Label shown in EMailAdmin
|
||||||
@ -281,4 +282,49 @@ class Dovecot extends Mail\Imap
|
|||||||
// mailbox get's automatic created with full rights for user
|
// mailbox get's automatic created with full rights for user
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Metadata name to enable push notifications
|
||||||
|
*/
|
||||||
|
const METADATA_NAME = '/private/vendor/vendor.dovecot/http-notify';
|
||||||
|
const METADATA_MAILBOX = '';
|
||||||
|
const METADATA_PREFIX = 'user=';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable push notifictions for current connection and given account_id
|
||||||
|
*
|
||||||
|
* @param int $account_id =null 0=everyone on the instance
|
||||||
|
* @return bool true on success, false on failure
|
||||||
|
*/
|
||||||
|
function enablePush($account_id=null)
|
||||||
|
{
|
||||||
|
if (!class_exists(Tokens::class))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$this->setMetadata(self::METADATA_MAILBOX, [
|
||||||
|
self::METADATA_NAME => self::METADATA_PREFIX.$GLOBALS['egw_info']['user']['account_id'].'::'.$this->acc_id.';'.
|
||||||
|
$this->getMailBoxUserName($GLOBALS['egw_info']['user']['account_lid']) . ';' .
|
||||||
|
((string)$account_id === '0' ? Tokens::instance() : Tokens::user($account_id)) . '@' .
|
||||||
|
Api\Header\Http::host(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
catch (Horde_Imap_Client_Exception $e) {
|
||||||
|
_egw_log_exception($e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if push is available / konfigured for given server
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function pushAvailable()
|
||||||
|
{
|
||||||
|
return in_array($this->acc_imap_host, ['imap.egroupware.org', 'mail.egroupware.org']) ||
|
||||||
|
$this->acc_imap_host === 'mail' && $this->acc_imap_port == 10143;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
* @link http://www.stylite.de
|
* @link http://www.stylite.de
|
||||||
* @package api
|
* @package api
|
||||||
* @subpackage mail
|
* @subpackage mail
|
||||||
* @author Ralf Becker <rb@stylite.de>
|
* @author Ralf Becker <rb@egroupware.org>
|
||||||
* @author Stylite AG <info@stylite.de>
|
* @author EGroupware GmbH <info@egroupware.org>
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
* @version $Id$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace EGroupware\Api\Mail\Imap;
|
namespace EGroupware\Api\Mail\Imap;
|
||||||
|
38
api/src/Mail/Imap/PushIface.php
Normal file
38
api/src/Mail/Imap/PushIface.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* EGroupware Api: Push Interface for IMAP
|
||||||
|
*
|
||||||
|
* @link http://www.stylite.de
|
||||||
|
* @package api
|
||||||
|
* @subpackage mail
|
||||||
|
* @author Ralf Becker <rb@egroupware.org>
|
||||||
|
* @author EGroupware GmbH <info@egroupware.org>
|
||||||
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace EGroupware\Api\Mail\Imap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class holds all information about the imap connection.
|
||||||
|
* This is the base class for all other imap classes.
|
||||||
|
*
|
||||||
|
* Also proxies Sieve calls to Mail\Sieve (eg. it behaves like the former felamimail bosieve),
|
||||||
|
* to allow IMAP plugins to also manage Sieve connection.
|
||||||
|
*/
|
||||||
|
interface PushIface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Check if push is available / konfigured for given server
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function pushAvailable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable push notifictions for current connection and given account_id
|
||||||
|
*
|
||||||
|
* @param int $account_id =null 0=everyone on the instance
|
||||||
|
* @return bool true on success, false on failure
|
||||||
|
*/
|
||||||
|
function enablePush($account_id=null);
|
||||||
|
}
|
@ -248,7 +248,16 @@ class mail_ui
|
|||||||
|
|
||||||
// save session varchar
|
// save session varchar
|
||||||
$oldicServerID =& Api\Cache::getSession('mail','activeProfileID');
|
$oldicServerID =& Api\Cache::getSession('mail','activeProfileID');
|
||||||
if ($oldicServerID <> self::$icServerID) $this->mail_bo->openConnection(self::$icServerID);
|
if ($oldicServerID != self::$icServerID)
|
||||||
|
{
|
||||||
|
$this->mail_bo->openConnection(self::$icServerID);
|
||||||
|
// enable push notifications, if supported (and konfigured) by the server
|
||||||
|
if ($this->mail_bo->icServer instanceof Api\Mail\Imap\PushIface &&
|
||||||
|
$this->mail_bo->icServer->pushAvailable())
|
||||||
|
{
|
||||||
|
$this->mail_bo->icServer->enablePush();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (true) $oldicServerID = self::$icServerID;
|
if (true) $oldicServerID = self::$icServerID;
|
||||||
if (!Mail::storeActiveProfileIDToPref($this->mail_bo->icServer, self::$icServerID, true ))
|
if (!Mail::storeActiveProfileIDToPref($this->mail_bo->icServer, self::$icServerID, true ))
|
||||||
{
|
{
|
||||||
|
@ -5,10 +5,9 @@
|
|||||||
*
|
*
|
||||||
* @link http://www.egroupware.org
|
* @link http://www.egroupware.org
|
||||||
* @author EGroupware GmbH [info@egroupware.org]
|
* @author EGroupware GmbH [info@egroupware.org]
|
||||||
* @copyright (c) 2013-2014 by EGroupware GmbH <info-AT-egroupware.org>
|
* @copyright (c) 2013-2020 by EGroupware GmbH <info-AT-egroupware.org>
|
||||||
* @package mail
|
* @package mail
|
||||||
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
||||||
* @version $Id$
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*egw:uses
|
/*egw:uses
|
||||||
@ -367,6 +366,54 @@ app.classes.mail = AppJS.extend(
|
|||||||
this.preSetToggledOnActions ();
|
this.preSetToggledOnActions ();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a push notification about entry changes from the websocket
|
||||||
|
*
|
||||||
|
* Get's called for data of all apps, but should only handle data of apps it displays,
|
||||||
|
* which is by default only it's own, but can be for multiple apps eg. for calendar.
|
||||||
|
*
|
||||||
|
* @param pushData
|
||||||
|
* @param {string} pushData.app application name
|
||||||
|
* @param {(string|number)} pushData.id id of entry to refresh or null
|
||||||
|
* @param {string} pushData.type either 'update', 'edit', 'delete', 'add' or null
|
||||||
|
* - update: request just modified data from given rows. Sorting is not considered,
|
||||||
|
* so if the sort field is changed, the row will not be moved.
|
||||||
|
* - edit: rows changed, but sorting may be affected. Requires full reload.
|
||||||
|
* - delete: just delete the given rows clientside (no server interaction neccessary)
|
||||||
|
* - add: requires full reload for proper sorting
|
||||||
|
* @param {object|null} pushData.acl Extra data for determining relevance. eg: owner or responsible to decide if update is necessary
|
||||||
|
* @param {number} pushData.account_id User that caused the notification
|
||||||
|
*/
|
||||||
|
push: function(pushData)
|
||||||
|
{
|
||||||
|
// don't care about other apps data, reimplement if your app does care eg. calendar
|
||||||
|
if (pushData.app !== this.appname) return;
|
||||||
|
|
||||||
|
// only handle delete by default, for simple case of uid === "$app::$id"
|
||||||
|
if (pushData.type === 'delete')
|
||||||
|
{
|
||||||
|
return this._super.call(this, pushData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify user a new mail arrived
|
||||||
|
if (pushData.type === 'add')
|
||||||
|
{
|
||||||
|
this.egw.message(this.egw.lang('New mail from %1', pushData.acl.from)+'\n'+pushData.acl.subject+'\n'+pushData.acl.snippet, 'success');
|
||||||
|
}
|
||||||
|
// check if we might not see it because we are on a different mail account or folder
|
||||||
|
let nm = this.et2 ? this.et2.getWidgetById('nm') : null;
|
||||||
|
let nm_value = nm ? nm.getValue() : null;
|
||||||
|
if (nm_value && nm_value.col_filter)
|
||||||
|
{
|
||||||
|
this.updateList(nm, pushData);
|
||||||
|
}
|
||||||
|
// update unseen counter in folder-tree
|
||||||
|
if (pushData.type === 'add' && pushData.acl.folder && pushData.acl.unseen)
|
||||||
|
{
|
||||||
|
// todo: pushData.id contains acc_id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Observer method receives update notifications from all applications
|
* Observer method receives update notifications from all applications
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user