diff --git a/.idea/dictionaries/osboxes.xml b/.idea/dictionaries/osboxes.xml new file mode 100644 index 0000000..e813bfd --- /dev/null +++ b/.idea/dictionaries/osboxes.xml @@ -0,0 +1,7 @@ + + + + guids + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index db573e2..f3820b5 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,8 +2,7 @@ - - + @@ -23,12 +22,12 @@ - + - - + + @@ -37,74 +36,65 @@ - - + + - - + + - - + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -120,20 +110,22 @@ @@ -175,11 +167,6 @@ - - - - - @@ -212,46 +199,6 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + - + + + + + + @@ -403,12 +360,13 @@ 1480428196914 - + + - @@ -418,6 +376,7 @@ + @@ -428,7 +387,6 @@ - @@ -446,126 +404,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + @@ -574,6 +444,14 @@ + + + + + + + + @@ -593,14 +471,65 @@ - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -620,6 +549,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/data/Actions.js b/js/data/Actions.js new file mode 100644 index 0000000..170c823 --- /dev/null +++ b/js/data/Actions.js @@ -0,0 +1,227 @@ +/** + * Actions.js, Kopano Webapp contact to vcf im/exporter + * + * Author: Christoph Haas + * Copyright (C) 2012-2016 Christoph Haas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +Ext.namespace('Zarafa.plugins.contactimporter.data'); + +/** + * @class Zarafa.plugins.contactimporter.data.Actions + * Common actions which can be used within {@link Ext.Button buttons} + * or other {@link Ext.Component components} with action handlers. + * @singleton + */ +Zarafa.plugins.contactimporter.data.Actions = { + /** + * Generates a request to download the selected records as vCard. + * + * @param storeId + * @param recordIds + */ + exportToVCF: function (storeId, recordIds, recordFolder) { + if ((typeof recordIds != "undefined" && recordIds.length < 1) || (typeof recordFolder != "undefined" && recordFolder.get('content_count') < 1)) { + Zarafa.common.dialogs.MessageBox.show({ + title: dgettext('plugin_contactimporter', 'Error'), + msg: dgettext('plugin_contactimporter', 'No contacts found. Export skipped!'), + icon: Zarafa.common.dialogs.MessageBox.ERROR, + buttons: Zarafa.common.dialogs.MessageBox.OK + }); + } else { + + var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({ + successCallback: Zarafa.plugins.contactimporter.data.Actions.downloadVCF + }); + + var recordcount = 0; + var exportPayload = { + storeid: storeId, + records: undefined, + folder: undefined + }; + + if (typeof recordIds != "undefined") { + exportPayload.records = recordIds; + recordcount = recordIds.length; + } + + if (typeof recordFolder != "undefined") { + exportPayload.folder = recordFolder.get("entryid"); + recordcount = recordFolder.get('content_count'); + } + + // Notify user + // # TRANSLATORS: {0} will be replaced by the number of contacts that will be exported + container.getNotifier().notify('info', dgettext('plugin_contactimporter', 'Contact Export'), String.format(dgettext('plugin_contactimporter', 'Exporting {0} contacts. Please wait...'), recordcount)); + + + // request attachment preperation + container.getRequest().singleRequest( + 'contactmodule', + 'export', + exportPayload, + responseHandler + ); + } + }, + + /** + * Callback for the export request. + * @param {Object} response + */ + downloadVCF: function (response) { + if (response.status == false) { + Zarafa.common.dialogs.MessageBox.show({ + title: dgettext('plugin_contactimporter', 'Warning'), + msg: response.message, + icon: Zarafa.common.dialogs.MessageBox.WARNING, + buttons: Zarafa.common.dialogs.MessageBox.OK + }); + } else { + var downloadFrame = Ext.getBody().createChild({ + tag: 'iframe', + cls: 'x-hidden' + }); + + var url = document.URL; + var link = url.substring(0, url.lastIndexOf('/') + 1); + + link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_vcf"; + link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token)); + link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename)); + + downloadFrame.dom.contentWindow.location = link; + } + }, + + /** + * Get all contact folders. + * @param {boolean} asDropdownStore If true, a simple array store will be returned. + * @returns {*} + */ + getAllContactFolders: function (asDropdownStore) { + asDropdownStore = Ext.isEmpty(asDropdownStore) ? false : asDropdownStore; + + var allFolders = []; + + var defaultContactFolder = container.getHierarchyStore().getDefaultFolder('contact'); + + var inbox = container.getHierarchyStore().getDefaultStore(); + var pub = container.getHierarchyStore().getPublicStore(); + + if (!Ext.isEmpty(inbox.subStores) && inbox.subStores.folders.totalLength > 0) { + for (var i = 0; i < inbox.subStores.folders.totalLength; i++) { + var folder = inbox.subStores.folders.getAt(i); + if (!Ext.isEmpty(folder) && folder.get("container_class") == "IPF.Contact") { + if (asDropdownStore) { + allFolders.push([ + folder.get("entryid"), + folder.get("display_name") + ]); + } else { + allFolders.push({ + display_name: folder.get("display_name"), + entryid: folder.get("entryid"), + store_entryid: folder.get("store_entryid"), + is_public: false + }); + } + } + } + } + + if (!Ext.isEmpty(pub.subStores) && pub.subStores.folders.totalLength > 0) { + for (var j = 0; j < pub.subStores.folders.totalLength; j++) { + var folder = pub.subStores.folders.getAt(j); + if (!Ext.isEmpty(folder) && folder.get("container_class") == "IPF.Contact") { + if (asDropdownStore) { + allFolders.push([ + folder.get("entryid"), + folder.get("display_name") + " (Public)" + ]); + } else { + allFolders.push({ + display_name: folder.get("display_name"), + entryid: folder.get("entryid"), + store_entryid: folder.get("store_entryid"), + is_public: true + }); + } + } + } + } + + if (asDropdownStore) { + return allFolders.sort(Zarafa.plugins.contactimporter.data.Actions.dynamicSort(1)); + } else { + return allFolders; + } + }, + + /** + * Dynamic sort function, sorts by property name. + * @param {string|int} property + * @returns {Function} + */ + dynamicSort: function (property) { + var sortOrder = 1; + if (property[0] === "-") { + sortOrder = -1; + property = property.substr(1); + } + return function (a, b) { + var result = (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0; + return result * sortOrder; + } + }, + + /** + * Return a contact folder element by name. + * @param {string} name + * @returns {*} + */ + getContactFolderByName: function (name) { + var folders = Zarafa.plugins.contactimporter.data.Actions.getAllContactFolders(false); + + for (var i = 0; i < folders.length; i++) { + if (folders[i].display_name == name) { + return folders[i]; + } + } + + return container.getHierarchyStore().getDefaultFolder('contact'); + }, + + /** + * Return a contact folder element by entryid. + * @param {string} entryid + * @returns {*} + */ + getContactFolderByEntryid: function (entryid) { + var folders = Zarafa.plugins.contactimporter.data.Actions.getAllContactFolders(false); + + for (var i = 0; i < folders.length; i++) { + if (folders[i].entryid == entryid) { + return folders[i]; + } + } + + return container.getHierarchyStore().getDefaultFolder('contact'); + } +}; diff --git a/js/dialogs/ImportPanel.js b/js/dialogs/ImportPanel.js index 68719eb..beebb28 100644 --- a/js/dialogs/ImportPanel.js +++ b/js/dialogs/ImportPanel.js @@ -132,121 +132,6 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }; }, - /** - * Get all contact folders. - * @param {boolean} asDropdownStore If true, a simple array store will be returned. - * @returns {*} - */ - getAllContactFolders: function (asDropdownStore) { - asDropdownStore = Ext.isEmpty(asDropdownStore) ? false : asDropdownStore; - - var allFolders = []; - - var defaultContactFolder = container.getHierarchyStore().getDefaultFolder('contact'); - - var inbox = container.getHierarchyStore().getDefaultStore(); - var pub = container.getHierarchyStore().getPublicStore(); - - if (!Ext.isEmpty(inbox.subStores) && inbox.subStores.folders.totalLength > 0) { - for (var i = 0; i < inbox.subStores.folders.totalLength; i++) { - var folder = inbox.subStores.folders.getAt(i); - if (!Ext.isEmpty(folder) && folder.get("container_class") == "IPF.Contact") { - if (asDropdownStore) { - allFolders.push([ - folder.get("entryid"), - folder.get("display_name") - ]); - } else { - allFolders.push({ - display_name: folder.get("display_name"), - entryid: folder.get("entryid"), - store_entryid: folder.get("store_entryid"), - is_public: false - }); - } - } - } - } - - if (!Ext.isEmpty(pub.subStores) && pub.subStores.folders.totalLength > 0) { - for (var j = 0; j < pub.subStores.folders.totalLength; j++) { - var folder = pub.subStores.folders.getAt(j); - if (!Ext.isEmpty(folder) && folder.get("container_class") == "IPF.Contact") { - if (asDropdownStore) { - allFolders.push([ - folder.get("entryid"), - folder.get("display_name") + " (Public)" - ]); - } else { - allFolders.push({ - display_name: folder.get("display_name"), - entryid: folder.get("entryid"), - store_entryid: folder.get("store_entryid"), - is_public: true - }); - } - } - } - } - - if (asDropdownStore) { - return allFolders.sort(this.dynamicSort(1)); - } else { - return allFolders; - } - }, - - /** - * Dynamic sort function, sorts by property name. - * @param {string|int} property - * @returns {Function} - */ - dynamicSort: function (property) { - var sortOrder = 1; - if (property[0] === "-") { - sortOrder = -1; - property = property.substr(1); - } - return function (a, b) { - var result = (a[property].toLowerCase() < b[property].toLowerCase()) ? -1 : (a[property].toLowerCase() > b[property].toLowerCase()) ? 1 : 0; - return result * sortOrder; - } - }, - - /** - * Return a contact folder element by name. - * @param {string} name - * @returns {*} - */ - getContactFolderByName: function (name) { - var folders = this.getAllContactFolders(false); - - for (var i = 0; i < folders.length; i++) { - if (folders[i].display_name == name) { - return folders[i]; - } - } - - return container.getHierarchyStore().getDefaultFolder('contact'); - }, - - /** - * Return a contact folder element by entryid. - * @param {string} entryid - * @returns {*} - */ - getContactFolderByEntryid: function (entryid) { - var folders = this.getAllContactFolders(false); - - for (var i = 0; i < folders.length; i++) { - if (folders[i].entryid == entryid) { - return folders[i]; - } - } - - return container.getHierarchyStore().getDefaultFolder('contact'); - }, - /** * Reloads the data of the grid * @private @@ -309,18 +194,18 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }, /** - * Generate the UI calendar select box. + * Generate the UI addressbook select box. * @returns {*} */ createSelectBox: function () { - var myStore = this.getAllContactFolders(true); + var myStore = Zarafa.plugins.contactimporter.data.Actions.getAllContactFolders(true); return { xtype: "selectbox", ref: 'addressbookSelector', editable: false, name: "choosen_addressbook", - value: Ext.isEmpty(this.folder) ? this.getContactFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/contactimporter/default_addressbook")).entryid : this.folder, + value: Ext.isEmpty(this.folder) ? Zarafa.plugins.contactimporter.data.Actions.getContactFolderByName(container.getSettingsModel().get("zarafa/v1/plugins/contactimporter/default_addressbook")).entryid : this.folder, width: 100, fieldLabel: dgettext('plugin_contactimporter', 'Select folder'), store: myStore, @@ -430,7 +315,7 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { this.submitAllButton.disable(); Zarafa.common.dialogs.MessageBox.show({ title: dgettext('plugin_contactimporter', 'Error'), - msg: _(action.result.error), + msg: action.result.error, icon: Zarafa.common.dialogs.MessageBox.ERROR, buttons: Zarafa.common.dialogs.MessageBox.OK }); @@ -542,7 +427,7 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { buttons: Zarafa.common.dialogs.MessageBox.OK }); } else { - var contactFolder = this.getContactFolderByEntryid(folderValue); + var contactFolder = Zarafa.plugins.contactimporter.data.Actions.getContactFolderByEntryid(folderValue); this.loadMask.show(); var uids = []; diff --git a/js/plugin.contactimporter.js b/js/plugin.contactimporter.js index 2956920..9570c61 100644 --- a/js/plugin.contactimporter.js +++ b/js/plugin.contactimporter.js @@ -83,55 +83,7 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { recordIds.push(btn.records[i].get("entryid")); } - var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({ - successCallback: this.downloadVCF, - scope: this - }); - - // Notify user - // # TRANSLATORS: {0} will be replaced by the number of contacts that will be exported - container.getNotifier().notify('info', dgettext('plugin_contactimporter', 'Contact Export'), String.format(dgettext('plugin_contactimporter', 'Exporting {0} contacts. Please wait...'), recordIds.length)); - - - // request attachment preperation - container.getRequest().singleRequest( - 'contactmodule', - 'export', - { - storeid: btn.records[0].get("store_entryid"), - records: recordIds - }, - responseHandler - ); - }, - - /** - * Callback for the export request. - * @param {Object} response - */ - downloadVCF: function (response) { - if (response.status == false) { - Zarafa.common.dialogs.MessageBox.show({ - title: dgettext('plugin_contactimporter', 'Warning'), - msg: response.message, - icon: Zarafa.common.dialogs.MessageBox.WARNING, - buttons: Zarafa.common.dialogs.MessageBox.OK - }); - } else { - var downloadFrame = Ext.getBody().createChild({ - tag: 'iframe', - cls: 'x-hidden' - }); - - var url = document.URL; - var link = url.substring(0, url.lastIndexOf('/') + 1); - - link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_vcf"; - link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token)); - link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename)); - - downloadFrame.dom.contentWindow.location = link; - } + Zarafa.plugins.contactimporter.data.Actions.exportToVCF(btn.records[0].get("store_entryid"), recordIds, undefined); }, /** diff --git a/js/ui/ContextMenu.js b/js/ui/ContextMenu.js index 1700995..b88b6e7 100644 --- a/js/ui/ContextMenu.js +++ b/js/ui/ContextMenu.js @@ -94,25 +94,7 @@ Zarafa.plugins.contactimporter.ui.ContextMenu = Ext.extend(Zarafa.hierarchy.ui.C * @private */ onContextItemExport: function () { - var responseHandler = new Zarafa.plugins.contactimporter.data.ResponseHandler({ - successCallback: this.downloadVCF, - scope: this - }); - - // Notify user - // # TRANSLATORS: {0} will be replaced by the number of contacts that will be exported - container.getNotifier().notify('info', dgettext('plugin_contactimporter', 'Contact Export'), String.format(dgettext('plugin_contactimporter', 'Exporting {0} contacts. Please wait...'), this.records.get('content_count'))); - - // request attachment preperation - container.getRequest().singleRequest( - 'contactmodule', - 'export', - { - storeid: this.records.get("store_entryid"), - folder: this.records.get("entryid") - }, - responseHandler - ); + Zarafa.plugins.contactimporter.data.Actions.exportToVCF(this.records.get("store_entryid"), undefined, this.records); }, /** @@ -127,35 +109,6 @@ Zarafa.plugins.contactimporter.ui.ContextMenu = Ext.extend(Zarafa.hierarchy.ui.C }; Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config); - }, - - /** - * Callback for the export request. - * @param {Object} response - */ - downloadVCF: function (response) { - if (response.status == false) { - Zarafa.common.dialogs.MessageBox.show({ - title: dgettext('plugin_contactimporter', 'Warning'), - msg: response.message, - icon: Zarafa.common.dialogs.MessageBox.WARNING, - buttons: Zarafa.common.dialogs.MessageBox.OK - }); - } else { - var downloadFrame = Ext.getBody().createChild({ - tag: 'iframe', - cls: 'x-hidden' - }); - - var url = document.URL; - var link = url.substring(0, url.lastIndexOf('/') + 1); - - link += "index.php?sessionid=" + container.getUser().getSessionId() + "&load=custom&name=download_vcf"; - link = Ext.urlAppend(link, "token=" + encodeURIComponent(response.download_token)); - link = Ext.urlAppend(link, "filename=" + encodeURIComponent(response.filename)); - - downloadFrame.dom.contentWindow.location = link; - } } }); diff --git a/php/download.php b/php/download.php index 52edb6b..1ad0618 100644 --- a/php/download.php +++ b/php/download.php @@ -23,49 +23,52 @@ */ class DownloadHandler { - /** - * Download the given vcf file. - */ - public static function doDownload() - { - if (isset($_GET["token"])) { - $token = $_GET["token"]; - } else { - return false; - } + /** + * Download the given vcf file. + * @return boolean + */ + public static function doDownload() + { + if (isset($_GET["token"])) { + $token = $_GET["token"]; + } else { + return false; + } - if (isset($_GET["filename"])) { - $filename = $_GET["filename"]; - } else { - return false; - } + if (isset($_GET["filename"])) { + $filename = $_GET["filename"]; + } else { + return false; + } - // validate token - if (!ctype_alnum($token)) { // token is a md5 hash - return false; - } + // validate token + if (!preg_match('/^[a-zA-Z0-9]+$/', $token)) { // token is a md5 hash + return false; + } - $file = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "vcf_" . $token . ".vcf"; + $file = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "vcf_" . $token . ".vcf"; - if (!file_exists($file)) { // invalid token - return false; - } + if (!file_exists($file)) { // invalid token + return false; + } - // set headers here - header('Content-Disposition: attachment; filename="' . $filename . '"'); + // set headers here + header('Content-Disposition: attachment; filename="' . $filename . '"'); - // no caching - header('Expires: 0'); // set expiration time - header('Content-Description: File Transfer'); - header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); - header('Content-Length: ' . filesize($file)); - header('Content-Type: application/octet-stream'); - header('Pragma: public'); - flush(); + // no caching + header('Expires: 0'); // set expiration time + header('Content-Description: File Transfer'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Content-Length: ' . filesize($file)); + header('Content-Type: application/octet-stream'); + header('Pragma: public'); + flush(); - // print the downloaded file - readfile($file); - ignore_user_abort(true); - unlink($file); - } + // print the downloaded file + readfile($file); + ignore_user_abort(true); + unlink($file); + + return true; + } } \ No newline at end of file diff --git a/php/helper.php b/php/helper.php new file mode 100644 index 0000000..80c763a --- /dev/null +++ b/php/helper.php @@ -0,0 +1,62 @@ + + * Copyright (C) 2012-2016 Christoph Haas + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +namespace contactimporter; + +class Helper +{ + /** + * Generates a random string with variable length. + * + * @param $length the lenght of the generated string, defaults to 6 + * @return string a random string + */ + public static function randomstring($length = 6) + { + // $chars - all allowed charakters + $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + + srand((double)microtime() * 1000000); + $i = 0; + $pass = ""; + while ($i < $length) { + $num = rand() % strlen($chars); + $tmp = substr($chars, $num, 1); + $pass = $pass . $tmp; + $i++; + } + return $pass; + } + + /** + * respond/echo JSON + * + * @param $arr + * @return string JSON encoded string + */ + public static function respondJSON($arr) + { + echo json_encode($arr); + } +} \ No newline at end of file diff --git a/php/module.contact.php b/php/module.contact.php index 1e471c9..79ccf43 100644 --- a/php/module.contact.php +++ b/php/module.contact.php @@ -1,4 +1,5 @@ getMessage(); + $errorMsg = $e->getMessage(); } $contacts = array(); if (!$error && iterator_count($parser) > 0) { $contacts = $this->parseContactsToArray($parser); - $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid)); - $folder = mapi_msgstore_openentry($store, hex2bin($folderid)); + $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeId)); + $folder = mapi_msgstore_openentry($store, hex2bin($folderId)); - $importall = false; + $importAll = false; if (count($uids) == count($contacts)) { - $importall = true; + $importAll = true; } $propValuesMAPI = array(); @@ -179,7 +163,7 @@ class ContactModule extends Module // iterate through all contacts and import them :) foreach ($contacts as $contact) { - if (isset($contact["display_name"]) && ($importall || in_array($contact["internal_fields"]["contact_uid"], $uids))) { + if (isset($contact["display_name"]) && ($importAll || in_array($contact["internal_fields"]["contact_uid"], $uids))) { // parse the arraykeys // TODO: this is very slow... foreach ($contact as $key => $value) { @@ -242,7 +226,7 @@ class ContactModule extends Module } else { $response['status'] = false; $response['count'] = 0; - $response['message'] = $error ? $error_msg : dgettext("plugin_contactimporter", "VCF file is empty!"); + $response['message'] = $error ? $errorMsg : dgettext("plugin_contactimporter", "VCF file is empty!"); } $this->addActionData($actionType, $response); @@ -252,20 +236,20 @@ class ContactModule extends Module /** * Get a property from the array. * @param $props - * @param $propname + * @param $propName * @return string */ - private function getProp($props, $propname) + private function getProp($props, $propName) { - $p = $this->getProperties(); - if (isset($props["props"][$propname])) { - return $props["props"][$propname]; + if (isset($props["props"][$propName])) { + return $props["props"][$propName]; } return ""; } /** * Export selected contacts to vCard. + * * @param $actionType * @param $actionData * @return bool @@ -273,9 +257,9 @@ class ContactModule extends Module private function exportContacts($actionType, $actionData) { // Get store id - $storeid = false; + $storeId = false; if (isset($actionData["storeid"])) { - $storeid = $actionData["storeid"]; + $storeId = $actionData["storeid"]; } // Get records @@ -295,17 +279,17 @@ class ContactModule extends Module $error_msg = ""; // write csv - $token = $this->randomstring(16); + $token = Helper::randomstring(16); $file = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "vcf_" . $token . ".vcf"; file_put_contents($file, ""); - $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid)); + $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeId)); if ($store) { // load folder first if ($folder !== false) { - $mapifolder = mapi_msgstore_openentry($store, hex2bin($folder)); + $mapiFolder = mapi_msgstore_openentry($store, hex2bin($folder)); - $table = mapi_folder_getcontentstable($mapifolder); + $table = mapi_folder_getcontentstable($mapiFolder); $list = mapi_table_queryallrows($table, array(PR_ENTRYID)); foreach ($list as $item) { @@ -314,7 +298,7 @@ class ContactModule extends Module } for ($index = 0, $count = count($records); $index < $count; $index++) { // define vcard - $vcard = new VCard(); + $vCard = new VCard(); $message = mapi_msgstore_openentry($store, hex2bin($records[$index])); @@ -324,118 +308,118 @@ class ContactModule extends Module $messageProps = $GLOBALS['operations']->getMessageProps($store, $message, $properties, $plaintext); // define variables - $firstname = $this->getProp($messageProps, "given_name"); - $lastname = $this->getProp($messageProps, "surname"); + $firstName = $this->getProp($messageProps, "given_name"); + $lastName = $this->getProp($messageProps, "surname"); $additional = $this->getProp($messageProps, "middle_name"); $prefix = $this->getProp($messageProps, "display_name_prefix"); $suffix = ''; // add personal data - $vcard->addName($lastname, $firstname, $additional, $prefix, $suffix); + $vCard->addName($lastName, $firstName, $additional, $prefix, $suffix); $company = $this->getProp($messageProps, "company_name"); if (!empty($company)) { - $vcard->addCompany($company); + $vCard->addCompany($company); } - $jobtitle = $this->getProp($messageProps, "title"); - if (!empty($jobtitle)) { - $vcard->addJobtitle($jobtitle); + $jobTitle = $this->getProp($messageProps, "title"); + if (!empty($jobTitle)) { + $vCard->addJobtitle($jobTitle); } // MAIL $mail = $this->getProp($messageProps, "email_address_1"); if (!empty($mail)) { - $vcard->addEmail($mail); + $vCard->addEmail($mail); } $mail = $this->getProp($messageProps, "email_address_2"); if (!empty($mail)) { - $vcard->addEmail($mail); + $vCard->addEmail($mail); } $mail = $this->getProp($messageProps, "email_address_3"); if (!empty($mail)) { - $vcard->addEmail($mail); + $vCard->addEmail($mail); } // PHONE - $wphone = $this->getProp($messageProps, "business_telephone_number"); - if (!empty($wphone)) { - $vcard->addPhoneNumber($wphone, 'WORK'); + $wPhone = $this->getProp($messageProps, "business_telephone_number"); + if (!empty($wPhone)) { + $vCard->addPhoneNumber($wPhone, 'WORK'); } - $wphone = $this->getProp($messageProps, "home_telephone_number"); - if (!empty($wphone)) { - $vcard->addPhoneNumber($wphone, 'HOME'); + $wPhone = $this->getProp($messageProps, "home_telephone_number"); + if (!empty($wPhone)) { + $vCard->addPhoneNumber($wPhone, 'HOME'); } - $wphone = $this->getProp($messageProps, "cellular_telephone_number"); - if (!empty($wphone)) { - $vcard->addPhoneNumber($wphone, 'CELL'); + $wPhone = $this->getProp($messageProps, "cellular_telephone_number"); + if (!empty($wPhone)) { + $vCard->addPhoneNumber($wPhone, 'CELL'); } - $wphone = $this->getProp($messageProps, "business_fax_number"); - if (!empty($wphone)) { - $vcard->addPhoneNumber($wphone, 'FAX'); + $wPhone = $this->getProp($messageProps, "business_fax_number"); + if (!empty($wPhone)) { + $vCard->addPhoneNumber($wPhone, 'FAX'); } - $wphone = $this->getProp($messageProps, "pager_telephone_number"); - if (!empty($wphone)) { - $vcard->addPhoneNumber($wphone, 'PAGER'); + $wPhone = $this->getProp($messageProps, "pager_telephone_number"); + if (!empty($wPhone)) { + $vCard->addPhoneNumber($wPhone, 'PAGER'); } - $wphone = $this->getProp($messageProps, "car_telephone_number"); - if (!empty($wphone)) { - $vcard->addPhoneNumber($wphone, 'CAR'); + $wPhone = $this->getProp($messageProps, "car_telephone_number"); + if (!empty($wPhone)) { + $vCard->addPhoneNumber($wPhone, 'CAR'); } // ADDRESS - $addr = $this->getProp($messageProps, "business_address"); - if (!empty($addr)) { - $vcard->addAddress(null, null, $this->getProp($messageProps, "business_address_street"), $this->getProp($messageProps, "business_address_city"), $this->getProp($messageProps, "business_address_state"), $this->getProp($messageProps, "business_address_postal_code"), $this->getProp($messageProps, "business_address_country"), "WORK"); + $address = $this->getProp($messageProps, "business_address"); + if (!empty($address)) { + $vCard->addAddress(null, null, $this->getProp($messageProps, "business_address_street"), $this->getProp($messageProps, "business_address_city"), $this->getProp($messageProps, "business_address_state"), $this->getProp($messageProps, "business_address_postal_code"), $this->getProp($messageProps, "business_address_country"), "WORK"); } - $addr = $this->getProp($messageProps, "home_address"); - if (!empty($addr)) { - $vcard->addAddress(null, null, $this->getProp($messageProps, "home_address_street"), $this->getProp($messageProps, "home_address_city"), $this->getProp($messageProps, "home_address_state"), $this->getProp($messageProps, "home_address_postal_code"), $this->getProp($messageProps, "home_address_country"), "HOME"); + $address = $this->getProp($messageProps, "home_address"); + if (!empty($address)) { + $vCard->addAddress(null, null, $this->getProp($messageProps, "home_address_street"), $this->getProp($messageProps, "home_address_city"), $this->getProp($messageProps, "home_address_state"), $this->getProp($messageProps, "home_address_postal_code"), $this->getProp($messageProps, "home_address_country"), "HOME"); } - $addr = $this->getProp($messageProps, "other_address"); - if (!empty($addr)) { - $vcard->addAddress(null, null, $this->getProp($messageProps, "other_address_street"), $this->getProp($messageProps, "other_address_city"), $this->getProp($messageProps, "other_address_state"), $this->getProp($messageProps, "other_address_postal_code"), $this->getProp($messageProps, "other_address_country"), "OTHER"); + $address = $this->getProp($messageProps, "other_address"); + if (!empty($address)) { + $vCard->addAddress(null, null, $this->getProp($messageProps, "other_address_street"), $this->getProp($messageProps, "other_address_city"), $this->getProp($messageProps, "other_address_state"), $this->getProp($messageProps, "other_address_postal_code"), $this->getProp($messageProps, "other_address_country"), "OTHER"); } // MISC $url = $this->getProp($messageProps, "webpage"); if (!empty($url)) { - $vcard->addURL($url); + $vCard->addURL($url); } - $bday = $this->getProp($messageProps, "birthday"); - if (!empty($bday)) { - $vcard->addBirthday(date("Y-m-d", $bday)); + $birthday = $this->getProp($messageProps, "birthday"); + if (!empty($birthday)) { + $vCard->addBirthday(date("Y-m-d", $birthday)); } $notes = $this->getProp($messageProps, "body"); if (!empty($notes)) { - $vcard->addNote($notes); + $vCard->addNote($notes); } - $haspicture = $this->getProp($messageProps, "has_picture"); - if (!empty($haspicture) && $haspicture === true) { - $attachnum = -1; + $hasPicture = $this->getProp($messageProps, "has_picture"); + if (!empty($hasPicture) && $hasPicture === true) { + $attachNum = -1; if (isset($messageProps["attachments"]) && isset($messageProps["attachments"]["item"])) { foreach ($messageProps["attachments"]["item"] as $attachment) { if ($attachment["props"]["attachment_contactphoto"] == true) { - $attachnum = $attachment["props"]["attach_num"]; + $attachNum = $attachment["props"]["attach_num"]; break; } } } - if ($attachnum >= 0) { - $attachment = $this->getAttachmentByAttachNum($message, $attachnum); // get first attachment only - $phototoken = $this->randomstring(16); - $tmpphoto = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "photo_" . $phototoken . ".jpg"; - $this->storeSavedAttachment($tmpphoto, $attachment); - $vcard->addPhoto($tmpphoto, true); - unlink($tmpphoto); + if ($attachNum >= 0) { + $attachment = $this->getAttachmentByAttachNum($message, $attachNum); // get first attachment only + $photoToken = Helper::randomstring(16); + $tmpPhoto = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "photo_" . $photoToken . ".jpg"; + $this->storeSavedAttachment($tmpPhoto, $attachment); + $vCard->addPhoto($tmpPhoto, true); + unlink($tmpPhoto); } } // write combined vcf - file_put_contents($file, file_get_contents($file) . $vcard->getOutput()); + file_put_contents($file, file_get_contents($file) . $vCard->getOutput()); } } else { return false; @@ -453,11 +437,14 @@ class ContactModule extends Module $this->addActionData($actionType, $response); $GLOBALS["bus"]->addData($this->getResponseData()); + + return true; } /** * Returns attachment based on specified attachNum, additionally it will also get embedded message * if we want to get the inline image attachment. + * * @param $message * @param array $attachNum * @return MAPIAttach embedded message attachment or attachment that is requested @@ -473,10 +460,11 @@ class ContactModule extends Module /** * Function will open passed attachment and generate response for that attachment to send it to client. * This should only be used to download attachment that is already saved in MAPIMessage. + * * @param MAPIAttach $attachment attachment which will be dumped to client side * @return Response response to sent to client including attachment data */ - private function storeSavedAttachment($temppath, $attachment) + private function storeSavedAttachment($tempPath, $attachment) { // Check if the attachment is opened if ($attachment) { @@ -490,12 +478,13 @@ class ContactModule extends Module $body .= mapi_stream_read($stream, BLOCK_SIZE); } - file_put_contents($temppath, $body); + file_put_contents($tempPath, $body); } } /** * Replace String Property Tags + * * @param $store * @param $properties * @return array @@ -563,7 +552,7 @@ class ContactModule extends Module /** * A simple Property map initialization * - * @return [array] the propertyarray + * @return array the propertyarray */ private function getProperties() { @@ -708,7 +697,7 @@ class ContactModule extends Module private function loadContacts($actionType, $actionData) { $error = false; - $error_msg = ""; + $errorMsg = ""; if (is_readable($actionData["vcf_filepath"])) { $parser = null; @@ -717,11 +706,11 @@ class ContactModule extends Module $parser = VCardParser::parseFromFile($actionData["vcf_filepath"]); } catch (Exception $e) { $error = true; - $error_msg = $e->getMessage(); + $errorMsg = $e->getMessage(); } if ($error) { $response['status'] = false; - $response['message'] = $error_msg; + $response['message'] = $errorMsg; } else { if (iterator_count($parser) == 0) { $response['status'] = false; @@ -750,8 +739,8 @@ class ContactModule extends Module /** * Create a array with contacts * - * @param contacts vcard or csv contacts - * @param csv optional, true if contacts are csv contacts + * @param VCard $contacts or csv contacts + * @param bool|optional $csv true if contacts are csv contacts * @return array parsed contacts * @private */ @@ -818,13 +807,13 @@ class ContactModule extends Module } } if (isset($vCard->email) && count($vCard->email) > 0) { - $emailcount = 0; + $emailCount = 0; $properties["address_book_long"] = 0; foreach ($vCard->email as $type => $email) { foreach ($email as $mail) { - $fileas = $mail; + $fileAs = $mail; if (isset($properties["fileas"]) && !empty($properties["fileas"])) { - $fileas = $properties["fileas"]; // set to real name + $fileAs = $properties["fileas"]; // set to real name } // we only have storage for 3 mail addresses! @@ -841,24 +830,24 @@ class ContactModule extends Module * address_book_long stores sum of the flags * these both properties should be in sync always */ - switch ($emailcount) { + switch ($emailCount) { case 0: $properties["email_address_1"] = $mail; - $properties["email_address_display_name_1"] = $fileas . " (" . $mail . ")"; + $properties["email_address_display_name_1"] = $fileAs . " (" . $mail . ")"; $properties["email_address_display_name_email_1"] = $mail; $properties["address_book_mv"][] = 0; // this is needed for adding the contact to the email address book, 0 = email 1 $properties["address_book_long"] += 1; // this specifies the number of elements in address_book_mv break; case 1: $properties["email_address_2"] = $mail; - $properties["email_address_display_name_2"] = $fileas . " (" . $mail . ")"; + $properties["email_address_display_name_2"] = $fileAs . " (" . $mail . ")"; $properties["email_address_display_name_email_2"] = $mail; $properties["address_book_mv"][] = 1; // this is needed for adding the contact to the email address book, 1 = email 2 $properties["address_book_long"] += 2; // this specifies the number of elements in address_book_mv break; case 2: $properties["email_address_3"] = $mail; - $properties["email_address_display_name_3"] = $fileas . " (" . $mail . ")"; + $properties["email_address_display_name_3"] = $fileAs . " (" . $mail . ")"; $properties["email_address_display_name_email_3"] = $mail; $properties["address_book_mv"][] = 2; // this is needed for adding the contact to the email address book, 2 = email 3 $properties["address_book_long"] += 4; // this specifies the number of elements in address_book_mv @@ -866,7 +855,7 @@ class ContactModule extends Module default: break; } - $emailcount++; + $emailCount++; } } } @@ -936,7 +925,7 @@ class ContactModule extends Module if (!is_writable(TMP_PATH . "/")) { error_log("Can not write to export tmp directory!"); } else { - $tmppath = TMP_PATH . "/" . $this->randomstring(15); + $tmppath = TMP_PATH . "/" . Helper::randomstring(15); if (isset($vCard->rawPhoto)) { if (file_put_contents($tmppath, $vCard->rawPhoto)) { $properties["internal_fields"]["x_photo_path"] = $tmppath; @@ -968,14 +957,14 @@ class ContactModule extends Module } /** - * Generate the whole addressstring + * Generate the whole address string * * @param street * @param zip * @param city * @param state * @param country - * @return string the concatinated address string + * @return string the concatenated address string * @private */ private function buildAddressString($street, $zip, $city, $state, $country) @@ -1009,6 +998,7 @@ class ContactModule extends Module /** * Store the file to a temporary directory + * * @param $actionType * @param $actionData * @private @@ -1016,15 +1006,15 @@ class ContactModule extends Module private function getAttachmentPath($actionType, $actionData) { // Get store id - $storeid = false; + $storeId = false; if (isset($actionData["store"])) { - $storeid = $actionData["store"]; + $storeId = $actionData["store"]; } // Get message entryid - $entryid = false; + $entryId = false; if (isset($actionData["entryid"])) { - $entryid = $actionData["entryid"]; + $entryId = $actionData["entryid"]; } // Check which type isset @@ -1037,13 +1027,13 @@ class ContactModule extends Module } // Check if storeid and entryid isset - if ($storeid && $entryid) { + if ($storeId && $entryId) { // Open the store - $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid)); + $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeId)); if ($store) { // Open the message - $message = mapi_msgstore_openentry($store, hex2bin($entryid)); + $message = mapi_msgstore_openentry($store, hex2bin($entryId)); if ($message) { $attachment = false; @@ -1053,10 +1043,10 @@ class ContactModule extends Module // Loop through the attachNums, message in message in message ... for ($i = 0; $i < (count($attachNum) - 1); $i++) { // Open the attachment - $tempattach = mapi_message_openattach($message, (int)$attachNum[$i]); - if ($tempattach) { + $tempAttach = mapi_message_openattach($message, (int)$attachNum[$i]); + if ($tempAttach) { // Open the object in the attachment - $message = mapi_attach_openobj($tempattach); + $message = mapi_attach_openobj($tempAttach); } } @@ -1100,7 +1090,7 @@ class ContactModule extends Module $ext_found = false; while (!feof($fh) && !$ext_found) { $line = fgets($fh); - preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result); + preg_match('/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i', $line, $result); if ($extension == $result[1]) { $ext_found = true; $contentType = $result[2]; @@ -1112,25 +1102,26 @@ class ContactModule extends Module } - $tmpname = tempnam(TMP_PATH, stripslashes($filename)); + $tmpName = tempnam(TMP_PATH, stripslashes($filename)); // Open a stream to get the attachment data $stream = mapi_openpropertytostream($attachment, PR_ATTACH_DATA_BIN); $stat = mapi_stream_stat($stream); // File length = $stat["cb"] - $fhandle = fopen($tmpname, 'w'); + $fHandle = fopen($tmpName, 'w'); $buffer = null; for ($i = 0; $i < $stat["cb"]; $i += BLOCK_SIZE) { // Write stream $buffer = mapi_stream_read($stream, BLOCK_SIZE); - fwrite($fhandle, $buffer, strlen($buffer)); + fwrite($fHandle, $buffer, strlen($buffer)); } - fclose($fhandle); + fclose($fHandle); $response = array(); - $response['tmpname'] = $tmpname; + $response['tmpname'] = $tmpName; $response['filename'] = $filename; + $response['contenttype'] = $contentType; $response['status'] = true; $this->addActionData($actionType, $response); $GLOBALS["bus"]->addData($this->getResponseData()); @@ -1152,6 +1143,7 @@ class ContactModule extends Module /** * Check if string starts with other string. + * * @param $haystack * @param $needle * @return bool @@ -1161,4 +1153,4 @@ class ContactModule extends Module $haystack = str_replace("type=", "", $haystack); // remove type from string return substr($haystack, 0, strlen($needle)) === $needle; } -} +} \ No newline at end of file diff --git a/php/plugin.contactimporter.php b/php/plugin.contactimporter.php index 5613573..a4b8c84 100644 --- a/php/plugin.contactimporter.php +++ b/php/plugin.contactimporter.php @@ -1,4 +1,5 @@ false, 'error' => dgettext("plugin_contactimporter", "Not authenticated!"))); + die(); } -/** - * Generates a random string with variable length. - * @param $length the lenght of the generated string - * @return string a random string - */ -function randomstring($length = 6) -{ - // $chars - all allowed charakters - $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - - srand((double)microtime() * 1000000); - $i = 0; - $pass = ""; - while ($i < $length) { - $num = rand() % strlen($chars); - $tmp = substr($chars, $num, 1); - $pass = $pass . $tmp; - $i++; - } - return $pass; -} - -$destpath = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD; -$destpath .= $_FILES['vcfdata']['name'] . randomstring(); - if (is_readable($_FILES['vcfdata']['tmp_name'])) { - $result = move_uploaded_file($_FILES['vcfdata']['tmp_name'], $destpath); + $dstPath = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD; + $dstPath .= $_FILES['vcfdata']['name'] . Helper::randomstring(); + + $result = move_uploaded_file($_FILES['vcfdata']['tmp_name'], $dstPath); if ($result) { - respondJSON(array('success' => true, 'vcf_file' => $destpath)); + Helper::respondJSON(array('success' => true, 'vcf_file' => $dstPath)); } else { - respondJSON(array('success' => false, 'error' => dgettext("plugin_contactimporter", "File could not be moved to TMP path! Check plugin config and folder permissions!"))); + Helper::respondJSON(array('success' => false, 'error' => dgettext("plugin_contactimporter", "File could not be moved to TMP path! Check plugin config and folder permissions!"))); } } else { - respondJSON(array('success' => false, 'error' => dgettext("plugin_contactimporter", "File could not be read by server, upload error!"))); + Helper::respondJSON(array('success' => false, 'error' => dgettext("plugin_contactimporter", "File could not be read by server, upload error!"))); } \ No newline at end of file