From ecaa6e3a35e8b4b15141a47dd15da5d48b5fd7c4 Mon Sep 17 00:00:00 2001 From: Jelle van der Waa Date: Wed, 11 May 2016 10:40:44 +0200 Subject: [PATCH] initial commit --- build.xml | 198 +++++++++++++++++++++++++++ config.php | 5 + js/ABOUT.js | 0 js/MDM.js | 50 +++++++ js/data/JsonDeviceReader.js | 32 +++++ js/data/MDMDeviceRecord.js | 33 +++++ js/data/MDMDeviceStore.js | 33 +++++ js/data/MDMRecord.js | 0 js/data/MDMResponseHandler.js | 74 +++++++++++ js/data/ProvisioningStatus.js | 67 ++++++++++ js/settings/MDMSettingsCategory.js | 35 +++++ js/settings/MDMSettingsWidget.js | 198 +++++++++++++++++++++++++++ js/ui/Renderers.js | 23 ++++ manifest.xml | 41 ++++++ php/class.pluginmdmmodule.php | 207 +++++++++++++++++++++++++++++ php/plugin.mdm.php | 48 +++++++ resources/css/mdm.css | 3 + resources/icons/mdm_icon.png | Bin 0 -> 262 bytes resources/icons/mdm_icon.xcf | Bin 0 -> 4649 bytes 19 files changed, 1047 insertions(+) create mode 100755 build.xml create mode 100755 config.php create mode 100755 js/ABOUT.js create mode 100755 js/MDM.js create mode 100644 js/data/JsonDeviceReader.js create mode 100644 js/data/MDMDeviceRecord.js create mode 100644 js/data/MDMDeviceStore.js create mode 100644 js/data/MDMRecord.js create mode 100644 js/data/MDMResponseHandler.js create mode 100644 js/data/ProvisioningStatus.js create mode 100755 js/settings/MDMSettingsCategory.js create mode 100644 js/settings/MDMSettingsWidget.js create mode 100644 js/ui/Renderers.js create mode 100755 manifest.xml create mode 100755 php/class.pluginmdmmodule.php create mode 100755 php/plugin.mdm.php create mode 100755 resources/css/mdm.css create mode 100755 resources/icons/mdm_icon.png create mode 100755 resources/icons/mdm_icon.xcf diff --git a/build.xml b/build.xml new file mode 100755 index 0000000..4a33950 --- /dev/null +++ b/build.xml @@ -0,0 +1,198 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + var Ext = {}; + var Zarafa = {}; + var container = {}; + var _ = function(key, domain) {}; + var dgettext = function(domain, msgid) {}; + var dngettext = function(domain, msgid, msgid_plural, count) {}; + var dnpgettext = function(domain, msgctxt, msgid, msgid_plural, count) {}; + var dpgettext = function(domain, msgctxt, msgid) {}; + var ngettext = function(msgid, msgid_plural, count) {}; + var npgettext = function(msgctxt, msgid, msgid_plural, count) {}; + var pgettext = function(msgctxt, msgid) {}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config.php b/config.php new file mode 100755 index 0000000..307b465 --- /dev/null +++ b/config.php @@ -0,0 +1,5 @@ + diff --git a/js/ABOUT.js b/js/ABOUT.js new file mode 100755 index 0000000..e69de29 diff --git a/js/MDM.js b/js/MDM.js new file mode 100755 index 0000000..123e226 --- /dev/null +++ b/js/MDM.js @@ -0,0 +1,50 @@ +Ext.namespace('Zarafa.plugins.mdm'); + +/** + * @class Zarafa.plugins.mdm.MDM + * @extends Zarafa.core.Plugin + * + * Plugin which lists all devices connected to a Kopano account with Z-Push. + * The user can wipe, resync, remove a device using buttons in the WebApp. + */ +Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, { + /** + * Constructor + * @param {Object} config + * @protected + */ + constructor : function(config) { + config = config || {}; + Zarafa.plugins.mdm.MDM.superclass.constructor.call(this, config); + }, + + /** + * Called after constructor. + * Registers insertion points. + * @protected + */ + initPlugin : function() + { + this.registerInsertionPoint('context.settings.categories', this.createSettingCategory, this); + Zarafa.plugins.mdm.MDM.superclass.initPlugin.apply(this, arguments); + }, + + /** + * Creates a category in settings for Z-Push + * @return {mdmsettingscategory} + */ + createSettingCategory: function() { + return [{ + xtype : 'Zarafa.plugins.mdm.mdmsettingscategory' + }]; + } + +}); + +Zarafa.onReady(function() { + container.registerPlugin(new Zarafa.core.PluginMetaData({ + name : 'mdm', + displayName : _('Mobile device management'), + pluginConstructor : Zarafa.plugins.mdm.MDM + })); +}); diff --git a/js/data/JsonDeviceReader.js b/js/data/JsonDeviceReader.js new file mode 100644 index 0000000..6f2b2c6 --- /dev/null +++ b/js/data/JsonDeviceReader.js @@ -0,0 +1,32 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.JsonCertificateReader + * @extends Zarafa.core.data.JsonReader + */ +Zarafa.plugins.mdm.data.JsonCertificateReader = Ext.extend(Zarafa.core.data.JsonReader, { + /** + * @cfg {Zarafa.core.data.RecordCustomObjectType} customObjectType The custom object type + * which represents the {@link Ext.data.Record records} which should be created using + * {@link Zarafa.core.data.RecordFactory#createRecordObjectByCustomType}. + */ + customObjectType : Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, + + /** + * @constructor + * @param {Object} meta Metadata configuration options. + * @param {Object} recordType (optional) Optional Record type matches the type + * which must be read from response. If no type is given, it will use the + * record type for the {@link Zarafa.core.data.RecordCustomObjectType#ZARAFA_MDM}. + */ + constructor : function(meta, recordType) + { + meta = Ext.applyIf(meta || {}, { + dynamicRecord : false + }); + + recordType = Zarafa.core.data.RecordFactory.getRecordClassByCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM); + + Zarafa.plugins.mdm.data.JsonCertificateReader.superclass.constructor.call(this, meta, recordType); + } +}); diff --git a/js/data/MDMDeviceRecord.js b/js/data/MDMDeviceRecord.js new file mode 100644 index 0000000..b017348 --- /dev/null +++ b/js/data/MDMDeviceRecord.js @@ -0,0 +1,33 @@ +Ext.namespace('Zarafa.plugins.mdm'); + +Zarafa.plugins.mdm.data.MDMDeviceRecordFields = [ + {name: 'entryid', type: 'string'}, + {name: 'changed', type: 'boolean'}, + {name: 'deviceos', type: 'string'}, + {name: 'devicefriendlyname', type: 'string'}, + {name: 'deviceinfo', type: 'string'}, + {name: 'devicetype', type: 'string'}, + {name: 'devicemodel', type: 'string'}, + {name: 'domain', type: 'string'}, + {name: 'hierarchyuuid', type: 'string'}, + // ignoredmessages + {name: 'firstsynctime', type: 'date', dateFormat: 'timestamp'}, + {name: 'lastupdatetime', type: 'date', dateFormat: 'timestamp'}, + {name: 'wipestatus', type: 'string'}, + {name: 'useragent', type: 'string'} +]; + +/** + * + */ +Zarafa.plugins.mdm.data.MDMDeviceRecord = Ext.extend(Zarafa.core.data.IPMRecord, {}); +Zarafa.core.data.RecordCustomObjectType.addProperty('ZARAFA_MDM'); +Zarafa.core.data.RecordFactory.addFieldToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, Zarafa.plugins.mdm.data.MDMDeviceRecordFields); + +Zarafa.core.data.RecordFactory.addListenerToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, 'createphantom', function(record) +{ + // Phantom records must always be marked as opened (they contain the full set of data) + record.afterOpen(); +}); + +Zarafa.core.data.RecordFactory.setBaseClassToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, Zarafa.plugins.mdm.data.MDMDeviceRecord); diff --git a/js/data/MDMDeviceStore.js b/js/data/MDMDeviceStore.js new file mode 100644 index 0000000..a9f7ea1 --- /dev/null +++ b/js/data/MDMDeviceStore.js @@ -0,0 +1,33 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.MDMDeviceStore + * @extends Zarafa.core.data.ListModuleStore + * @xtype mdm.devicestore + * Store specific for MDM Plugin which creates {@link Zarafa.plugins.mdm.MDMDeviceRecord record}. + */ +Zarafa.plugins.mdm.data.MDMDeviceStore = Ext.extend(Zarafa.core.data.ListModuleStore, { + /** + * @constructor + * @param config Configuration object + */ + constructor : function(config) + { + config = config || {}; + + Ext.applyIf(config, { + autoLoad : true, + remoteSort: false, + reader : new Zarafa.plugins.mdm.data.JsonCertificateReader(), + writer : new Zarafa.core.data.JsonWriter(), + proxy : new Zarafa.core.data.IPMProxy({ + listModuleName: 'pluginmdmmodule', + itemModuleName: 'pluginmdmmodule' + }) + }); + + Zarafa.plugins.mdm.data.MDMDeviceStore.superclass.constructor.call(this, config); + } +}); + +Ext.reg('mdm.devicestore', Zarafa.plugins.mdm.data.MDMDeviceStore); diff --git a/js/data/MDMRecord.js b/js/data/MDMRecord.js new file mode 100644 index 0000000..e69de29 diff --git a/js/data/MDMResponseHandler.js b/js/data/MDMResponseHandler.js new file mode 100644 index 0000000..31ad6ed --- /dev/null +++ b/js/data/MDMResponseHandler.js @@ -0,0 +1,74 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.MDMResponseHandler + * @extends Zarafa.core.data.AbstractResponseHandler + * + * MDM specific response handler. + */ +Zarafa.plugins.mdm.data.MDMResponseHandler = Ext.extend(Zarafa.core.data.AbstractResponseHandler, { + + /** + * @cfg {Function} successCallback The function which + * will be called after success request. + */ + successCallback : Ext.emptyFn, + + /** + * @cfg {Function} failureCallback The function which + * will be called after a failed request. + * This callback is optional and currently unused. + */ + failureCallback : Ext.emptyFn, + + /** + * Device information from Z-Push's soap call, + * @param {Object} response Object contained the response data. + */ + doInfo : function(response) { + this.successCallback(response); + /* + if(response.status != true && this.failureCallback != null) { + this.failureCallback(response); + } else { + this.successCallback(response); + }*/ + }, + + /** + * Call the successCallback callback function if device was successfully removed from + * z-push server. + * @param {Object} response Object contained the response data. + */ + doRemove : function(response) + { + if(response.remove){ + this.successCallback(); + } + }, + + /** + * If wipe request response was successful, show informative message. + * @param {Object} response Object contained the response data. + */ + doWipe : function(response) { + if (response.wipe === true) { + container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Wiping device')); + } else { + container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Password incorrect')); + } + }, + + /** + * If resync request response was successful, show informative message. + * @param {Object} response Object contained the response data. + */ + doResync : function(response) { + if (response.resync === true) { + container.getNotifier().notify('info.mdm', _('Mobile Device Manager'), _('Full resync in progress')); + } + } + +}); + +Ext.reg('mdm.responsehandler', Zarafa.plugins.mdm.data.MDMResponseHandler); diff --git a/js/data/ProvisioningStatus.js b/js/data/ProvisioningStatus.js new file mode 100644 index 0000000..41ae333 --- /dev/null +++ b/js/data/ProvisioningStatus.js @@ -0,0 +1,67 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.ProvisioningStatus + * @extends Zarafa.core.Enum + * + * @singleton + */ +Zarafa.plugins.mdm.data.ProvisioningStatus = Zarafa.core.Enum.create({ + /** + * Denotes that the wipe is not applicable. + * @property + * @type Number + */ + 'NOT_APPLICABLE' : 0, + + /** + * Denotes that the wipe is ok. + * @property + * @type Number + */ + 'OK' : 1, + + /** + * Denotes that the wipe is pending. + * @property + * @type Number + */ + 'WIPE_PENDING' : 2, + + /** + * Denotes that the Wipe is requested. + * @property + * @type Number + */ + 'WIPE_REQUESTED' : 4, + + /** + * Denotes that the Wipe is executed. + * @property + * @type Number + */ + 'WIPE_EXECUTED' : 8, + + /** + * Return the display name for the given provisioning Status + * @param {Zarafa.plugins.mdm.js.data.ProvisioningStatus} provisioningStatus The given provisioning status + * @return {String} The display name for the provisioning status + */ + getDisplayName : function(provisioningStatus) + { + switch (provisioningStatus) { + case Zarafa.plugins.mdm.data.ProvisioningStatus.NOT_APPLICABLE: + return _('Not Applicable'); + case Zarafa.plugins.mdm.data.ProvisioningStatus.OK: + return _('Ok'); + case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_PENDING: + return _('Wipe Pending'); + case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_REQUESTED: + return _('Wipe Requested'); + case Zarafa.plugins.mdm.data.ProvisioningStatus.WIPE_EXECUTED: + return _('Wipe Executed'); + } + return ''; + } +}); + diff --git a/js/settings/MDMSettingsCategory.js b/js/settings/MDMSettingsCategory.js new file mode 100755 index 0000000..0f21f83 --- /dev/null +++ b/js/settings/MDMSettingsCategory.js @@ -0,0 +1,35 @@ +Ext.namespace('Zarafa.plugins.mdm.settings'); + +/* + * Settings category entry for MDM + * @extends + */ + +/** + * @class Zarafa.plugins.mdm.settings.MDMSettingsCategory + * @extends Zarafa.settings.ui.SettingsCategory + * @xtype Zarafa.plugins.mdmsettingscategory + * + * The mdm settings category entry. + */ +Zarafa.plugins.mdm.settings.MDMSettingsCategory = Ext.extend(Zarafa.settings.ui.SettingsCategory, { + /** + * @constructor + * @param {Object} config Configuration object + */ + constructor : function(config) { + config = config || {}; + + Ext.applyIf(config, { + title : _('MDM'), + iconCls : 'icon_mdm_settings', + items : [{ + xtype : 'Zarafa.plugins.mdm.mdmsettingswidget' + }] + }); + + Zarafa.plugins.mdm.settings.MDMSettingsCategory.superclass.constructor.call(this, config); + } +}); + +Ext.reg('Zarafa.plugins.mdm.mdmsettingscategory', Zarafa.plugins.mdm.settings.MDMSettingsCategory); diff --git a/js/settings/MDMSettingsWidget.js b/js/settings/MDMSettingsWidget.js new file mode 100644 index 0000000..5168de6 --- /dev/null +++ b/js/settings/MDMSettingsWidget.js @@ -0,0 +1,198 @@ +Ext.namespace('Zarafa.plugins.mdm.settings'); + +/** + * @class Zarafa.plugins.mdm.settings.MDMSettingsWidget + * @extends Zarafa.settings.ui.SettingsWidget + */ +Zarafa.plugins.mdm.settings.MDMSettingsWidget = Ext.extend(Zarafa.settings.ui.SettingsWidget, { + + /** + * @constructor + * @param {Object} config Configuration object + */ + constructor : function(config) + { + config = config || {}; + + var store = new Zarafa.plugins.mdm.data.MDMDeviceStore(); + Ext.applyIf(config, { + title : _('Mobile Devices'), + items : [{ + xtype : 'container', + layout : 'column', + items : [{ + xtype : 'grid', + name : _('Devices'), + ref : '../deviceGrid', + height : 400, + store : store, + viewConfig : { + forceFit : true, + deferEmptyText: false, + emptyText: '
' + _('No devices connected to your account') + '
' + }, + columns : [{ + dataIndex : 'devicetype', + header : _('Device'), + renderer : Ext.util.Format.htmlEncode + },{ + dataIndex : 'useragent', + header : _('User Agent'), + renderer : Ext.util.Format.htmlEncode + },{ + dataIndex : 'wipestatus', + header : _('Provisioning Status'), + renderer : Zarafa.plugins.mdm.ui.Renderers.provisioningStatus + },{ + dataIndex : 'lastupdatetime', + header : _('Last Update'), + renderer : Ext.util.Format.htmlEncode + },{ + dataIndex : 'entryid', + header : _('Device ID'), + renderer : Ext.util.Format.htmlEncode + },{ + dataIndex : 'deviceos', + header : _('Device OS'), + hidden : true, + renderer : Ext.util.Format.htmlEncode + },{ + dataIndex : 'devicefriendlyname', + header : _('Device Info'), + hidden : true, + renderer : Ext.util.Format.htmlEncode + },{ + dataIndex : 'firstsynctime', + header : _('First Sync time'), + hidden : true, + renderer : Ext.util.Format.htmlEncode + }], + buttons : [{ + text : _('Wipe Device'), + ref : '../../../wipeBtn', + handler : this.onWipeBtn, + scope : this + },{ + text : _('Full resync'), + ref : '../../../resyncBtn', + handler : this.onFullResync, + scope : this + },{ + text : _('Remove device'), + ref : '../../../removeBtn', + handler : this.onRemoveDevice, + scope : this + },{ + text : _('Refresh'), + ref : '../../../refresh', + handler : this.onRefresh, + scope : this + }] + }] + }] + }); + Zarafa.plugins.mdm.settings.MDMSettingsWidget.superclass.constructor.call(this, config); + }, + + /** + * Function which handles the click event on the "Wipe Device" button, displays + * a MessageBox for the user to confirm the wipe action. The wipe action is + * handled by the onWipeDevice function. + */ + onWipeBtn : function() + { + var msgbox = Ext.MessageBox.show({ + title: _('Kopano WebApp'), + msg: _('Do you really want to wipe your device?\n Enter your password to confirm.'), + inputType :'password', + icon: Ext.MessageBox.WARNING, + buttons: Ext.MessageBox.YESNO, + fn: this.onWipeDevice, + prompt: true, + scope: this.deviceGrid + }); + + // ExtJS does not support a password field. + msgbox.getDialog().body.child('input').dom.type = 'password'; + }, + + /** + * Function which handles the confirmation button in the "wipe device" messagebox. + * Sends an wipe request to PHP for the selected device in the grid. + * + * @param {Ext.Button} button button from the messagebox + * @param {String} password user password + */ + onWipeDevice : function(button, password) + { + if (button === 'yes') { + var selectionModel = this.getSelectionModel(); + var record = selectionModel.getSelected(); + if (record) { + container.getRequest().singleRequest( + 'pluginmdmmodule', + 'wipe', + { 'deviceid' : record.get('entryid'), 'password': password }, + new Zarafa.plugins.mdm.data.MDMResponseHandler() + ); + } + } + }, + + /** + * Function which handles the click event on the "Full resync" button, sends a + * full resync request to PHP. + */ + onFullResync : function() + { + var selectionModel = this.deviceGrid.getSelectionModel(); + var record = selectionModel.getSelected(); + if(record) { + container.getRequest().singleRequest( + 'pluginmdmmodule', + 'resync', + { 'deviceid' : record.get('entryid') }, + new Zarafa.plugins.mdm.data.MDMResponseHandler() + ); + } + }, + + /** + * Remove all state data for a device, essentially resyncing it. + */ + onRemoveDevice : function() + { + var selectionModel = this.deviceGrid.getSelectionModel(); + var record = selectionModel.getSelected(); + if(record) { + container.getRequest().singleRequest( + 'pluginmdmmodule', + 'remove', + { 'deviceid' : record.get('entryid') }, + new Zarafa.plugins.mdm.data.MDMResponseHandler({ + successCallback : this.removeDone.createDelegate(this, [record], true) + }) + ); + } + }, + + /** + * Callback function triggers when device was successfully removed from the z-push server. + * we have to remove that device from {@link Zarafa.plugins.mdm.data.MDMDeviceStore store}. + * @param {Zarafa.plugins.mdm.data.MDMDeviceRecord} record {@link Zarafa.core.data.IPMRecord record} object + */ + removeDone : function(record) + { + record.getStore().remove(record); + }, + + /** + * Function which refreshes the store records from the server. + */ + onRefresh : function() + { + this.deviceGrid.getStore().load(); + } +}); + +Ext.reg('Zarafa.plugins.mdm.mdmsettingswidget', Zarafa.plugins.mdm.settings.MDMSettingsWidget); diff --git a/js/ui/Renderers.js b/js/ui/Renderers.js new file mode 100644 index 0000000..2b6b946 --- /dev/null +++ b/js/ui/Renderers.js @@ -0,0 +1,23 @@ +Ext.namespace('Zarafa.plugins.mdm.ui'); + +/** + * @class Zarafa.plugins.mdm.ui.Renderers + * Methods of this object can be used as renderers for grid panels, to render + * cells in custom format according to data type + * @singleton + */ +Zarafa.plugins.mdm.ui.Renderers = { + + /** + * Render the Provisioning Status. + * + * @param {Object} value The data value for the cell. + * @param {Object} p An object with metadata + * @param {Ext.data.record} record The {Ext.data.Record} from which the data was extracted. + * @return {String} The formatted string + */ + provisioningStatus : function(value, p, record) + { + return Zarafa.plugins.mdm.data.ProvisioningStatus.getDisplayName(parseInt(value)); + } +} \ No newline at end of file diff --git a/manifest.xml b/manifest.xml new file mode 100755 index 0000000..e579906 --- /dev/null +++ b/manifest.xml @@ -0,0 +1,41 @@ + + + + + 0.1 + mdm + Mobile Device Management + Kopano + http://www.kopano.com + Mobile Device Management plugin + + + config.php + + + + + + php/plugin.mdm.php + php/class.pluginmdmmodule.php + + + js/mdm.js + js/mdm-debug.js + js/MDM.js + js/data/MDMResponseHandler.js + js/data/MDMDeviceRecord.js + js/data/JsonDeviceReader.js + js/data/MDMDeviceStore.js + js/data/ProvisioningStatus.js + js/settings/MDMSettingsWidget.js + js/settings/MDMSettingsCategory.js + js/ui/Renderers.js + + + resources/css/mdm.css + + + + + diff --git a/php/class.pluginmdmmodule.php b/php/class.pluginmdmmodule.php new file mode 100755 index 0000000..c79b4b4 --- /dev/null +++ b/php/class.pluginmdmmodule.php @@ -0,0 +1,207 @@ +server = (PLUGIN_MDM_SERVER_SSL ? 'https://' : 'http://') . PLUGIN_MDM_SERVER; + + // For backward compatibility we will check if the Encryption store exists. If not, + // we will fall back to the old way of retrieving the password from the session. + if ( class_exists('EncryptionStore') ) { + + // Get the username and password from the Encryption store + $encryptionStore = EncryptionStore::getInstance(); + $this->username = $encryptionStore->get('username'); + $this->password = $encryptionStore->get('password'); + } else { + $this->username = $GLOBALS['mapisession']->getUserName(); + + $this->password = $_SESSION['password']; + if(function_exists('openssl_decrypt')) { + // In PHP 5.3.3 the iv parameter was added + if(version_compare(phpversion(), "5.3.3", "<")) { + $this->password = openssl_decrypt($this->password, "des-ede3-cbc", PASSWORD_KEY, 0); + } else { + $this->password = openssl_decrypt($this->password, "des-ede3-cbc", PASSWORD_KEY, 0, PASSWORD_IV); + } + } + } + + $this->url = $this->server .'/Microsoft-Server-ActiveSync?Cmd=WebserviceDevice&DeviceId=webservice&DeviceType=webservice&User=' . $this->username; + } + + /** + * Helper to setup a client. + */ + function getSoapClient() + { + return new SoapClient(null, array( + 'location' => $this->url, + 'uri' => $this->server, + 'trace' => 1, + 'login' => $this->username, + 'password' => $this->password + )); + } + + /** + * Function which calls the soap call to do a full resync + * @param int $deviceid of phone which has to be resynced + * @return json $response object contains the response of the soap request from Z-Push + */ + function resyncDevice($deviceid) + { + $client = $this->getSoapClient(); + return $client->ResyncDevice($deviceid); + } + + /** + * Function which calls the wipeDevice soap call + * @param int $deviceid of phone which has to be wiped + * @param string $password user password + * @return json $response object contains the response of the soap request from Z-Push + */ + function wipeDevice($deviceid, $password) + { + if ($password == $this->password) { + $client = $this->getSoapClient(); + return $client->WipeDevice($deviceid); + } else { + return false; + } + } + + /** + * function which calls the ListDeviceDetails soap call + * @return array $response array contains a list of devices connected to the users account + */ + function getDevices() + { + $client = $this->getSoapClient(); + return $client->ListDevicesDetails(); + } + + + /** + function which calls the wipeDevice soap call + * @param int $deviceid of phone which has to be wiped + * @return json $response object contains the response of the soap request from Z-Push + */ + function removeDevice($deviceid) + { + $client = $this->getSoapClient(); + return $client->RemoveDevice($deviceid); + } + + /** + * Executes all the actions in the $data variable. + * @return boolean true on success of false on fialure. + */ + function execute() + { + foreach($this->data as $actionType => $actionData) + { + if(isset($actionType)) { + try { + switch($actionType) + { + case 'wipe': + $this->wipeDevice($actionData['deviceid'], $actionData['password']); + $this->addActionData('wipe', array( + 'type' => 3, + 'wipe' => $this->wipeDevice($actionData['deviceid'], $actionData['password']) + )); + $GLOBALS['bus']->addData($this->getResponseData()); + break; + case 'resync': + $this->addActionData('resync', array( + 'type' => 3, + 'resync' => $this->resyncDevice($actionData['deviceid']) + )); + $GLOBALS['bus']->addData($this->getResponseData()); + break; + case 'remove': + $this->addActionData('remove', array( + 'type' => 3, + 'remove' => $this->removeDevice($actionData['deviceid']) + )); + $GLOBALS['bus']->addData($this->getResponseData()); + break; + case 'list': + $items = array(); + $date['page'] = array(); + + $rawData = $this->getDevices(); + foreach($rawData as $device){ + $device = $device->data; + $item = array(); + $item['entryid'] = $device['deviceid']; + $item['changed'] = $device['changed']; + $item['deviceos'] = $device['deviceos']; + $item['devicefriendlyname'] = $device['devicefriendlyname']; + $item['devicetype'] = $device['devicetype']; + $item['devicemodel'] = $device['devicemodel']; + $item['hierarchyuuid'] = $device['hierarchyuuid']; + $item['firstsynctime'] = $device['firstsynctime']; + $item['lastupdatetime'] = $device['lastupdatetime']; + $item['wipestatus'] = $device['wipestatus']; + $item['useragent'] = $device['useragent']; + $item['domain'] = $device['domain']; + array_push($items, array('props' => $item)); + } + $data['page']['start'] = 0; + $data['page']['rowcount'] = count($rawData); + $data['page']['totalrowcount'] = $data['page']['rowcount']; + $data = array_merge($data, array('item' => $items)); + + $this->addActionData('list', $data); + $GLOBALS['bus']->addData($this->getResponseData()); + break; + default: + $this->handleUnknownActionType($actionType); + } + } catch (SoapFault $fault) { + $display_message = _('Something went wrong.'); + if ($fault->faultcode === 'HTTP') { + if ($fault->getMessage() === "Unauthorized") { + $display_message = _('Unable to connect to Z-Push Server. Unauthorized.'); + } + if ($fault->getMessage() === "Could not connect to host") { + $display_message = _('Unable to connect to Z-Push Server. Could not connect to host.'); + } + if ($fault->getMessage() === "Not Found") { + $display_message = _('Unable to connect to Z-Push Server. Not found.'); + } + } else if ($fault->faultcode === "ERROR") { + $display_message = _('Device ID could not be found'); + } + $this->sendFeedback(false, array("type" => ERROR_GENERAL, "info" => array('display_message' => $display_message))); + } + catch (Exception $e) { + $this->sendFeedback(true, array("type" => ERROR_GENERAL, "info" => array('display_message' => _('Something went wrong')))); + } + } + } + } +}; +?> diff --git a/php/plugin.mdm.php b/php/plugin.mdm.php new file mode 100755 index 0000000..bc2e043 --- /dev/null +++ b/php/plugin.mdm.php @@ -0,0 +1,48 @@ +registerHook('server.core.settings.init.before'); + } + + /** + * Function is executed when a hook is triggered by the PluginManager + * @param String $eventID Identifier of the hook + * @param Array $data Reference to the data of the triggered hook + */ + function execute($eventID, &$data){ + switch($eventID){ + case 'server.core.settings.init.before': + $this->onBeforeSettingsInit($data); + break; + } + } + + /** + * Called when the core Settings class is initialized and ready to accept sysadmin default + * settings. Registers the sysadmin defaults for the StatsLogging plugin. + * @param Array $data Reference to the data of the triggered hook + */ + function onBeforeSettingsInit(&$data){ + $data['settingsObj']->addSysAdminDefaults(Array( + 'zarafa' => Array( + 'v1' => Array( + 'plugins' => Array( + 'mdm' => Array( + 'enable' => PLUGIN_MDM_USER_DEFAULT_ENABLE_MDM, + ) + ) + ) + ) + )); + } +} +?> diff --git a/resources/css/mdm.css b/resources/css/mdm.css new file mode 100755 index 0000000..352ac96 --- /dev/null +++ b/resources/css/mdm.css @@ -0,0 +1,3 @@ +.icon_mdm_settings { + background-image:url(../icons/mdm_icon.png) !important; +} \ No newline at end of file diff --git a/resources/icons/mdm_icon.png b/resources/icons/mdm_icon.png new file mode 100755 index 0000000000000000000000000000000000000000..7af0f8c0d031d83ede284ddcbd25c8043b1bc000 GIT binary patch literal 262 zcmV+h0r~!kP)K&8E#BhXs;(^b M07*qoM6N<$g5QR0S^xk5 literal 0 HcmV?d00001 diff --git a/resources/icons/mdm_icon.xcf b/resources/icons/mdm_icon.xcf new file mode 100755 index 0000000000000000000000000000000000000000..70b1edc0ee29733fe7f6a91eaaceca051259fa13 GIT binary patch literal 4649 zcmeHKU1(cn7=BNZHfhqjs_oXa9m%@3rW=`SPyg1RW0lPd@xp-v3o_faO&09m+77#m zk&1PWO+f@%g${aCoUjW~gds&x6v}2D9SC(Q-pm_yKMV^s$@jfJZ~oTJidRJ~{ou*- zyw7*Olaq7K_r7n!k%3|Vcu&Y5iuCsp#zYzh_+h{h@hISW>TMzcMiJluY{1sEmg9xXE_y4_+rQ@T+-93@Pu)j9*T`*6qWv0F0@xjQLKQh>Jv~N__ z4~0UbePh`Rl+}N=QqKKL4H^y3$&a!Gn^2a^{XFvdfwKN7876rUIyC>M2~ET zmNAinZHy@A04}qO$POvZjbcXU^kRY= z*&yYc;}%Yk?+&-JGUm9N)!DXYN3%Ng4ZB%)!qA_QlXRnm(-M9y;eH7h`7u@>_jWnD z)X5uSBsfZESpT?GyOhW3(;(GR9_t{PcOlD^G&;ZIX7 zC0vL9V5ex4^lVlg%Btr!oT?gkj_W5VYV4wTLC5j)Gc_~u>0@nfq<+8S1+0x`|O0>Uqi(RQXB&Gedll1c$!^!F= z1CDb1iieb3k0&`#Riu~x-^PEjm`VEapx8!@pk+fE$VsOPr`co)a?O267j06Xx5!6( zvRd2Vo7N~3JR-=d68;RcHecO?7CUqoSmtiiPA-mEngUabAg*#EmWfEO&BjL zZeVrShs~y6heV#k4$4`l#0@7awUGIxv1@&xN6Rj pE7-j(?cg0Bij1oMifiHf@XtSH>zesip?bs;i_@KQ^%xy#(4Vy&i%kFk literal 0 HcmV?d00001