diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/build.xml b/build.xml index 687da16..c47e16b 100644 --- a/build.xml +++ b/build.xml @@ -1,18 +1,15 @@ - - - - - - - + + + + + - @@ -21,30 +18,8 @@ - - - - - - - - - - - - - - - - - - - - - - @@ -54,8 +29,7 @@ - - + @@ -68,16 +42,6 @@ - - - - - - - - - - @@ -89,19 +53,11 @@ - - - - - - - - - + @@ -110,8 +66,8 @@ - - + + @@ -155,16 +111,7 @@ var npgettext = function(msgctxt, msgid, msgid_plural, count) {}; var pgettext = function(msgctxt, msgid) {}; - - + @@ -172,105 +119,81 @@ - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - - - - Processing manifest.xml - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + + - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/config.php b/config.php index f8c526e..29ed52f 100644 --- a/config.php +++ b/config.php @@ -2,7 +2,7 @@ /** Disable the import plugin for all clients */ define('PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE', false); /** Disable the export feature for all clients */ - define('PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE_EXPORT', false); // currently not available + define('PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE_EXPORT', false); /** The default addressbook to import to (default: contact)*/ define('PLUGIN_CONTACTIMPORTER_DEFAULT', "contact"); diff --git a/js/dialogs/ImportPanel.js b/js/dialogs/ImportPanel.js index c58fbe5..0840159 100644 --- a/js/dialogs/ImportPanel.js +++ b/js/dialogs/ImportPanel.js @@ -47,7 +47,7 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { config = config || {}; var self = this; - if(typeof config.filename !== "undefined") { + if(!Ext.isEmpty(config.filename)) { this.vcffile = config.filename; } @@ -146,13 +146,13 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { var i = 0; for(i = 0; i < contactdata.contacts.length; i++) { - parsedData[i] = new Array( + parsedData[i] = [ contactdata.contacts[i]["display_name"], contactdata.contacts[i]["given_name"], contactdata.contacts[i]["surname"], contactdata.contacts[i]["company_name"], contactdata.contacts[i] - ); + ]; } } else { return null; @@ -202,10 +202,10 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { /* add all local contact folders */ var i = 0; - myStore.push(new Array(defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName())); + myStore.push([defaultFolder.getDefaultFolderKey(), defaultFolder.getDisplayName()]); for(i = 0; i < subFolders.length; i++) { /* Store all subfolders */ - myStore.push(new Array(subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false)); // 3rd field = isPublicfolder + myStore.push([subFolders[i].getDisplayName(), subFolders[i].getDisplayName(), false]); // 3rd field = isPublicfolder } /* add all shared contact folders */ @@ -217,7 +217,7 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { var pubSubFolders = pubFolder.getChildren(); for(i = 0; i < pubSubFolders.length; i++) { if(pubSubFolders[i].isContainerClass("IPF.Contact")){ - myStore.push(new Array(pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true)); // 3rd field = isPublicfolder + myStore.push([pubSubFolders[i].getDisplayName(), pubSubFolders[i].getDisplayName() + " [Shared]", true]); // 3rd field = isPublicfolder } } } catch (e) { @@ -455,7 +455,7 @@ Zarafa.plugins.contactimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { if(addressbookexist) { this.loadMask.show(); - var uids = new Array(); + var uids = []; var store_entryid = ""; //receive Records from grid rows diff --git a/js/plugin.contactimporter.js b/js/plugin.contactimporter.js index aba36a7..c36a696 100644 --- a/js/plugin.contactimporter.js +++ b/js/plugin.contactimporter.js @@ -47,6 +47,7 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { /* directly import received vcfs */ this.registerInsertionPoint('common.contextmenu.attachment.actions', this.createAttachmentImportButton); + /* add import button to south navigation */ this.registerInsertionPoint("navigation.south", this.createImportButton, this); }, @@ -60,7 +61,6 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { createImportButton: function () { var button = { xtype : 'button', - id : "importcontactsbutton", text : _('Import Contacts'), iconCls : 'icon_contactimporter_button', navigationContext : container.getContextByName('contact'), @@ -90,9 +90,9 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { var extension = record.data.name.split('.').pop().toLowerCase(); if(record.data.filetype == "text/vcard" || extension == "vcf" || extension == "vcard") { - item.setDisabled(false); + item.setVisible(false); } else { - item.setDisabled(true); + item.setVisible(true); } } }; @@ -103,10 +103,7 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { */ gotAttachmentFileName: function(response) { if(response.status == true) { - Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts'], undefined, { - manager : Ext.WindowMgr, - filename : response.tmpname - }); + this.openImportDialog(response.tmpname); } else { Zarafa.common.dialogs.MessageBox.show({ title : _('Error'), @@ -182,12 +179,23 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { * Clickhandler for the button */ onImportButtonClick: function () { - Ext.getCmp("importcontactsbutton").disable(); - Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts'], undefined, { - manager : Ext.WindowMgr - }); + this.openImportDialog(); }, - + + /** + * Open the import dialog. + * + * @param {String} filename + */ + openImportDialog: function(filename) { + var componentType = Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts']; + var config = { + filename: filename + }; + + Zarafa.core.data.UIFactory.openLayerComponent(componentType, undefined, config); + }, + /** * Bid for the type of shared component * and the given record. @@ -200,7 +208,7 @@ Zarafa.plugins.contactimporter.ImportPlugin = Ext.extend(Zarafa.core.Plugin, { var bid = -1; switch(type) { case Zarafa.core.data.SharedComponentType['plugins.contactimporter.dialogs.importcontacts']: - bid = 2; + bid = 1; break; } return bid; diff --git a/manifest.xml b/manifest.xml index bcd1b92..acafc6f 100644 --- a/manifest.xml +++ b/manifest.xml @@ -2,7 +2,7 @@ - @_@PLUGIN_VERSION@_@ + 2.0.0 contactimporter VCF Contact Importer/Exporter Christoph Haas @@ -24,6 +24,7 @@ js/contactimporter-debug.js js/plugin.contactimporter.js + js/ABOUT.js js/data/ResponseHandler.js js/dialogs/ImportContentPanel.js js/dialogs/ImportPanel.js diff --git a/php/vcf/class.vCard.php b/php/vcf/class.vCard.php index 3b30e7e..bed6891 100644 --- a/php/vcf/class.vCard.php +++ b/php/vcf/class.vCard.php @@ -5,9 +5,8 @@ * @link https://github.com/nuovo/vCard-parser * @author Martins Pilsetnieks, Roberts Bruveris * @see RFC 2426, RFC 2425 - * @version 0.4.8 -*/ - + * @version 0.4.9 + */ class vCard implements Countable, Iterator { const MODE_ERROR = 'error'; @@ -42,15 +41,15 @@ class vCard implements Countable, Iterator * @static Parts of structured elements according to the spec. */ private static $Spec_StructuredElements = array( - 'n' => array('LastName', 'FirstName', 'AdditionalNames', 'Prefixes', 'Suffixes'), - 'adr' => array('POBox', 'ExtendedAddress', 'StreetAddress', 'Locality', 'Region', 'PostalCode', 'Country'), - 'geo' => array('Latitude', 'Longitude'), - 'org' => array('Name', 'Unit1', 'Unit2') + 'n' => array('lastname', 'firstname', 'additionalnames', 'prefixes', 'suffixes'), + 'adr' => array('pobox', 'extendedaddress', 'streetaddress', 'locality', 'region', 'postalcode', 'country'), + 'geo' => array('latitude', 'longitude'), + 'org' => array('name', 'unit1', 'unit2') ); private static $Spec_MultipleValueElements = array('nickname', 'categories'); private static $Spec_ElementTypes = array( - 'email' => array('internet', 'x400', 'pref'), + 'email' => array('internet', 'x400', 'pref', 'home', 'work'), 'adr' => array('dom', 'intl', 'postal', 'parcel', 'home', 'work', 'pref'), 'label' => array('dom', 'intl', 'postal', 'parcel', 'home', 'work', 'pref'), 'tel' => array('home', 'msg', 'work', 'pref', 'voice', 'fax', 'cell', 'video', 'pager', 'bbs', 'modem', 'car', 'isdn', 'pcs'), @@ -121,21 +120,26 @@ class vCard implements Countable, Iterator $this -> Mode = $vCardBeginCount == 1 ? vCard::MODE_SINGLE : vCard::MODE_MULTIPLE; // Removing/changing inappropriate newlines, i.e., all CRs or multiple newlines are changed to a single newline - $this -> RawData = str_replace("\r", "\n", $this -> RawData); - $this -> RawData = preg_replace('{(\n+)}', "\n", $this -> RawData); + + // MCA: removed, this break crlf vcard specification, all line dilimiter are CRLF + //$this -> RawData = str_replace("\r", "\n", $this -> RawData); + //$this -> RawData = preg_replace('{(\n)+}', "\n", $this -> RawData); // In multiple card mode the raw text is split at card beginning markers and each // fragment is parsed in a separate vCard object. if ($this -> Mode == self::MODE_MULTIPLE) { - $this -> RawData = explode('BEGIN:VCARD', $this -> RawData); + //Cannot use "explode", because we need to ignore, for example, 'AGENT:BEGIN:VCARD' + $this -> RawData = preg_split('{^BEGIN\:VCARD}miS', $this -> RawData); $this -> RawData = array_filter($this -> RawData); foreach ($this -> RawData as $SinglevCardRawData) { + // mca: remove \n and \r at start + //$SinglevCardRawData=ltrim($SinglevCardRawData); // Prepending "BEGIN:VCARD" to the raw string because we exploded on that one. // If there won't be the BEGIN marker in the new object, it will fail. - $SinglevCardRawData = 'BEGIN:VCARD'."\n".$SinglevCardRawData; + $SinglevCardRawData = 'BEGIN:VCARD'.$SinglevCardRawData; $ClassName = get_class($this); $this -> Data[] = new $ClassName(false, $SinglevCardRawData); @@ -143,20 +147,20 @@ class vCard implements Countable, Iterator } else { - // Protect the BASE64 final = sign (detected by the line beginning with whitespace), otherwise the next replace will get rid of it - $this -> RawData = preg_replace('{(\n\s.+)=(\n)}', '$1-base64=-$2', $this -> RawData); - // Joining multiple lines that are split with a hard wrap and indicated by an equals sign at the end of line // (quoted-printable-encoded values in v2.1 vCards) - $this -> RawData = str_replace("=\n", '', $this -> RawData); + $this -> RawData = str_replace("=\r\n", '', $this -> RawData); + + // Protect the BASE64 final = sign (detected by the line beginning with whitespace), otherwise the next replace will get rid of it + $this -> RawData = preg_replace('{(\r\n\s.+)=(\r\n)}', '$1-base64=-$2', $this -> RawData); // Joining multiple lines that are split with a soft wrap (space or tab on the beginning of the next line - $this -> RawData = str_replace(array("\n ", "\n\t"), '-wrap-', $this -> RawData); + $this -> RawData = str_replace(array("\r\n ", "\r\n\t"), '-wrap-', $this -> RawData); // Restoring the BASE64 final equals sign (see a few lines above) - $this -> RawData = str_replace("-base64=-\n", "=\n", $this -> RawData); + $this -> RawData = str_replace("-base64=-\r\n", "=\r\n", $this -> RawData); - $Lines = explode("\n", $this -> RawData); + $Lines = explode("\r\n", $this -> RawData); foreach ($Lines as $Line) { @@ -212,6 +216,7 @@ class vCard implements Countable, Iterator $ItemIndex = (int)str_ireplace('item', '', $TmpKey[0]); } + if (count($KeyParts) > 1) { $Parameters = self::ParseParameters($Key, array_slice($KeyParts, 1)); @@ -262,7 +267,7 @@ class vCard implements Countable, Iterator $Value = self::ParseStructuredValue($Value, $Key); if ($Type) { - $Value['Type'] = $Type; + $Value['type'] = $Type; } } else @@ -275,15 +280,15 @@ class vCard implements Countable, Iterator if ($Type) { $Value = array( - 'Value' => $Value, - 'Type' => $Type + 'value' => $Value, + 'type' => $Type ); } } if (is_array($Value) && $Encoding) { - $Value['Encoding'] = $Encoding; + $Value['encoding'] = $Encoding; } if (!isset($this -> Data[$Key])) @@ -296,6 +301,22 @@ class vCard implements Countable, Iterator } } + /** + * method to get key list of the current vcard + * + * @return array list of key + */ + public function getKeyList() + { + $keylist=array(); + if (isset($this -> Data)) + { + foreach($this -> Data as $key => $val) + $keylist[]=$key; + } + return $keylist; + } + /** * Magic method to get the various vCard values as object members, e.g. * a call to $vCard -> N gets the "N" value @@ -318,10 +339,10 @@ class vCard implements Countable, Iterator $Value = $this -> Data[$Key]; foreach ($Value as $K => $V) { - if (stripos($V['Value'], 'uri:') === 0) + if (isset($V['Value']) && stripos($V['Value'], 'uri:') === 0) { - $Value[$K]['Value'] = substr($V, 4); - $Value[$K]['Encoding'] = 'uri'; + $Value[$K]['value'] = substr($V, 4); + $Value[$K]['encoding'] = 'uri'; } } return $Value; @@ -340,6 +361,20 @@ class vCard implements Countable, Iterator return array(); } + /** + * Magic method to check isset for the various vCard values as object members, e.g. + * a call to isset( $vCard -> fn ) checks existence of a value. + * + * @param string Key + * + * @return bool isset + */ + public function __isset($Key) { + $Key = strtolower($Key); + $val = $this->$Key; + return isset($val); + } + /** * Saves an embedded file * @@ -361,15 +396,15 @@ class vCard implements Countable, Iterator } // Returing false if it is an image URL - if (stripos($this -> Data[$Key][$Index]['Value'], 'uri:') === 0) + if (stripos($this -> Data[$Key][$Index]['value'], 'uri:') === 0) { return false; } if (is_writable($TargetPath) || (!file_exists($TargetPath) && is_writable(dirname($TargetPath)))) { - $RawContent = $this -> Data[$Key][$Index]['Value']; - if (isset($this -> Data[$Key][$Index]['Encoding']) && $this -> Data[$Key][$Index]['Encoding'] == 'b') + $RawContent = $this -> Data[$Key][$Index]['value']; + if (isset($this -> Data[$Key][$Index]['encoding']) && $this -> Data[$Key][$Index]['encoding'] == 'b') { $RawContent = base64_decode($RawContent); } @@ -404,10 +439,10 @@ class vCard implements Countable, Iterator if (count($Arguments) > 1) { - $Types = array_values(array_slice($Arguments, 1)); + $Types = array_map('strtolower', array_values(array_slice($Arguments, 1))); if (isset(self::$Spec_StructuredElements[$Key]) && - in_array($Arguments[1], self::$Spec_StructuredElements[$Key]) + in_array(strtolower($Arguments[1]), self::$Spec_StructuredElements[$Key]) ) { $LastElementIndex = 0; @@ -439,8 +474,8 @@ class vCard implements Countable, Iterator elseif (isset(self::$Spec_ElementTypes[$Key])) { $this -> Data[$Key][] = array( - 'Value' => $Value, - 'Type' => $Types + 'value' => $Value, + 'type' => $Types ); } } @@ -475,9 +510,9 @@ class vCard implements Countable, Iterator foreach ($Values as $Index => $Value) { $Text .= $KeyUC; - if (is_array($Value) && isset($Value['Type'])) + if (is_array($Value) && isset($Value['type'])) { - $Text .= ';TYPE='.self::PrepareTypeStrForOutput($Value['Type']); + $Text .= ';TYPE='.self::PrepareTypeStrForOutput($Value['type']); } $Text .= ':'; @@ -492,7 +527,7 @@ class vCard implements Countable, Iterator } elseif (is_array($Value) && isset(self::$Spec_ElementTypes[$Key])) { - $Text .= $Value['Value']; + $Text .= $Value['value']; } else { @@ -574,7 +609,8 @@ class vCard implements Countable, Iterator $Parameters = array(); foreach ($RawParams as $Item) { - $Parameters[] = explode('=', strtolower($Item)); + // try to correct issue https://github.com/nuovo/vCard-parser/issues/20 + $Parameters[] = explode('=', strtolower($Item),2); } $Type = array(); @@ -604,10 +640,13 @@ class vCard implements Countable, Iterator } elseif (count($Parameter) > 2) { - $TempTypeParams = self::ParseParameters($Key, explode(',', $RawParams[$Index])); - if ($TempTypeParams['type']) + if(count(explode(',', $RawParams[$Index], -1)) > 0) { - $Type = array_merge($Type, $TempTypeParams['type']); + $TempTypeParams = self::ParseParameters($Key, explode(',', $RawParams[$Index])); + if ($TempTypeParams['type']) + { + $Type = array_merge($Type, $TempTypeParams['type']); + } } } else