diff --git a/.idea/contactimporter.iml b/.idea/contactimporter.iml
index 0c76797..c956989 100644
--- a/.idea/contactimporter.iml
+++ b/.idea/contactimporter.iml
@@ -4,15 +4,5 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml
new file mode 100644
index 0000000..e7bedf3
--- /dev/null
+++ b/.idea/copyright/profiles_settings.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..be9a660
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..0ef7566
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,333 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ project
+
+
+ true
+
+
+
+ DIRECTORY
+
+ false
+
+
+
+
+
+
+
+
+
+ 1480428196914
+
+
+ 1480428196914
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Unnamed
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config.php b/config.php
index 3788267..1570309 100644
--- a/config.php
+++ b/config.php
@@ -7,4 +7,3 @@ define('PLUGIN_CONTACTIMPORTER_DEFAULT', "Kontakte");
/** Tempory path for uploaded files... */
define('PLUGIN_CONTACTIMPORTER_TMP_UPLOAD', "/var/lib/kopano-webapp/tmp/");
-?>
diff --git a/languages/de_DE.UTF-8/LC_MESSAGES/plugin_contactimporter.po b/languages/de_DE.UTF-8/LC_MESSAGES/plugin_contactimporter.po
new file mode 100644
index 0000000..e69de29
diff --git a/languages/de_DE.UTF-8/language.txt b/languages/de_DE.UTF-8/language.txt
new file mode 100644
index 0000000..1149b6b
--- /dev/null
+++ b/languages/de_DE.UTF-8/language.txt
@@ -0,0 +1,2 @@
+Deutsch
+deu_DEU
diff --git a/languages/en_US.UTF-8/LC_MESSAGES/plugin_calendarimporter.mo b/languages/en_US.UTF-8/LC_MESSAGES/plugin_calendarimporter.mo
new file mode 100644
index 0000000..ab0296d
Binary files /dev/null and b/languages/en_US.UTF-8/LC_MESSAGES/plugin_calendarimporter.mo differ
diff --git a/languages/en_US.UTF-8/LC_MESSAGES/plugin_calendarimporter.po b/languages/en_US.UTF-8/LC_MESSAGES/plugin_calendarimporter.po
new file mode 100644
index 0000000..9711b7c
--- /dev/null
+++ b/languages/en_US.UTF-8/LC_MESSAGES/plugin_calendarimporter.po
@@ -0,0 +1,57 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Plugin Contactimporter\n"
+"POT-Creation-Date: 2016-11-29 15:23+0100\n"
+"PO-Revision-Date: 2016-11-29 15:23+0100\n"
+"Last-Translator: \n"
+"Language-Team: Christoph Haas \n"
+"Language: en_US\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7.1\n"
+"X-Poedit-Basepath: ../../../php\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPath-1: vendor\n"
+
+#: module.contact.php:245
+msgid "VCF file is empty!"
+msgstr "VCF file is empty!"
+
+#. TRANSLATORS: Filename suffix for exported files
+#: module.contact.php:448
+msgid "_contacts.vcf"
+msgstr "_contacts.vcf"
+
+#: module.contact.php:451
+msgid "No contacts found. Export skipped!"
+msgstr "No contacts found. Export skipped!"
+
+#: module.contact.php:728
+msgid "No contacts in vcf file"
+msgstr "No contacts in vcf file"
+
+#: module.contact.php:739
+msgid "File could not be read by server"
+msgstr "File could not be read by server"
+
+#: module.contact.php:1141
+msgid "Store could not be opened!"
+msgstr "Store could not be opened!"
+
+#: module.contact.php:1147
+msgid "Wrong call, store and entryid have to be set!"
+msgstr "Wrong call, store and entryid have to be set!"
+
+#: upload.php:69
+msgid ""
+"File could not be moved to TMP path! Check plugin config and folder "
+"permissions!"
+msgstr ""
+"File could not be moved to TMP path! Check plugin config and folder "
+"permissions!"
+
+#: upload.php:72
+msgid "File could not be read by server, upload error!"
+msgstr "File could not be read by server, upload error!"
diff --git a/languages/en_US.UTF-8/language.txt b/languages/en_US.UTF-8/language.txt
new file mode 100644
index 0000000..ea7e1f6
--- /dev/null
+++ b/languages/en_US.UTF-8/language.txt
@@ -0,0 +1,2 @@
+English (US)
+eng_USA
diff --git a/manifest.xml b/manifest.xml
index 32a0584..b81c4a1 100644
--- a/manifest.xml
+++ b/manifest.xml
@@ -9,6 +9,9 @@
http://www.sprinternet.at
Import or Export a VCF file to/from the zarafa addressbook
+
+ languages
+
config.php
diff --git a/php/download.php b/php/download.php
index cbbc2d2..52edb6b 100644
--- a/php/download.php
+++ b/php/download.php
@@ -1,7 +1,7 @@
* Copyright (C) 2012-2016 Christoph Haas
@@ -25,7 +25,6 @@ class DownloadHandler
{
/**
* Download the given vcf file.
- * @return bool
*/
public static function doDownload()
{
diff --git a/php/module.contact.php b/php/module.contact.php
index b653b94..1e471c9 100644
--- a/php/module.contact.php
+++ b/php/module.contact.php
@@ -1,6 +1,6 @@
* Copyright (C) 2012-2016 Christoph Haas
@@ -29,1139 +29,1136 @@ use JeroenDesloovere\VCard\VCardParser;
class ContactModule extends Module
{
- private $DEBUG = false; // enable error_log debugging
-
- /**
- * @constructor
- * @param $id
- * @param $data
- */
- public function __construct($id, $data)
- {
- parent::__construct($id, $data);
- }
-
- /**
- * Executes all the actions in the $data variable.
- * Exception part is used for authentication errors also
- * @return boolean true on success or false on failure.
- */
- public function execute()
- {
- $result = false;
-
- if (!$this->DEBUG) {
- /* disable error printing - otherwise json communication might break... */
- ini_set('display_errors', '0');
- }
-
- foreach ($this->data as $actionType => $actionData) {
- if (isset($actionType)) {
- try {
- if ($this->DEBUG) {
- error_log("exec: " . $actionType);
- }
- switch ($actionType) {
- case "load":
- $result = $this->loadContacts($actionType, $actionData);
- break;
- case "import":
- $result = $this->importContacts($actionType, $actionData);
- break;
- case "export":
- $result = $this->exportContacts($actionType, $actionData);
- break;
- case "importattachment":
- $result = $this->getAttachmentPath($actionType, $actionData);
- break;
- default:
- $this->handleUnknownActionType($actionType);
- }
-
- } catch (MAPIException $e) {
- if ($this->DEBUG) {
- error_log("mapi exception: " . $e->getMessage());
- }
- } catch (Exception $e) {
- if ($this->DEBUG) {
- error_log("exception: " . $e->getMessage());
- }
- }
- }
- }
-
- return $result;
- }
-
- /**
- * Generates a random string with variable length.
- * @param $length the lenght of the generated string
- * @return string a random string
- */
- private 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;
- }
-
- /**
- * Add an attachment to the give contact
- * @param $actionType
- * @param $actionData
- */
- private function importContacts($actionType, $actionData)
- {
-
- // Get uploaded vcf path
- $vcffile = false;
- if (isset($actionData["vcf_filepath"])) {
- $vcffile = $actionData["vcf_filepath"];
- }
-
- // Get store id
- $storeid = false;
- if (isset($actionData["storeid"])) {
- $storeid = $actionData["storeid"];
- }
-
- // Get folder entryid
- $folderid = false;
- if (isset($actionData["folderid"])) {
- $folderid = $actionData["folderid"];
- }
-
- // Get uids
- $uids = array();
- if (isset($actionData["uids"])) {
- $uids = $actionData["uids"];
- }
-
- $response = array();
- $error = false;
- $error_msg = "";
-
- // parse the vcf file a last time...
- $parser = null;
- try {
- $parser = VCardParser::parseFromFile($vcffile);
- } catch (Exception $e) {
- $error = true;
- $error_msg = $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));
-
- $importall = false;
- if (count($uids) == count($contacts)) {
- $importall = true;
- }
-
- $propValuesMAPI = array();
- $properties = $this->getProperties();
- $properties = $this->replaceStringPropertyTags($store, $properties);
- $count = 0;
-
- // 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))) {
- // parse the arraykeys
- // TODO: this is very slow...
- foreach ($contact as $key => $value) {
- if ($key !== "internal_fields") {
- $propValuesMAPI[$properties[$key]] = $value;
- }
- }
-
- $propValuesMAPI[$properties["message_class"]] = "IPM.Contact";
- $propValuesMAPI[$properties["icon_index"]] = "512";
- $message = mapi_folder_createmessage($folder);
-
-
- if (isset($contact["internal_fields"]["x_photo_path"])) {
- $propValuesMAPI[$properties["picture"]] = 1; // contact has an image
-
- // import the photo
- $contactPicture = file_get_contents($contact["internal_fields"]["x_photo_path"]);
- $attach = mapi_message_createattach($message);
-
- // Set properties of the attachment
- $propValuesIMG = array(
- PR_ATTACH_SIZE => strlen($contactPicture),
- PR_ATTACH_LONG_FILENAME => 'ContactPicture.jpg',
- PR_ATTACHMENT_HIDDEN => false,
- PR_DISPLAY_NAME => 'ContactPicture.jpg',
- PR_ATTACH_METHOD => ATTACH_BY_VALUE,
- PR_ATTACH_MIME_TAG => 'image/jpeg',
- PR_ATTACHMENT_CONTACTPHOTO => true,
- PR_ATTACH_DATA_BIN => $contactPicture,
- PR_ATTACHMENT_FLAGS => 1,
- PR_ATTACH_EXTENSION_A => '.jpg',
- PR_ATTACH_NUM => 1
- );
-
- mapi_setprops($attach, $propValuesIMG);
- mapi_savechanges($attach);
- if ($this->DEBUG) {
- error_log("Contactpicture imported!");
- }
-
- if (mapi_last_hresult() > 0) {
- error_log("Error saving attach to contact: " . get_mapi_error_name());
- }
- }
-
- mapi_setprops($message, $propValuesMAPI);
- mapi_savechanges($message);
- if ($this->DEBUG) {
- error_log("New contact added: \"" . $propValuesMAPI[$properties["display_name"]] . "\".\n");
- }
- $count++;
- }
- }
-
- $response['status'] = true;
- $response['count'] = $count;
- $response['message'] = "";
-
- } else {
- $response['status'] = false;
- $response['count'] = 0;
- $response['message'] = $error ? $error_msg : "VCF file empty!";
- }
-
- $this->addActionData($actionType, $response);
- $GLOBALS["bus"]->addData($this->getResponseData());
- }
-
- /**
- * Get a property from the array.
- * @param $props
- * @param $propname
- * @return string
- */
- private function getProp($props, $propname)
- {
- $p = $this->getProperties();
- if (isset($props["props"][$propname])) {
- return $props["props"][$propname];
- }
- return "";
- }
-
- /**
- * Export selected contacts to vCard.
- * @param $actionType
- * @param $actionData
- * @return bool
- */
- private function exportContacts($actionType, $actionData)
- {
- // Get store id
- $storeid = false;
- if (isset($actionData["storeid"])) {
- $storeid = $actionData["storeid"];
- }
-
- // Get records
- $records = array();
- if (isset($actionData["records"])) {
- $records = $actionData["records"];
- }
-
- // Get folders
- $folder = false;
- if (isset($actionData["folder"])) {
- $folder = $actionData["folder"];
- }
-
- $response = array();
- $error = false;
- $error_msg = "";
-
- // write csv
- $token = $this->randomstring(16);
- $file = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "vcf_" . $token . ".vcf";
- file_put_contents($file, "");
-
- $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
- if ($store) {
- // load folder first
- if ($folder !== false) {
- $mapifolder = mapi_msgstore_openentry($store, hex2bin($folder));
-
- $table = mapi_folder_getcontentstable($mapifolder);
- $list = mapi_table_queryallrows($table, array(PR_ENTRYID));
-
- foreach ($list as $item) {
- $records[] = bin2hex($item[PR_ENTRYID]);
- }
- }
- for ($index = 0, $count = count($records); $index < $count; $index++) {
- // define vcard
- $vcard = new VCard();
-
- $message = mapi_msgstore_openentry($store, hex2bin($records[$index]));
-
- // get message properties.
- $properties = $GLOBALS['properties']->getContactProperties();
- $plaintext = true;
- $messageProps = $GLOBALS['operations']->getMessageProps($store, $message, $properties, $plaintext);
-
- // define variables
- $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);
-
- $company = $this->getProp($messageProps, "company_name");
- if (!empty($company)) {
- $vcard->addCompany($company);
- }
-
- $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);
- }
- $mail = $this->getProp($messageProps, "email_address_2");
- if (!empty($mail)) {
- $vcard->addEmail($mail);
- }
- $mail = $this->getProp($messageProps, "email_address_3");
- if (!empty($mail)) {
- $vcard->addEmail($mail);
- }
-
- // PHONE
- $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, "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, "pager_telephone_number");
- if (!empty($wphone)) {
- $vcard->addPhoneNumber($wphone, 'PAGER');
- }
- $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");
- }
- $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");
- }
- $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");
- }
-
- // MISC
- $url = $this->getProp($messageProps, "webpage");
- if (!empty($url)) {
- $vcard->addURL($url);
- }
-
- $bday = $this->getProp($messageProps, "birthday");
- if (!empty($bday)) {
- $vcard->addBirthday(date("Y-m-d", $bday));
- }
-
- $notes = $this->getProp($messageProps, "body");
- if (!empty($notes)) {
- $vcard->addNote($notes);
- }
-
- $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"];
- 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);
- }
- }
- // write combined vcf
- file_put_contents($file, file_get_contents($file) . $vcard->getOutput());
- }
- } else {
- return false;
- }
-
- if (count($records) > 0) {
- $response['status'] = true;
- $response['download_token'] = $token;
- $response['filename'] = count($records) . "contacts.vcf";
- } else {
- $response['status'] = false;
- $response['message'] = "No contacts found. Export skipped!";
- }
-
- $this->addActionData($actionType, $response);
- $GLOBALS["bus"]->addData($this->getResponseData());
- }
-
- /**
- * 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
- */
- private function getAttachmentByAttachNum($message, $attachNum)
- {
- // open the attachment
- $attachment = mapi_message_openattach($message, $attachNum);
-
- return $attachment;
- }
-
- /**
- * 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)
- {
- // Check if the attachment is opened
- if ($attachment) {
- // Open a stream to get the attachment data
- $stream = mapi_openproperty($attachment, PR_ATTACH_DATA_BIN, IID_IStream, 0, 0);
- $stat = mapi_stream_stat($stream);
-
- // Read the attachment content from the stream
- $body = '';
- for ($i = 0; $i < $stat['cb']; $i += BLOCK_SIZE) {
- $body .= mapi_stream_read($stream, BLOCK_SIZE);
- }
-
- file_put_contents($temppath, $body);
- }
- }
-
- /**
- * Replace String Property Tags
- * @param $store
- * @param $properties
- * @return array
- */
- private function replaceStringPropertyTags($store, $properties)
- {
- $newProperties = array();
-
- $ids = array("name" => array(), "id" => array(), "guid" => array(), "type" => array()); // this array stores all the information needed to retrieve a named property
- $num = 0;
-
- // caching
- $guids = array();
-
- foreach ($properties as $name => $val) {
- if (is_string($val)) {
- $split = explode(":", $val);
-
- if (count($split) != 3) { // invalid string, ignore
- trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE);
- continue;
- }
-
- if (substr($split[2], 0, 2) == "0x") {
- $id = hexdec(substr($split[2], 2));
- } else {
- $id = $split[2];
- }
-
- // have we used this guid before?
- if (!defined($split[1])) {
- if (!array_key_exists($split[1], $guids)) {
- $guids[$split[1]] = makeguid($split[1]);
- }
- $guid = $guids[$split[1]];
- } else {
- $guid = constant($split[1]);
- }
-
- // temp store info about named prop, so we have to call mapi_getidsfromnames just one time
- $ids["name"][$num] = $name;
- $ids["id"][$num] = $id;
- $ids["guid"][$num] = $guid;
- $ids["type"][$num] = $split[0];
- $num++;
- } else {
- // not a named property
- $newProperties[$name] = $val;
- }
- }
-
- if (count($ids["id"]) == 0) {
- return $newProperties;
- }
-
- // get the ids
- $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]);
- foreach ($named as $num => $prop) {
- $newProperties[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop));
- }
-
- return $newProperties;
- }
-
- /**
- * A simple Property map initialization
- *
- * @return [array] the propertyarray
- */
- private function getProperties()
- {
- $properties = array();
-
- $properties["subject"] = PR_SUBJECT;
- $properties["hide_attachments"] = "PT_BOOLEAN:PSETID_Common:0x851";
- $properties["icon_index"] = PR_ICON_INDEX;
- $properties["message_class"] = PR_MESSAGE_CLASS;
- $properties["display_name"] = PR_DISPLAY_NAME;
- $properties["given_name"] = PR_GIVEN_NAME;
- $properties["middle_name"] = PR_MIDDLE_NAME;
- $properties["surname"] = PR_SURNAME;
- $properties["home_telephone_number"] = PR_HOME_TELEPHONE_NUMBER;
- $properties["cellular_telephone_number"] = PR_CELLULAR_TELEPHONE_NUMBER;
- $properties["office_telephone_number"] = PR_OFFICE_TELEPHONE_NUMBER;
- $properties["business_fax_number"] = PR_BUSINESS_FAX_NUMBER;
- $properties["company_name"] = PR_COMPANY_NAME;
- $properties["title"] = PR_TITLE;
- $properties["department_name"] = PR_DEPARTMENT_NAME;
- $properties["office_location"] = PR_OFFICE_LOCATION;
- $properties["profession"] = PR_PROFESSION;
- $properties["manager_name"] = PR_MANAGER_NAME;
- $properties["assistant"] = PR_ASSISTANT;
- $properties["nickname"] = PR_NICKNAME;
- $properties["display_name_prefix"] = PR_DISPLAY_NAME_PREFIX;
- $properties["spouse_name"] = PR_SPOUSE_NAME;
- $properties["generation"] = PR_GENERATION;
- $properties["birthday"] = PR_BIRTHDAY;
- $properties["wedding_anniversary"] = PR_WEDDING_ANNIVERSARY;
- $properties["sensitivity"] = PR_SENSITIVITY;
- $properties["fileas"] = "PT_STRING8:PSETID_Address:0x8005";
- $properties["fileas_selection"] = "PT_LONG:PSETID_Address:0x8006";
- $properties["email_address_1"] = "PT_STRING8:PSETID_Address:0x8083";
- $properties["email_address_display_name_1"] = "PT_STRING8:PSETID_Address:0x8080";
- $properties["email_address_display_name_email_1"] = "PT_STRING8:PSETID_Address:0x8084";
- $properties["email_address_type_1"] = "PT_STRING8:PSETID_Address:0x8082";
- $properties["email_address_2"] = "PT_STRING8:PSETID_Address:0x8093";
- $properties["email_address_display_name_2"] = "PT_STRING8:PSETID_Address:0x8090";
- $properties["email_address_display_name_email_2"] = "PT_STRING8:PSETID_Address:0x8094";
- $properties["email_address_type_2"] = "PT_STRING8:PSETID_Address:0x8092";
- $properties["email_address_3"] = "PT_STRING8:PSETID_Address:0x80a3";
- $properties["email_address_display_name_3"] = "PT_STRING8:PSETID_Address:0x80a0";
- $properties["email_address_display_name_email_3"] = "PT_STRING8:PSETID_Address:0x80a4";
- $properties["email_address_type_3"] = "PT_STRING8:PSETID_Address:0x80a2";
- $properties["home_address"] = "PT_STRING8:PSETID_Address:0x801a";
- $properties["business_address"] = "PT_STRING8:PSETID_Address:0x801b";
- $properties["other_address"] = "PT_STRING8:PSETID_Address:0x801c";
- $properties["mailing_address"] = "PT_LONG:PSETID_Address:0x8022";
- $properties["im"] = "PT_STRING8:PSETID_Address:0x8062";
- $properties["webpage"] = "PT_STRING8:PSETID_Address:0x802b";
- $properties["business_home_page"] = PR_BUSINESS_HOME_PAGE;
- $properties["email_address_entryid_1"] = "PT_BINARY:PSETID_Address:0x8085";
- $properties["email_address_entryid_2"] = "PT_BINARY:PSETID_Address:0x8095";
- $properties["email_address_entryid_3"] = "PT_BINARY:PSETID_Address:0x80a5";
- $properties["address_book_mv"] = "PT_MV_LONG:PSETID_Address:0x8028";
- $properties["address_book_long"] = "PT_LONG:PSETID_Address:0x8029";
- $properties["oneoff_members"] = "PT_MV_BINARY:PSETID_Address:0x8054";
- $properties["members"] = "PT_MV_BINARY:PSETID_Address:0x8055";
- $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
- $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
- $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
- $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
- $properties["last_modification_time"] = PR_LAST_MODIFICATION_TIME;
-
- // Detailed contacts properties
- // Properties for phone numbers
- $properties["assistant_telephone_number"] = PR_ASSISTANT_TELEPHONE_NUMBER;
- $properties["business2_telephone_number"] = PR_BUSINESS2_TELEPHONE_NUMBER;
- $properties["callback_telephone_number"] = PR_CALLBACK_TELEPHONE_NUMBER;
- $properties["car_telephone_number"] = PR_CAR_TELEPHONE_NUMBER;
- $properties["company_telephone_number"] = PR_COMPANY_MAIN_PHONE_NUMBER;
- $properties["home2_telephone_number"] = PR_HOME2_TELEPHONE_NUMBER;
- $properties["home_fax_number"] = PR_HOME_FAX_NUMBER;
- $properties["isdn_number"] = PR_ISDN_NUMBER;
- $properties["other_telephone_number"] = PR_OTHER_TELEPHONE_NUMBER;
- $properties["pager_telephone_number"] = PR_PAGER_TELEPHONE_NUMBER;
- $properties["primary_fax_number"] = PR_PRIMARY_FAX_NUMBER;
- $properties["primary_telephone_number"] = PR_PRIMARY_TELEPHONE_NUMBER;
- $properties["radio_telephone_number"] = PR_RADIO_TELEPHONE_NUMBER;
- $properties["telex_telephone_number"] = PR_TELEX_NUMBER;
- $properties["ttytdd_telephone_number"] = PR_TTYTDD_PHONE_NUMBER;
- $properties["business_telephone_number"] = PR_BUSINESS_TELEPHONE_NUMBER;
-
- // Additional fax properties
- $properties["fax_1_address_type"] = "PT_STRING8:PSETID_Address:0x80B2";
- $properties["fax_1_email_address"] = "PT_STRING8:PSETID_Address:0x80B3";
- $properties["fax_1_original_display_name"] = "PT_STRING8:PSETID_Address:0x80B4";
- $properties["fax_1_original_entryid"] = "PT_BINARY:PSETID_Address:0x80B5";
- $properties["fax_2_address_type"] = "PT_STRING8:PSETID_Address:0x80C2";
- $properties["fax_2_email_address"] = "PT_STRING8:PSETID_Address:0x80C3";
- $properties["fax_2_original_display_name"] = "PT_STRING8:PSETID_Address:0x80C4";
- $properties["fax_2_original_entryid"] = "PT_BINARY:PSETID_Address:0x80C5";
- $properties["fax_3_address_type"] = "PT_STRING8:PSETID_Address:0x80D2";
- $properties["fax_3_email_address"] = "PT_STRING8:PSETID_Address:0x80D3";
- $properties["fax_3_original_display_name"] = "PT_STRING8:PSETID_Address:0x80D4";
- $properties["fax_3_original_entryid"] = "PT_BINARY:PSETID_Address:0x80D5";
-
- // Properties for addresses
- // Home address
- $properties["home_address_street"] = PR_HOME_ADDRESS_STREET;
- $properties["home_address_city"] = PR_HOME_ADDRESS_CITY;
- $properties["home_address_state"] = PR_HOME_ADDRESS_STATE_OR_PROVINCE;
- $properties["home_address_postal_code"] = PR_HOME_ADDRESS_POSTAL_CODE;
- $properties["home_address_country"] = PR_HOME_ADDRESS_COUNTRY;
- // Other address
- $properties["other_address_street"] = PR_OTHER_ADDRESS_STREET;
- $properties["other_address_city"] = PR_OTHER_ADDRESS_CITY;
- $properties["other_address_state"] = PR_OTHER_ADDRESS_STATE_OR_PROVINCE;
- $properties["other_address_postal_code"] = PR_OTHER_ADDRESS_POSTAL_CODE;
- $properties["other_address_country"] = PR_OTHER_ADDRESS_COUNTRY;
- // Business address
- $properties["business_address_street"] = "PT_STRING8:PSETID_Address:0x8045";
- $properties["business_address_city"] = "PT_STRING8:PSETID_Address:0x8046";
- $properties["business_address_state"] = "PT_STRING8:PSETID_Address:0x8047";
- $properties["business_address_postal_code"] = "PT_STRING8:PSETID_Address:0x8048";
- $properties["business_address_country"] = "PT_STRING8:PSETID_Address:0x8049";
- // Mailing address
- $properties["country"] = PR_COUNTRY;
- $properties["city"] = PR_LOCALITY;
- $properties["postal_address"] = PR_POSTAL_ADDRESS;
- $properties["postal_code"] = PR_POSTAL_CODE;
- $properties["state"] = PR_STATE_OR_PROVINCE;
- $properties["street"] = PR_STREET_ADDRESS;
- // Special Date such as birthday n anniversary appoitment's entryid is store
- $properties["birthday_eventid"] = "PT_BINARY:PSETID_Address:0x804D";
- $properties["anniversary_eventid"] = "PT_BINARY:PSETID_Address:0x804E";
-
- $properties["notes"] = PR_BODY;
-
- // hasimage
- $properties["picture"] = "PT_BOOLEAN:{00062004-0000-0000-C000-000000000046}:0x8015";
-
- return $properties;
- }
-
- /**
- * Function that parses the uploaded vcf file and posts it via json
- * @param $actionType
- * @param $actionData
- */
- private function loadContacts($actionType, $actionData)
- {
- $error = false;
- $error_msg = "";
-
- if (is_readable($actionData["vcf_filepath"])) {
- $parser = null;
-
- try {
- $parser = VCardParser::parseFromFile($actionData["vcf_filepath"]);
- } catch (Exception $e) {
- $error = true;
- $error_msg = $e->getMessage();
- }
- if ($error) {
- $response['status'] = false;
- $response['message'] = $error_msg;
- } else {
- if (iterator_count($parser) == 0) {
- $response['status'] = false;
- $response['message'] = "No contacts in vcf file";
- } else {
- $response['status'] = true;
- $response['parsed_file'] = $actionData["vcf_filepath"];
- $response['parsed'] = array(
- 'contacts' => $this->parseContactsToArray($parser)
- );
- }
- }
- } else {
- $response['status'] = false;
- $response['message'] = "File could not be read by server";
- }
-
- $this->addActionData($actionType, $response);
- $GLOBALS["bus"]->addData($this->getResponseData());
-
- if ($this->DEBUG) {
- error_log("parsing done, bus data written!");
- }
- }
-
- /**
- * Create a array with contacts
- *
- * @param contacts vcard or csv contacts
- * @param csv optional, true if contacts are csv contacts
- * @return array parsed contacts
- * @private
- */
- private function parseContactsToArray($contacts, $csv = false)
- {
- $carr = array();
-
- if (!$csv) {
- foreach ($contacts as $Index => $vCard) {
- $properties = array();
- if (isset($vCard->fullname)) {
- $properties["display_name"] = $vCard->fullname;
- $properties["fileas"] = $vCard->fullname;
- } elseif (!isset($vCard->organization)) {
- error_log("Skipping entry! No fullname/organization given.");
- continue;
- }
-
- $properties["hide_attachments"] = true;
-
- //uid - used for front/backend communication
- $properties["internal_fields"] = array();
- $properties["internal_fields"]["contact_uid"] = base64_encode($Index . $properties["fileas"]);
-
- $properties["given_name"] = $vCard->firstname;
- $properties["middle_name"] = $vCard->additional;
- $properties["surname"] = $vCard->lastname;
- $properties["display_name_prefix"] = $vCard->prefix;
-
- if (isset($vCard->phone) && count($vCard->phone) > 0) {
- foreach ($vCard->phone as $type => $number) {
- $number = $number[0]; // we only can store one number
- if ($this->startswith(strtolower($type), "home") || strtolower($type) === "default") {
- $properties["home_telephone_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "cell")) {
- $properties["cellular_telephone_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "work")) {
- $properties["business_telephone_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "fax")) {
- $properties["business_fax_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "pager")) {
- $properties["pager_telephone_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "isdn")) {
- $properties["isdn_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "car")) {
- $properties["car_telephone_number"] = $number;
- } else {
- if ($this->startswith(strtolower($type), "modem")) {
- $properties["ttytdd_telephone_number"] = $number;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- if (isset($vCard->email) && count($vCard->email) > 0) {
- $emailcount = 0;
- $properties["address_book_long"] = 0;
- foreach ($vCard->email as $type => $email) {
- foreach ($email as $mail) {
- $fileas = $mail;
- if (isset($properties["fileas"]) && !empty($properties["fileas"])) {
- $fileas = $properties["fileas"]; // set to real name
- }
-
- // we only have storage for 3 mail addresses!
- /**
- * type of email address address_book_mv address_book_long
- * email1 0 1 (0x00000001)
- * email2 1 2 (0x00000002)
- * email3 2 4 (0x00000004)
- * fax2(business fax) 3 8 (0x00000008)
- * fax3(home fax) 4 16 (0x00000010)
- * fax1(primary fax) 5 32 (0x00000020)
- *
- * address_book_mv is a multivalued property so all the values are passed in array
- * address_book_long stores sum of the flags
- * these both properties should be in sync always
- */
- switch ($emailcount) {
- case 0:
- $properties["email_address_1"] = $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_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_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
- break;
- default:
- break;
- }
- $emailcount++;
- }
- }
- }
- if (isset($vCard->organization)) {
- $properties["company_name"] = $vCard->organization;
- if (empty($properties["display_name"])) {
- $properties["display_name"] = $vCard->organization; // if we have no displayname - use the company name as displayname
- $properties["fileas"] = $vCard->organization;
- }
- }
- if (isset($vCard->title)) {
- $properties["title"] = $vCard->title;
- }
- if (isset($vCard->url) && count($vCard->url) > 0) {
- foreach ($vCard->url as $type => $url) {
- $url = $url[0]; // only 1 webaddress per type
- $properties["webpage"] = $url;
- break; // we can only store on url
- }
- }
- if (isset($vCard->address) && count($vCard->address) > 0) {
-
- foreach ($vCard->address as $type => $address) {
- $address = $address[0]; // we only can store one address per type
- if ($this->startswith(strtolower($type), "work")) {
- $properties["business_address_street"] = $address->street;
- if (!empty($address->extended)) {
- $properties["business_address_street"] .= "\n" . $address->extended;
- }
- $properties["business_address_city"] = $address->city;
- $properties["business_address_state"] = $address->region;
- $properties["business_address_postal_code"] = $address->zip;
- $properties["business_address_country"] = $address->country;
- $properties["business_address"] = $this->buildAddressString($properties["business_address_street"], $address->zip, $address->city, $address->region, $address->country);
- } else {
- if ($this->startswith(strtolower($type), "home")) {
- $properties["home_address_street"] = $address->street;
- if (!empty($address->extended)) {
- $properties["home_address_street"] .= "\n" . $address->extended;
- }
- $properties["home_address_city"] = $address->city;
- $properties["home_address_state"] = $address->region;
- $properties["home_address_postal_code"] = $address->zip;
- $properties["home_address_country"] = $address->country;
- $properties["home_address"] = $this->buildAddressString($properties["home_address_street"], $address->zip, $address->city, $address->region, $address->country);
- } else {
- $properties["other_address_street"] = $address->street;
- if (!empty($address->extended)) {
- $properties["other_address_street"] .= "\n" . $address->extended;
- }
- $properties["other_address_city"] = $address->city;
- $properties["other_address_state"] = $address->region;
- $properties["other_address_postal_code"] = $address->zip;
- $properties["other_address_country"] = $address->country;
- $properties["other_address"] = $this->buildAddressString($properties["other_address_street"], $address->zip, $address->city, $address->region, $address->country);
- }
- }
- }
- }
- if (isset($vCard->birthday)) {
- $properties["birthday"] = $vCard->birthday->getTimestamp();
- }
- if (isset($vCard->note)) {
- $properties["notes"] = $vCard->note;
- }
- if (isset($vCard->rawPhoto) || isset($vCard->photo)) {
- if (!is_writable(TMP_PATH . "/")) {
- error_log("Can not write to export tmp directory!");
- } else {
- $tmppath = TMP_PATH . "/" . $this->randomstring(15);
- if (isset($vCard->rawPhoto)) {
- if (file_put_contents($tmppath, $vCard->rawPhoto)) {
- $properties["internal_fields"]["x_photo_path"] = $tmppath;
- }
- } elseif (isset($vCard->photo)) {
- if ($this->startswith(strtolower($vCard->photo), "http://") || $this->startswith(strtolower($vCard->photo), "https://")) { // check if it starts with http
- $ctx = stream_context_create(array('http' =>
- array(
- 'timeout' => 3, //3 Seconds timout
- )
- ));
-
- if (file_put_contents($tmppath, file_get_contents($vCard->photo, false, $ctx))) {
- $properties["internal_fields"]["x_photo_path"] = $tmppath;
- }
- } else {
- error_log("Invalid photo url: " . $vCard->photo);
- }
- }
- }
- }
- array_push($carr, $properties);
- }
- } else {
- error_log("csv parsing not implemented");
- }
-
- return $carr;
- }
-
- /**
- * Generate the whole addressstring
- *
- * @param street
- * @param zip
- * @param city
- * @param state
- * @param country
- * @return string the concatinated address string
- * @private
- */
- private function buildAddressString($street, $zip, $city, $state, $country)
- {
- $out = "";
-
- if (isset($country) && $street != "") {
- $out = $country;
- }
-
- $zcs = "";
- if (isset($zip) && $zip != "") {
- $zcs = $zip;
- }
- if (isset($city) && $city != "") {
- $zcs .= (($zcs) ? " " : "") . $city;
- }
- if (isset($state) && $state != "") {
- $zcs .= (($zcs) ? " " : "") . $state;
- }
- if ($zcs) {
- $out = $zcs . "\n" . $out;
- }
-
- if (isset($street) && $street != "") {
- $out = $street . (($out) ? "\n\n" . $out : "");
- }
-
- return $out;
- }
-
- /**
- * Store the file to a temporary directory
- * @param $actionType
- * @param $actionData
- * @private
- */
- private function getAttachmentPath($actionType, $actionData)
- {
- // Get store id
- $storeid = false;
- if (isset($actionData["store"])) {
- $storeid = $actionData["store"];
- }
-
- // Get message entryid
- $entryid = false;
- if (isset($actionData["entryid"])) {
- $entryid = $actionData["entryid"];
- }
-
- // Check which type isset
- $openType = "attachment";
-
- // Get number of attachment which should be opened.
- $attachNum = false;
- if (isset($actionData["attachNum"])) {
- $attachNum = $actionData["attachNum"];
- }
-
- // Check if storeid and entryid isset
- if ($storeid && $entryid) {
- // Open the store
- $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
-
- if ($store) {
- // Open the message
- $message = mapi_msgstore_openentry($store, hex2bin($entryid));
-
- if ($message) {
- $attachment = false;
-
- // Check if attachNum isset
- if ($attachNum) {
- // 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) {
- // Open the object in the attachment
- $message = mapi_attach_openobj($tempattach);
- }
- }
-
- // Open the attachment
- $attachment = mapi_message_openattach($message, (int)$attachNum[(count($attachNum) - 1)]);
- }
-
- // Check if the attachment is opened
- if ($attachment) {
-
- // Get the props of the attachment
- $props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
- // Content Type
- $contentType = "application/octet-stream";
- // Filename
- $filename = "ERROR";
-
- // Set filename
- if (isset($props[PR_ATTACH_LONG_FILENAME])) {
- $filename = $props[PR_ATTACH_LONG_FILENAME];
- } else {
- if (isset($props[PR_ATTACH_FILENAME])) {
- $filename = $props[PR_ATTACH_FILENAME];
- } else {
- if (isset($props[PR_DISPLAY_NAME])) {
- $filename = $props[PR_DISPLAY_NAME];
- }
- }
- }
-
- // Set content type
- if (isset($props[PR_ATTACH_MIME_TAG])) {
- $contentType = $props[PR_ATTACH_MIME_TAG];
- } else {
- // Parse the extension of the filename to get the content type
- if (strrpos($filename, ".") !== false) {
- $extension = strtolower(substr($filename, strrpos($filename, ".")));
- $contentType = "application/octet-stream";
- if (is_readable("mimetypes.dat")) {
- $fh = fopen("mimetypes.dat", "r");
- $ext_found = false;
- while (!feof($fh) && !$ext_found) {
- $line = fgets($fh);
- preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result);
- if ($extension == $result[1]) {
- $ext_found = true;
- $contentType = $result[2];
- }
- }
- fclose($fh);
- }
- }
- }
-
-
- $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');
- $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));
- }
- fclose($fhandle);
-
- $response = array();
- $response['tmpname'] = $tmpname;
- $response['filename'] = $filename;
- $response['status'] = true;
- $this->addActionData($actionType, $response);
- $GLOBALS["bus"]->addData($this->getResponseData());
- }
- }
- } else {
- $response['status'] = false;
- $response['message'] = "Store could not be opened!";
- $this->addActionData($actionType, $response);
- $GLOBALS["bus"]->addData($this->getResponseData());
- }
- } else {
- $response['status'] = false;
- $response['message'] = "Wrong call, store and entryid have to be set!";
- $this->addActionData($actionType, $response);
- $GLOBALS["bus"]->addData($this->getResponseData());
- }
- }
-
- /**
- * Check if string starts with other string.
- * @param $haystack
- * @param $needle
- * @return bool
- */
- private function startswith($haystack, $needle)
- {
- $haystack = str_replace("type=", "", $haystack); // remove type from string
- return substr($haystack, 0, strlen($needle)) === $needle;
- }
+ private $DEBUG = false; // enable error_log debugging
+
+ /**
+ * @constructor
+ * @param $id
+ * @param $data
+ */
+ public function __construct($id, $data)
+ {
+ parent::__construct($id, $data);
+ }
+
+ /**
+ * Executes all the actions in the $data variable.
+ * Exception part is used for authentication errors also
+ * @return boolean true on success or false on failure.
+ */
+ public function execute()
+ {
+ $result = false;
+
+ if (!$this->DEBUG) {
+ /* disable error printing - otherwise json communication might break... */
+ ini_set('display_errors', '0');
+ }
+
+ foreach ($this->data as $actionType => $actionData) {
+ if (isset($actionType)) {
+ try {
+ if ($this->DEBUG) {
+ error_log("exec: " . $actionType);
+ }
+ switch ($actionType) {
+ case "load":
+ $result = $this->loadContacts($actionType, $actionData);
+ break;
+ case "import":
+ $result = $this->importContacts($actionType, $actionData);
+ break;
+ case "export":
+ $result = $this->exportContacts($actionType, $actionData);
+ break;
+ case "importattachment":
+ $result = $this->getAttachmentPath($actionType, $actionData);
+ break;
+ default:
+ $this->handleUnknownActionType($actionType);
+ }
+
+ } catch (MAPIException $e) {
+ if ($this->DEBUG) {
+ error_log("mapi exception: " . $e->getMessage());
+ }
+ } catch (Exception $e) {
+ if ($this->DEBUG) {
+ error_log("exception: " . $e->getMessage());
+ }
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Generates a random string with variable length.
+ * @param $length the lenght of the generated string
+ * @return string a random string
+ */
+ private 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;
+ }
+
+ /**
+ * Add an attachment to the give contact
+ * @param $actionType
+ * @param $actionData
+ */
+ private function importContacts($actionType, $actionData)
+ {
+
+ // Get uploaded vcf path
+ $vcffile = false;
+ if (isset($actionData["vcf_filepath"])) {
+ $vcffile = $actionData["vcf_filepath"];
+ }
+
+ // Get store id
+ $storeid = false;
+ if (isset($actionData["storeid"])) {
+ $storeid = $actionData["storeid"];
+ }
+
+ // Get folder entryid
+ $folderid = false;
+ if (isset($actionData["folderid"])) {
+ $folderid = $actionData["folderid"];
+ }
+
+ // Get uids
+ $uids = array();
+ if (isset($actionData["uids"])) {
+ $uids = $actionData["uids"];
+ }
+
+ $response = array();
+ $error = false;
+ $error_msg = "";
+
+ // parse the vcf file a last time...
+ $parser = null;
+ try {
+ $parser = VCardParser::parseFromFile($vcffile);
+ } catch (Exception $e) {
+ $error = true;
+ $error_msg = $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));
+
+ $importall = false;
+ if (count($uids) == count($contacts)) {
+ $importall = true;
+ }
+
+ $propValuesMAPI = array();
+ $properties = $this->getProperties();
+ $properties = $this->replaceStringPropertyTags($store, $properties);
+ $count = 0;
+
+ // 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))) {
+ // parse the arraykeys
+ // TODO: this is very slow...
+ foreach ($contact as $key => $value) {
+ if ($key !== "internal_fields") {
+ $propValuesMAPI[$properties[$key]] = $value;
+ }
+ }
+
+ $propValuesMAPI[$properties["message_class"]] = "IPM.Contact";
+ $propValuesMAPI[$properties["icon_index"]] = "512";
+ $message = mapi_folder_createmessage($folder);
+
+
+ if (isset($contact["internal_fields"]["x_photo_path"])) {
+ $propValuesMAPI[$properties["picture"]] = 1; // contact has an image
+
+ // import the photo
+ $contactPicture = file_get_contents($contact["internal_fields"]["x_photo_path"]);
+ $attach = mapi_message_createattach($message);
+
+ // Set properties of the attachment
+ $propValuesIMG = array(
+ PR_ATTACH_SIZE => strlen($contactPicture),
+ PR_ATTACH_LONG_FILENAME => 'ContactPicture.jpg',
+ PR_ATTACHMENT_HIDDEN => false,
+ PR_DISPLAY_NAME => 'ContactPicture.jpg',
+ PR_ATTACH_METHOD => ATTACH_BY_VALUE,
+ PR_ATTACH_MIME_TAG => 'image/jpeg',
+ PR_ATTACHMENT_CONTACTPHOTO => true,
+ PR_ATTACH_DATA_BIN => $contactPicture,
+ PR_ATTACHMENT_FLAGS => 1,
+ PR_ATTACH_EXTENSION_A => '.jpg',
+ PR_ATTACH_NUM => 1
+ );
+
+ mapi_setprops($attach, $propValuesIMG);
+ mapi_savechanges($attach);
+ if ($this->DEBUG) {
+ error_log("Contactpicture imported!");
+ }
+
+ if (mapi_last_hresult() > 0) {
+ error_log("Error saving attach to contact: " . get_mapi_error_name());
+ }
+ }
+
+ mapi_setprops($message, $propValuesMAPI);
+ mapi_savechanges($message);
+ if ($this->DEBUG) {
+ error_log("New contact added: \"" . $propValuesMAPI[$properties["display_name"]] . "\".\n");
+ }
+ $count++;
+ }
+ }
+
+ $response['status'] = true;
+ $response['count'] = $count;
+ $response['message'] = "";
+
+ } else {
+ $response['status'] = false;
+ $response['count'] = 0;
+ $response['message'] = $error ? $error_msg : dgettext("plugin_contactimporter", "VCF file is empty!");
+ }
+
+ $this->addActionData($actionType, $response);
+ $GLOBALS["bus"]->addData($this->getResponseData());
+ }
+
+ /**
+ * Get a property from the array.
+ * @param $props
+ * @param $propname
+ * @return string
+ */
+ private function getProp($props, $propname)
+ {
+ $p = $this->getProperties();
+ if (isset($props["props"][$propname])) {
+ return $props["props"][$propname];
+ }
+ return "";
+ }
+
+ /**
+ * Export selected contacts to vCard.
+ * @param $actionType
+ * @param $actionData
+ * @return bool
+ */
+ private function exportContacts($actionType, $actionData)
+ {
+ // Get store id
+ $storeid = false;
+ if (isset($actionData["storeid"])) {
+ $storeid = $actionData["storeid"];
+ }
+
+ // Get records
+ $records = array();
+ if (isset($actionData["records"])) {
+ $records = $actionData["records"];
+ }
+
+ // Get folders
+ $folder = false;
+ if (isset($actionData["folder"])) {
+ $folder = $actionData["folder"];
+ }
+
+ $response = array();
+ $error = false;
+ $error_msg = "";
+
+ // write csv
+ $token = $this->randomstring(16);
+ $file = PLUGIN_CONTACTIMPORTER_TMP_UPLOAD . "vcf_" . $token . ".vcf";
+ file_put_contents($file, "");
+
+ $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
+ if ($store) {
+ // load folder first
+ if ($folder !== false) {
+ $mapifolder = mapi_msgstore_openentry($store, hex2bin($folder));
+
+ $table = mapi_folder_getcontentstable($mapifolder);
+ $list = mapi_table_queryallrows($table, array(PR_ENTRYID));
+
+ foreach ($list as $item) {
+ $records[] = bin2hex($item[PR_ENTRYID]);
+ }
+ }
+ for ($index = 0, $count = count($records); $index < $count; $index++) {
+ // define vcard
+ $vcard = new VCard();
+
+ $message = mapi_msgstore_openentry($store, hex2bin($records[$index]));
+
+ // get message properties.
+ $properties = $GLOBALS['properties']->getContactProperties();
+ $plaintext = true;
+ $messageProps = $GLOBALS['operations']->getMessageProps($store, $message, $properties, $plaintext);
+
+ // define variables
+ $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);
+
+ $company = $this->getProp($messageProps, "company_name");
+ if (!empty($company)) {
+ $vcard->addCompany($company);
+ }
+
+ $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);
+ }
+ $mail = $this->getProp($messageProps, "email_address_2");
+ if (!empty($mail)) {
+ $vcard->addEmail($mail);
+ }
+ $mail = $this->getProp($messageProps, "email_address_3");
+ if (!empty($mail)) {
+ $vcard->addEmail($mail);
+ }
+
+ // PHONE
+ $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, "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, "pager_telephone_number");
+ if (!empty($wphone)) {
+ $vcard->addPhoneNumber($wphone, 'PAGER');
+ }
+ $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");
+ }
+ $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");
+ }
+ $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");
+ }
+
+ // MISC
+ $url = $this->getProp($messageProps, "webpage");
+ if (!empty($url)) {
+ $vcard->addURL($url);
+ }
+
+ $bday = $this->getProp($messageProps, "birthday");
+ if (!empty($bday)) {
+ $vcard->addBirthday(date("Y-m-d", $bday));
+ }
+
+ $notes = $this->getProp($messageProps, "body");
+ if (!empty($notes)) {
+ $vcard->addNote($notes);
+ }
+
+ $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"];
+ 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);
+ }
+ }
+ // write combined vcf
+ file_put_contents($file, file_get_contents($file) . $vcard->getOutput());
+ }
+ } else {
+ return false;
+ }
+
+ if (count($records) > 0) {
+ $response['status'] = true;
+ $response['download_token'] = $token;
+ // TRANSLATORS: Filename suffix for exported files
+ $response['filename'] = count($records) . dgettext("plugin_contactimporter", "_contacts.vcf");
+ } else {
+ $response['status'] = false;
+ $response['message'] = dgettext("plugin_contactimporter", "No contacts found. Export skipped!");
+ }
+
+ $this->addActionData($actionType, $response);
+ $GLOBALS["bus"]->addData($this->getResponseData());
+ }
+
+ /**
+ * 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
+ */
+ private function getAttachmentByAttachNum($message, $attachNum)
+ {
+ // open the attachment
+ $attachment = mapi_message_openattach($message, $attachNum);
+
+ return $attachment;
+ }
+
+ /**
+ * 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)
+ {
+ // Check if the attachment is opened
+ if ($attachment) {
+ // Open a stream to get the attachment data
+ $stream = mapi_openproperty($attachment, PR_ATTACH_DATA_BIN, IID_IStream, 0, 0);
+ $stat = mapi_stream_stat($stream);
+
+ // Read the attachment content from the stream
+ $body = '';
+ for ($i = 0; $i < $stat['cb']; $i += BLOCK_SIZE) {
+ $body .= mapi_stream_read($stream, BLOCK_SIZE);
+ }
+
+ file_put_contents($temppath, $body);
+ }
+ }
+
+ /**
+ * Replace String Property Tags
+ * @param $store
+ * @param $properties
+ * @return array
+ */
+ private function replaceStringPropertyTags($store, $properties)
+ {
+ $newProperties = array();
+
+ $ids = array("name" => array(), "id" => array(), "guid" => array(), "type" => array()); // this array stores all the information needed to retrieve a named property
+ $num = 0;
+
+ // caching
+ $guids = array();
+
+ foreach ($properties as $name => $val) {
+ if (is_string($val)) {
+ $split = explode(":", $val);
+
+ if (count($split) != 3) { // invalid string, ignore
+ trigger_error(sprintf("Invalid property: %s \"%s\"", $name, $val), E_USER_NOTICE);
+ continue;
+ }
+
+ if (substr($split[2], 0, 2) == "0x") {
+ $id = hexdec(substr($split[2], 2));
+ } else {
+ $id = $split[2];
+ }
+
+ // have we used this guid before?
+ if (!defined($split[1])) {
+ if (!array_key_exists($split[1], $guids)) {
+ $guids[$split[1]] = makeguid($split[1]);
+ }
+ $guid = $guids[$split[1]];
+ } else {
+ $guid = constant($split[1]);
+ }
+
+ // temp store info about named prop, so we have to call mapi_getidsfromnames just one time
+ $ids["name"][$num] = $name;
+ $ids["id"][$num] = $id;
+ $ids["guid"][$num] = $guid;
+ $ids["type"][$num] = $split[0];
+ $num++;
+ } else {
+ // not a named property
+ $newProperties[$name] = $val;
+ }
+ }
+
+ if (count($ids["id"]) == 0) {
+ return $newProperties;
+ }
+
+ // get the ids
+ $named = mapi_getidsfromnames($store, $ids["id"], $ids["guid"]);
+ foreach ($named as $num => $prop) {
+ $newProperties[$ids["name"][$num]] = mapi_prop_tag(constant($ids["type"][$num]), mapi_prop_id($prop));
+ }
+
+ return $newProperties;
+ }
+
+ /**
+ * A simple Property map initialization
+ *
+ * @return [array] the propertyarray
+ */
+ private function getProperties()
+ {
+ $properties = array();
+
+ $properties["subject"] = PR_SUBJECT;
+ $properties["hide_attachments"] = "PT_BOOLEAN:PSETID_Common:0x851";
+ $properties["icon_index"] = PR_ICON_INDEX;
+ $properties["message_class"] = PR_MESSAGE_CLASS;
+ $properties["display_name"] = PR_DISPLAY_NAME;
+ $properties["given_name"] = PR_GIVEN_NAME;
+ $properties["middle_name"] = PR_MIDDLE_NAME;
+ $properties["surname"] = PR_SURNAME;
+ $properties["home_telephone_number"] = PR_HOME_TELEPHONE_NUMBER;
+ $properties["cellular_telephone_number"] = PR_CELLULAR_TELEPHONE_NUMBER;
+ $properties["office_telephone_number"] = PR_OFFICE_TELEPHONE_NUMBER;
+ $properties["business_fax_number"] = PR_BUSINESS_FAX_NUMBER;
+ $properties["company_name"] = PR_COMPANY_NAME;
+ $properties["title"] = PR_TITLE;
+ $properties["department_name"] = PR_DEPARTMENT_NAME;
+ $properties["office_location"] = PR_OFFICE_LOCATION;
+ $properties["profession"] = PR_PROFESSION;
+ $properties["manager_name"] = PR_MANAGER_NAME;
+ $properties["assistant"] = PR_ASSISTANT;
+ $properties["nickname"] = PR_NICKNAME;
+ $properties["display_name_prefix"] = PR_DISPLAY_NAME_PREFIX;
+ $properties["spouse_name"] = PR_SPOUSE_NAME;
+ $properties["generation"] = PR_GENERATION;
+ $properties["birthday"] = PR_BIRTHDAY;
+ $properties["wedding_anniversary"] = PR_WEDDING_ANNIVERSARY;
+ $properties["sensitivity"] = PR_SENSITIVITY;
+ $properties["fileas"] = "PT_STRING8:PSETID_Address:0x8005";
+ $properties["fileas_selection"] = "PT_LONG:PSETID_Address:0x8006";
+ $properties["email_address_1"] = "PT_STRING8:PSETID_Address:0x8083";
+ $properties["email_address_display_name_1"] = "PT_STRING8:PSETID_Address:0x8080";
+ $properties["email_address_display_name_email_1"] = "PT_STRING8:PSETID_Address:0x8084";
+ $properties["email_address_type_1"] = "PT_STRING8:PSETID_Address:0x8082";
+ $properties["email_address_2"] = "PT_STRING8:PSETID_Address:0x8093";
+ $properties["email_address_display_name_2"] = "PT_STRING8:PSETID_Address:0x8090";
+ $properties["email_address_display_name_email_2"] = "PT_STRING8:PSETID_Address:0x8094";
+ $properties["email_address_type_2"] = "PT_STRING8:PSETID_Address:0x8092";
+ $properties["email_address_3"] = "PT_STRING8:PSETID_Address:0x80a3";
+ $properties["email_address_display_name_3"] = "PT_STRING8:PSETID_Address:0x80a0";
+ $properties["email_address_display_name_email_3"] = "PT_STRING8:PSETID_Address:0x80a4";
+ $properties["email_address_type_3"] = "PT_STRING8:PSETID_Address:0x80a2";
+ $properties["home_address"] = "PT_STRING8:PSETID_Address:0x801a";
+ $properties["business_address"] = "PT_STRING8:PSETID_Address:0x801b";
+ $properties["other_address"] = "PT_STRING8:PSETID_Address:0x801c";
+ $properties["mailing_address"] = "PT_LONG:PSETID_Address:0x8022";
+ $properties["im"] = "PT_STRING8:PSETID_Address:0x8062";
+ $properties["webpage"] = "PT_STRING8:PSETID_Address:0x802b";
+ $properties["business_home_page"] = PR_BUSINESS_HOME_PAGE;
+ $properties["email_address_entryid_1"] = "PT_BINARY:PSETID_Address:0x8085";
+ $properties["email_address_entryid_2"] = "PT_BINARY:PSETID_Address:0x8095";
+ $properties["email_address_entryid_3"] = "PT_BINARY:PSETID_Address:0x80a5";
+ $properties["address_book_mv"] = "PT_MV_LONG:PSETID_Address:0x8028";
+ $properties["address_book_long"] = "PT_LONG:PSETID_Address:0x8029";
+ $properties["oneoff_members"] = "PT_MV_BINARY:PSETID_Address:0x8054";
+ $properties["members"] = "PT_MV_BINARY:PSETID_Address:0x8055";
+ $properties["private"] = "PT_BOOLEAN:PSETID_Common:0x8506";
+ $properties["contacts"] = "PT_MV_STRING8:PSETID_Common:0x853a";
+ $properties["contacts_string"] = "PT_STRING8:PSETID_Common:0x8586";
+ $properties["categories"] = "PT_MV_STRING8:PS_PUBLIC_STRINGS:Keywords";
+ $properties["last_modification_time"] = PR_LAST_MODIFICATION_TIME;
+
+ // Detailed contacts properties
+ // Properties for phone numbers
+ $properties["assistant_telephone_number"] = PR_ASSISTANT_TELEPHONE_NUMBER;
+ $properties["business2_telephone_number"] = PR_BUSINESS2_TELEPHONE_NUMBER;
+ $properties["callback_telephone_number"] = PR_CALLBACK_TELEPHONE_NUMBER;
+ $properties["car_telephone_number"] = PR_CAR_TELEPHONE_NUMBER;
+ $properties["company_telephone_number"] = PR_COMPANY_MAIN_PHONE_NUMBER;
+ $properties["home2_telephone_number"] = PR_HOME2_TELEPHONE_NUMBER;
+ $properties["home_fax_number"] = PR_HOME_FAX_NUMBER;
+ $properties["isdn_number"] = PR_ISDN_NUMBER;
+ $properties["other_telephone_number"] = PR_OTHER_TELEPHONE_NUMBER;
+ $properties["pager_telephone_number"] = PR_PAGER_TELEPHONE_NUMBER;
+ $properties["primary_fax_number"] = PR_PRIMARY_FAX_NUMBER;
+ $properties["primary_telephone_number"] = PR_PRIMARY_TELEPHONE_NUMBER;
+ $properties["radio_telephone_number"] = PR_RADIO_TELEPHONE_NUMBER;
+ $properties["telex_telephone_number"] = PR_TELEX_NUMBER;
+ $properties["ttytdd_telephone_number"] = PR_TTYTDD_PHONE_NUMBER;
+ $properties["business_telephone_number"] = PR_BUSINESS_TELEPHONE_NUMBER;
+
+ // Additional fax properties
+ $properties["fax_1_address_type"] = "PT_STRING8:PSETID_Address:0x80B2";
+ $properties["fax_1_email_address"] = "PT_STRING8:PSETID_Address:0x80B3";
+ $properties["fax_1_original_display_name"] = "PT_STRING8:PSETID_Address:0x80B4";
+ $properties["fax_1_original_entryid"] = "PT_BINARY:PSETID_Address:0x80B5";
+ $properties["fax_2_address_type"] = "PT_STRING8:PSETID_Address:0x80C2";
+ $properties["fax_2_email_address"] = "PT_STRING8:PSETID_Address:0x80C3";
+ $properties["fax_2_original_display_name"] = "PT_STRING8:PSETID_Address:0x80C4";
+ $properties["fax_2_original_entryid"] = "PT_BINARY:PSETID_Address:0x80C5";
+ $properties["fax_3_address_type"] = "PT_STRING8:PSETID_Address:0x80D2";
+ $properties["fax_3_email_address"] = "PT_STRING8:PSETID_Address:0x80D3";
+ $properties["fax_3_original_display_name"] = "PT_STRING8:PSETID_Address:0x80D4";
+ $properties["fax_3_original_entryid"] = "PT_BINARY:PSETID_Address:0x80D5";
+
+ // Properties for addresses
+ // Home address
+ $properties["home_address_street"] = PR_HOME_ADDRESS_STREET;
+ $properties["home_address_city"] = PR_HOME_ADDRESS_CITY;
+ $properties["home_address_state"] = PR_HOME_ADDRESS_STATE_OR_PROVINCE;
+ $properties["home_address_postal_code"] = PR_HOME_ADDRESS_POSTAL_CODE;
+ $properties["home_address_country"] = PR_HOME_ADDRESS_COUNTRY;
+ // Other address
+ $properties["other_address_street"] = PR_OTHER_ADDRESS_STREET;
+ $properties["other_address_city"] = PR_OTHER_ADDRESS_CITY;
+ $properties["other_address_state"] = PR_OTHER_ADDRESS_STATE_OR_PROVINCE;
+ $properties["other_address_postal_code"] = PR_OTHER_ADDRESS_POSTAL_CODE;
+ $properties["other_address_country"] = PR_OTHER_ADDRESS_COUNTRY;
+ // Business address
+ $properties["business_address_street"] = "PT_STRING8:PSETID_Address:0x8045";
+ $properties["business_address_city"] = "PT_STRING8:PSETID_Address:0x8046";
+ $properties["business_address_state"] = "PT_STRING8:PSETID_Address:0x8047";
+ $properties["business_address_postal_code"] = "PT_STRING8:PSETID_Address:0x8048";
+ $properties["business_address_country"] = "PT_STRING8:PSETID_Address:0x8049";
+ // Mailing address
+ $properties["country"] = PR_COUNTRY;
+ $properties["city"] = PR_LOCALITY;
+ $properties["postal_address"] = PR_POSTAL_ADDRESS;
+ $properties["postal_code"] = PR_POSTAL_CODE;
+ $properties["state"] = PR_STATE_OR_PROVINCE;
+ $properties["street"] = PR_STREET_ADDRESS;
+ // Special Date such as birthday n anniversary appoitment's entryid is store
+ $properties["birthday_eventid"] = "PT_BINARY:PSETID_Address:0x804D";
+ $properties["anniversary_eventid"] = "PT_BINARY:PSETID_Address:0x804E";
+
+ $properties["notes"] = PR_BODY;
+
+ // hasimage
+ $properties["picture"] = "PT_BOOLEAN:{00062004-0000-0000-C000-000000000046}:0x8015";
+
+ return $properties;
+ }
+
+ /**
+ * Function that parses the uploaded vcf file and posts it via json
+ * @param $actionType
+ * @param $actionData
+ */
+ private function loadContacts($actionType, $actionData)
+ {
+ $error = false;
+ $error_msg = "";
+
+ if (is_readable($actionData["vcf_filepath"])) {
+ $parser = null;
+
+ try {
+ $parser = VCardParser::parseFromFile($actionData["vcf_filepath"]);
+ } catch (Exception $e) {
+ $error = true;
+ $error_msg = $e->getMessage();
+ }
+ if ($error) {
+ $response['status'] = false;
+ $response['message'] = $error_msg;
+ } else {
+ if (iterator_count($parser) == 0) {
+ $response['status'] = false;
+ $response['message'] = dgettext("plugin_contactimporter", "No contacts in vcf file");
+ } else {
+ $response['status'] = true;
+ $response['parsed_file'] = $actionData["vcf_filepath"];
+ $response['parsed'] = array(
+ 'contacts' => $this->parseContactsToArray($parser)
+ );
+ }
+ }
+ } else {
+ $response['status'] = false;
+ $response['message'] = dgettext("plugin_contactimporter", "File could not be read by server");
+ }
+
+ $this->addActionData($actionType, $response);
+ $GLOBALS["bus"]->addData($this->getResponseData());
+
+ if ($this->DEBUG) {
+ error_log("parsing done, bus data written!");
+ }
+ }
+
+ /**
+ * Create a array with contacts
+ *
+ * @param contacts vcard or csv contacts
+ * @param csv optional, true if contacts are csv contacts
+ * @return array parsed contacts
+ * @private
+ */
+ private function parseContactsToArray($contacts, $csv = false)
+ {
+ $carr = array();
+
+ if (!$csv) {
+ foreach ($contacts as $Index => $vCard) {
+ $properties = array();
+ if (isset($vCard->fullname)) {
+ $properties["display_name"] = $vCard->fullname;
+ $properties["fileas"] = $vCard->fullname;
+ } elseif (!isset($vCard->organization)) {
+ error_log("Skipping entry! No fullname/organization given.");
+ continue;
+ }
+
+ $properties["hide_attachments"] = true;
+
+ //uid - used for front/backend communication
+ $properties["internal_fields"] = array();
+ $properties["internal_fields"]["contact_uid"] = base64_encode($Index . $properties["fileas"]);
+
+ $properties["given_name"] = $vCard->firstname;
+ $properties["middle_name"] = $vCard->additional;
+ $properties["surname"] = $vCard->lastname;
+ $properties["display_name_prefix"] = $vCard->prefix;
+
+ if (isset($vCard->phone) && count($vCard->phone) > 0) {
+ foreach ($vCard->phone as $type => $number) {
+ $number = $number[0]; // we only can store one number
+ if ($this->startswith(strtolower($type), "home") || strtolower($type) === "default") {
+ $properties["home_telephone_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "cell")) {
+ $properties["cellular_telephone_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "work")) {
+ $properties["business_telephone_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "fax")) {
+ $properties["business_fax_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "pager")) {
+ $properties["pager_telephone_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "isdn")) {
+ $properties["isdn_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "car")) {
+ $properties["car_telephone_number"] = $number;
+ } else {
+ if ($this->startswith(strtolower($type), "modem")) {
+ $properties["ttytdd_telephone_number"] = $number;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (isset($vCard->email) && count($vCard->email) > 0) {
+ $emailcount = 0;
+ $properties["address_book_long"] = 0;
+ foreach ($vCard->email as $type => $email) {
+ foreach ($email as $mail) {
+ $fileas = $mail;
+ if (isset($properties["fileas"]) && !empty($properties["fileas"])) {
+ $fileas = $properties["fileas"]; // set to real name
+ }
+
+ // we only have storage for 3 mail addresses!
+ /**
+ * type of email address address_book_mv address_book_long
+ * email1 0 1 (0x00000001)
+ * email2 1 2 (0x00000002)
+ * email3 2 4 (0x00000004)
+ * fax2(business fax) 3 8 (0x00000008)
+ * fax3(home fax) 4 16 (0x00000010)
+ * fax1(primary fax) 5 32 (0x00000020)
+ *
+ * address_book_mv is a multivalued property so all the values are passed in array
+ * address_book_long stores sum of the flags
+ * these both properties should be in sync always
+ */
+ switch ($emailcount) {
+ case 0:
+ $properties["email_address_1"] = $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_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_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
+ break;
+ default:
+ break;
+ }
+ $emailcount++;
+ }
+ }
+ }
+ if (isset($vCard->organization)) {
+ $properties["company_name"] = $vCard->organization;
+ if (empty($properties["display_name"])) {
+ $properties["display_name"] = $vCard->organization; // if we have no displayname - use the company name as displayname
+ $properties["fileas"] = $vCard->organization;
+ }
+ }
+ if (isset($vCard->title)) {
+ $properties["title"] = $vCard->title;
+ }
+ if (isset($vCard->url) && count($vCard->url) > 0) {
+ foreach ($vCard->url as $type => $url) {
+ $url = $url[0]; // only 1 webaddress per type
+ $properties["webpage"] = $url;
+ break; // we can only store on url
+ }
+ }
+ if (isset($vCard->address) && count($vCard->address) > 0) {
+
+ foreach ($vCard->address as $type => $address) {
+ $address = $address[0]; // we only can store one address per type
+ if ($this->startswith(strtolower($type), "work")) {
+ $properties["business_address_street"] = $address->street;
+ if (!empty($address->extended)) {
+ $properties["business_address_street"] .= "\n" . $address->extended;
+ }
+ $properties["business_address_city"] = $address->city;
+ $properties["business_address_state"] = $address->region;
+ $properties["business_address_postal_code"] = $address->zip;
+ $properties["business_address_country"] = $address->country;
+ $properties["business_address"] = $this->buildAddressString($properties["business_address_street"], $address->zip, $address->city, $address->region, $address->country);
+ } else {
+ if ($this->startswith(strtolower($type), "home")) {
+ $properties["home_address_street"] = $address->street;
+ if (!empty($address->extended)) {
+ $properties["home_address_street"] .= "\n" . $address->extended;
+ }
+ $properties["home_address_city"] = $address->city;
+ $properties["home_address_state"] = $address->region;
+ $properties["home_address_postal_code"] = $address->zip;
+ $properties["home_address_country"] = $address->country;
+ $properties["home_address"] = $this->buildAddressString($properties["home_address_street"], $address->zip, $address->city, $address->region, $address->country);
+ } else {
+ $properties["other_address_street"] = $address->street;
+ if (!empty($address->extended)) {
+ $properties["other_address_street"] .= "\n" . $address->extended;
+ }
+ $properties["other_address_city"] = $address->city;
+ $properties["other_address_state"] = $address->region;
+ $properties["other_address_postal_code"] = $address->zip;
+ $properties["other_address_country"] = $address->country;
+ $properties["other_address"] = $this->buildAddressString($properties["other_address_street"], $address->zip, $address->city, $address->region, $address->country);
+ }
+ }
+ }
+ }
+ if (isset($vCard->birthday)) {
+ $properties["birthday"] = $vCard->birthday->getTimestamp();
+ }
+ if (isset($vCard->note)) {
+ $properties["notes"] = $vCard->note;
+ }
+ if (isset($vCard->rawPhoto) || isset($vCard->photo)) {
+ if (!is_writable(TMP_PATH . "/")) {
+ error_log("Can not write to export tmp directory!");
+ } else {
+ $tmppath = TMP_PATH . "/" . $this->randomstring(15);
+ if (isset($vCard->rawPhoto)) {
+ if (file_put_contents($tmppath, $vCard->rawPhoto)) {
+ $properties["internal_fields"]["x_photo_path"] = $tmppath;
+ }
+ } elseif (isset($vCard->photo)) {
+ if ($this->startswith(strtolower($vCard->photo), "http://") || $this->startswith(strtolower($vCard->photo), "https://")) { // check if it starts with http
+ $ctx = stream_context_create(array('http' =>
+ array(
+ 'timeout' => 3, //3 Seconds timout
+ )
+ ));
+
+ if (file_put_contents($tmppath, file_get_contents($vCard->photo, false, $ctx))) {
+ $properties["internal_fields"]["x_photo_path"] = $tmppath;
+ }
+ } else {
+ error_log("Invalid photo url: " . $vCard->photo);
+ }
+ }
+ }
+ }
+ array_push($carr, $properties);
+ }
+ } else {
+ error_log("csv parsing not implemented");
+ }
+
+ return $carr;
+ }
+
+ /**
+ * Generate the whole addressstring
+ *
+ * @param street
+ * @param zip
+ * @param city
+ * @param state
+ * @param country
+ * @return string the concatinated address string
+ * @private
+ */
+ private function buildAddressString($street, $zip, $city, $state, $country)
+ {
+ $out = "";
+
+ if (isset($country) && $street != "") {
+ $out = $country;
+ }
+
+ $zcs = "";
+ if (isset($zip) && $zip != "") {
+ $zcs = $zip;
+ }
+ if (isset($city) && $city != "") {
+ $zcs .= (($zcs) ? " " : "") . $city;
+ }
+ if (isset($state) && $state != "") {
+ $zcs .= (($zcs) ? " " : "") . $state;
+ }
+ if ($zcs) {
+ $out = $zcs . "\n" . $out;
+ }
+
+ if (isset($street) && $street != "") {
+ $out = $street . (($out) ? "\n\n" . $out : "");
+ }
+
+ return $out;
+ }
+
+ /**
+ * Store the file to a temporary directory
+ * @param $actionType
+ * @param $actionData
+ * @private
+ */
+ private function getAttachmentPath($actionType, $actionData)
+ {
+ // Get store id
+ $storeid = false;
+ if (isset($actionData["store"])) {
+ $storeid = $actionData["store"];
+ }
+
+ // Get message entryid
+ $entryid = false;
+ if (isset($actionData["entryid"])) {
+ $entryid = $actionData["entryid"];
+ }
+
+ // Check which type isset
+ $openType = "attachment";
+
+ // Get number of attachment which should be opened.
+ $attachNum = false;
+ if (isset($actionData["attachNum"])) {
+ $attachNum = $actionData["attachNum"];
+ }
+
+ // Check if storeid and entryid isset
+ if ($storeid && $entryid) {
+ // Open the store
+ $store = $GLOBALS["mapisession"]->openMessageStore(hex2bin($storeid));
+
+ if ($store) {
+ // Open the message
+ $message = mapi_msgstore_openentry($store, hex2bin($entryid));
+
+ if ($message) {
+ $attachment = false;
+
+ // Check if attachNum isset
+ if ($attachNum) {
+ // 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) {
+ // Open the object in the attachment
+ $message = mapi_attach_openobj($tempattach);
+ }
+ }
+
+ // Open the attachment
+ $attachment = mapi_message_openattach($message, (int)$attachNum[(count($attachNum) - 1)]);
+ }
+
+ // Check if the attachment is opened
+ if ($attachment) {
+
+ // Get the props of the attachment
+ $props = mapi_attach_getprops($attachment, array(PR_ATTACH_LONG_FILENAME, PR_ATTACH_MIME_TAG, PR_DISPLAY_NAME, PR_ATTACH_METHOD));
+ // Content Type
+ $contentType = "application/octet-stream";
+ // Filename
+ $filename = "ERROR";
+
+ // Set filename
+ if (isset($props[PR_ATTACH_LONG_FILENAME])) {
+ $filename = $props[PR_ATTACH_LONG_FILENAME];
+ } else {
+ if (isset($props[PR_ATTACH_FILENAME])) {
+ $filename = $props[PR_ATTACH_FILENAME];
+ } else {
+ if (isset($props[PR_DISPLAY_NAME])) {
+ $filename = $props[PR_DISPLAY_NAME];
+ }
+ }
+ }
+
+ // Set content type
+ if (isset($props[PR_ATTACH_MIME_TAG])) {
+ $contentType = $props[PR_ATTACH_MIME_TAG];
+ } else {
+ // Parse the extension of the filename to get the content type
+ if (strrpos($filename, ".") !== false) {
+ $extension = strtolower(substr($filename, strrpos($filename, ".")));
+ $contentType = "application/octet-stream";
+ if (is_readable("mimetypes.dat")) {
+ $fh = fopen("mimetypes.dat", "r");
+ $ext_found = false;
+ while (!feof($fh) && !$ext_found) {
+ $line = fgets($fh);
+ preg_match("/(\.[a-z0-9]+)[ \t]+([^ \t\n\r]*)/i", $line, $result);
+ if ($extension == $result[1]) {
+ $ext_found = true;
+ $contentType = $result[2];
+ }
+ }
+ fclose($fh);
+ }
+ }
+ }
+
+
+ $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');
+ $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));
+ }
+ fclose($fhandle);
+
+ $response = array();
+ $response['tmpname'] = $tmpname;
+ $response['filename'] = $filename;
+ $response['status'] = true;
+ $this->addActionData($actionType, $response);
+ $GLOBALS["bus"]->addData($this->getResponseData());
+ }
+ }
+ } else {
+ $response['status'] = false;
+ $response['message'] = dgettext("plugin_contactimporter", "Store could not be opened!");
+ $this->addActionData($actionType, $response);
+ $GLOBALS["bus"]->addData($this->getResponseData());
+ }
+ } else {
+ $response['status'] = false;
+ $response['message'] = dgettext("plugin_contactimporter", "Wrong call, store and entryid have to be set!");
+ $this->addActionData($actionType, $response);
+ $GLOBALS["bus"]->addData($this->getResponseData());
+ }
+ }
+
+ /**
+ * Check if string starts with other string.
+ * @param $haystack
+ * @param $needle
+ * @return bool
+ */
+ private function startswith($haystack, $needle)
+ {
+ $haystack = str_replace("type=", "", $haystack); // remove type from string
+ return substr($haystack, 0, strlen($needle)) === $needle;
+ }
}
-
-;
-
-?>
diff --git a/php/plugin.contactimporter.php b/php/plugin.contactimporter.php
index f30b830..5613573 100644
--- a/php/plugin.contactimporter.php
+++ b/php/plugin.contactimporter.php
@@ -1,6 +1,6 @@
* Copyright (C) 2012-2016 Christoph Haas
@@ -30,63 +30,63 @@ require_once __DIR__ . "/download.php";
*/
class Plugincontactimporter extends Plugin
{
- /**
- * Constructor
- */
- function __construct() {}
+ /**
+ * Constructor
+ */
+ function __construct()
+ {
+ }
- /**
- * Function initializes the Plugin and registers all hooks
- *
- * @return void
- */
- function init()
- {
- $this->registerHook('server.core.settings.init.before');
- $this->registerHook('server.index.load.custom');
- }
+ /**
+ * Function initializes the Plugin and registers all hooks
+ *
+ * @return void
+ */
+ function init()
+ {
+ $this->registerHook('server.core.settings.init.before');
+ $this->registerHook('server.index.load.custom');
+ }
- /**
- * Function is executed when a hook is triggered by the PluginManager
- *
- * @param string $eventID the id of the triggered hook
- * @param mixed $data object(s) related to the hook
- * @return void
- */
- function execute($eventID, &$data)
- {
- switch ($eventID) {
- case 'server.core.settings.init.before' :
- $this->injectPluginSettings($data);
- break;
- case 'server.index.load.custom':
- if ($data['name'] == 'download_vcf') {
- DownloadHandler::doDownload();
- }
- break;
- }
- }
+ /**
+ * Function is executed when a hook is triggered by the PluginManager
+ *
+ * @param string $eventID the id of the triggered hook
+ * @param mixed $data object(s) related to the hook
+ * @return void
+ */
+ function execute($eventID, &$data)
+ {
+ switch ($eventID) {
+ case 'server.core.settings.init.before' :
+ $this->injectPluginSettings($data);
+ break;
+ case 'server.index.load.custom':
+ if ($data['name'] == 'download_vcf') {
+ DownloadHandler::doDownload();
+ }
+ break;
+ }
+ }
- /**
- * Called when the core Settings class is initialized and ready to accept sysadmin default
- * settings.
- * @param Array $data Reference to the data of the triggered hook
- */
- function injectPluginSettings(&$data)
- {
- $data['settingsObj']->addSysAdminDefaults(Array(
- 'zarafa' => Array(
- 'v1' => Array(
- 'plugins' => Array(
- 'contactimporter' => Array(
- 'enable' => PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE,
- 'default_addressbook' => PLUGIN_CONTACTIMPORTER_DEFAULT
- )
- )
- )
- )
- ));
- }
-}
-
-?>
+ /**
+ * Called when the core Settings class is initialized and ready to accept sysadmin default
+ * settings.
+ * @param [] $data Reference to the data of the triggered hook
+ */
+ function injectPluginSettings(&$data)
+ {
+ $data['settingsObj']->addSysAdminDefaults(Array(
+ 'zarafa' => Array(
+ 'v1' => Array(
+ 'plugins' => Array(
+ 'contactimporter' => Array(
+ 'enable' => PLUGIN_CONTACTIMPORTER_USER_DEFAULT_ENABLE,
+ 'default_addressbook' => PLUGIN_CONTACTIMPORTER_DEFAULT
+ )
+ )
+ )
+ )
+ ));
+ }
+}
\ No newline at end of file
diff --git a/php/upload.php b/php/upload.php
index 73b97c8..314b577 100644
--- a/php/upload.php
+++ b/php/upload.php
@@ -1,6 +1,6 @@
* Copyright (C) 2012-2016 Christoph Haas
@@ -32,7 +32,7 @@ ini_set('display_errors', '0');
*/
function respondJSON($arr)
{
- echo json_encode($arr);
+ echo json_encode($arr);
}
/**
@@ -42,33 +42,33 @@ function respondJSON($arr)
*/
function randomstring($length = 6)
{
- // $chars - all allowed charakters
- $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
+ // $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;
+ 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);
+ $result = move_uploaded_file($_FILES['vcfdata']['tmp_name'], $destpath);
- if ($result) {
- respondJSON(array('success' => true, 'vcf_file' => $destpath));
- } else {
- respondJSON(array('success' => false, 'error' => "File could not be moved to TMP path! Check plugin config and folder permissions!"));
- }
+ if ($result) {
+ respondJSON(array('success' => true, 'vcf_file' => $destpath));
+ } else {
+ 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' => "File could not be read by server, upload error!"));
+ respondJSON(array('success' => false, 'error' => dgettext("plugin_contactimporter", "File could not be read by server, upload error!")));
}
?>
\ No newline at end of file