MFB:
authorJan Schneider <jan@horde.org>
Wed, 30 Dec 2009 14:00:26 +0000 (15:00 +0100)
committerJan Schneider <jan@horde.org>
Wed, 30 Dec 2009 14:00:26 +0000 (15:00 +0100)
[jan] Only synchronize those fields that are supported by the client
(Request #6658, requires Horde 3.3.7).

framework/SyncML/SyncML/Backend.php
framework/SyncML/SyncML/Backend/Horde.php
framework/SyncML/SyncML/Backend/Sql.php
framework/SyncML/SyncML/Sync.php
turba/docs/CHANGES
turba/lib/Api.php
turba/lib/Driver.php

index 2359a2f..da9fc03 100644 (file)
@@ -503,10 +503,12 @@ class SyncML_Backend {
      *                             this is the guid.
      * @param string $contentType  Content-Type: the MIME type in which the
      *                             function should return the data.
+     * @param array $fields        Hash of field names and SyncML_Property
+     *                             properties with the requested fields.
      *
      * @return mixed  A string with the data entry or a PEAR_Error object.
      */
-    function retrieveEntry($databaseURI, $suid, $contentType)
+    function retrieveEntry($databaseURI, $suid, $contentType, $fields)
     {
         die('retrieveEntry() not implemented!');
     }
index 2bfd57b..87f1fa0 100644 (file)
@@ -336,14 +336,16 @@ class SyncML_Backend_Horde extends SyncML_Backend {
      *                             this is the guid.
      * @param string $contentType  Content-Type: the MIME type in which the
      *                             function should return the data.
+     * @param array $fields        Hash of field names and SyncML_Property
+     *                             properties with the requested fields.
      *
      * @return mixed  A string with the data entry or a PEAR_Error object.
      */
-    function retrieveEntry($databaseURI, $suid, $contentType)
+    function retrieveEntry($databaseURI, $suid, $contentType, $fields)
     {
         return $GLOBALS['registry']->call(
             $this->_normalize($databaseURI) . '/export',
-            array('guid' => $suid, 'contentType' => $contentType));
+            array('guid' => $suid, 'contentType' => $contentType, 'dummy' => null, 'fields' => $fields));
     }
 
     /**
index 5000a2a..9a5727e 100644 (file)
@@ -271,10 +271,12 @@ class SyncML_Backend_Sql extends SyncML_Backend {
      *                             this is the guid.
      * @param string $contentType  Content-Type: the MIME type in which the
      *                             function should return the data.
+     * @param array $fields        Hash of field names and SyncML_Property
+     *                             properties with the requested fields.
      *
      * @return mixed  A string with the data entry or a PEAR_Error object.
      */
-    function retrieveEntry($databaseURI, $suid, $contentType)
+    function retrieveEntry($databaseURI, $suid, $contentType, $fields)
     {
         $database = $this->_normalize($databaseURI);
 
index 37b06b4..315f9e6 100644 (file)
@@ -375,6 +375,12 @@ class SyncML_Sync {
             $this->_targetLocURI, $this->_sourceLocURI);
         $contentTypeTasks = $device->getPreferredContentTypeClient(
             'tasks', $this->_sourceLocURI);
+        if ($state->deviceInfo && $state->deviceInfo->CTCaps) {
+            $fields = array($contentType => isset($state->deviceInfo->CTCaps[$contentType]) ? $state->deviceInfo->CTCaps[$contentType] : null,
+                            $contentTypeTasks => isset($state->deviceInfo->CTCaps[$contentTypeTasks]) ? $state->deviceInfo->CTCaps[$contentTypeTasks] : null);
+        } else {
+            $fields = array($contentType => null, $contentTypeTasks => null);
+        }
 
         /* If server modifications are not retrieved yet (first Sync element),
          * do it now. */
@@ -479,7 +485,7 @@ class SyncML_Sync {
             $syncDB = isset($this->_server_task_adds[$suid]) ? 'tasks' : $this->_targetLocURI;
             $ct = isset($this->_server_task_adds[$suid]) ? $contentTypeTasks : $contentType;
 
-            $c = $backend->retrieveEntry($syncDB, $suid, $ct);
+            $c = $backend->retrieveEntry($syncDB, $suid, $ct, $fields[$ct]);
             /* Item in history but not in database. Strange, but can
              * happen. */
             if (is_a($c, 'PEAR_Error')) {
@@ -533,7 +539,7 @@ class SyncML_Sync {
         foreach ($replaces as $suid => $cuid) {
             $syncDB = isset($replaces2[$suid]) ? 'tasks' : $this->_targetLocURI;
             $ct = isset($replaces2[$suid]) ? $contentTypeTasks : $contentType;
-            $c = $backend->retrieveEntry($syncDB, $suid, $ct);
+            $c = $backend->retrieveEntry($syncDB, $suid, $ct, $fields[$ct]);
             if (is_a($c, 'PEAR_Error')) {
                 /* Item in history but not in database. */
                 unset($this->_server_replaces[$suid]);
index 73d8837..d4066d3 100644 (file)
@@ -10,7 +10,8 @@ v3.0-git
 v2.3.4-cvs
 ----------
 
-
+[jan] Only synchronize those fields that are supported by the client
+      (Request #6658, requires Horde 3.3.7).
 
 
 ------
index 6016dca..43819d4 100644 (file)
@@ -728,20 +728,20 @@ class Turba_Api extends Horde_Registry_Api
      * Export a contact, identified by UID, in the requested contentType.
      *
      * @param string $uid            Identify the contact to export.
-     * @param mixed $contentType     What format should the data be in?
-     *                               Either a string with one of:
-     *                               - text/directory
-     *                               - text/vcard
-     *                               - text/x-vcard
-     *                               The first two produce a vcard3.0 (rfc2426),
-     *                               the second produces a vcard in old 2.1 format
+     * @param mixed $contentType     What format should the data be in?  Either
+     *                               a string with one of: - text/directory -
+     *                               text/vcard - text/x-vcard The first two
+     *                               produce a vcard3.0 (rfc2426), the second
+     *                               produces a vcard in old 2.1 format
      *                               defined by imc.org
-     * @param string|array $sources  The source(s) from which the contact will be
-     *                               exported.
+     * @param string|array $sources The source(s) from which the contact will
+     *                               be exported.
+     * @param array $fields          Hash of field names and SyncML_Property
+     *                               properties with the requested fields.
      *
      * @return mixed  The requested data | PEAR_Error
      */
-    public function export($uid, $contentType, $sources = null)
+    public function export($uid, $contentType, $sources = null, $fields = null)
     {
         require_once dirname(__FILE__) . '/base.php';
         global $cfgSources, $prefs;
@@ -796,9 +796,10 @@ class Turba_Api extends Horde_Registry_Api
             case 'text/directory':
                 $export = '';
                 foreach ($result->objects as $obj) {
-                    $vcard = $driver->tovCard($obj, $version);
-                    /* vCards are not enclosed in BEGIN:VCALENDAR..END:VCALENDAR.
-                     * Export the individual cards instead. */
+                    $vcard = $driver->tovCard($obj, $version, $fields);
+                    /* vCards are not enclosed in
+                     * BEGIN:VCALENDAR..END:VCALENDAR.  Export the individual
+                     * cards instead. */
                     $export .= $vcard->exportvCalendar();
                 }
                 return $export;
index b877ef8..a735afc 100644 (file)
@@ -944,14 +944,16 @@ class Turba_Driver
     /**
      * Exports a given Turba_Object as an iCalendar vCard.
      *
-     * @param Turba_Object $object    A Turba_Object.
-     * @param string       $version   The vcard version to produce.
+     * @param Turba_Object $object  Turba_Object.
+     * @param string $version       The vcard version to produce.
+     * @param array $fields         Hash of field names and SyncML_Property
+     *                              properties with the requested fields.
      *
      * @static
      *
      * @return Horde_iCalendar_vcard  A Horde_iCalendar_vcard object.
      */
-    function tovCard($object, $version = '2.1')
+    function tovCard($object, $version = '2.1', $fields = null)
     {
         $hash = $object->getAttributes();
         $vcard = new Horde_iCalendar_vcard($version);
@@ -966,16 +968,28 @@ class Turba_Driver
 
             switch ($key) {
             case 'name':
+                if ($fields && !isset($fields['FN'])) {
+                    break;
+                }
                 $vcard->setAttribute('FN', $val, Horde_Mime::is8bit($val) ? $charset : array());
                 $formattedname = true;
                 break;
             case 'nickname':
             case 'alias':
+                if ($fields && !isset($fields['NICKNAME'])) {
+                    break;
+                }
                 $vcard->setAttribute('NICKNAME', $val,
                                      Horde_Mime::is8bit($val) ? $charset : array());
                 break;
 
             case 'homeAddress':
+                if ($fields &&
+                    (!isset($fields['LABEL']) ||
+                     (isset($fields['LABEL']->Params['TYPE']) &&
+                      !isset($fields['LABEL']->Params['TYPE']->ValEnum['HOME'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('LABEL', $val, array('HOME' => null));
                 } else {
@@ -983,13 +997,22 @@ class Turba_Driver
                 }
                 break;
             case 'workAddress':
+                if ($fields &&
+                    (!isset($fields['LABEL']) ||
+                     (isset($fields['LABEL']->Params['TYPE']) &&
+                      !isset($fields['LABEL']->Params['TYPE']->ValEnum['WORK'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
-                    $vcard->setAttribute('LABEL', $val, array('HOME' => null));
+                    $vcard->setAttribute('LABEL', $val, array('WORK' => null));
                 } else {
                     $vcard->setAttribute('LABEL', $val, array('TYPE' => 'WORK'));
                 }
                 break;
             case 'otherAddress':
+                if ($fields && !isset($fields['LABEL'])) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('LABEL', $val);
                 } else {
@@ -998,6 +1021,9 @@ class Turba_Driver
                 break;
 
             case 'phone':
+                if ($fields && !isset($fields['TEL'])) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val);
                 } else {
@@ -1005,6 +1031,12 @@ class Turba_Driver
                 }
                 break;
             case 'homePhone':
+                if ($fields &&
+                    (!isset($fields['TEL']) ||
+                     (isset($fields['TEL']->Params['TYPE']) &&
+                      !isset($fields['TEL']->Params['TYPE']->ValEnum['HOME'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('HOME' => null));
                 } else {
@@ -1012,6 +1044,12 @@ class Turba_Driver
                 }
                 break;
             case 'workPhone':
+                if ($fields &&
+                    (!isset($fields['TEL']) ||
+                     (isset($fields['TEL']->Params['TYPE']) &&
+                      !isset($fields['TEL']->Params['TYPE']->ValEnum['WORK'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('WORK' => null));
                 } else {
@@ -1019,6 +1057,12 @@ class Turba_Driver
                 }
                 break;
             case 'cellPhone':
+                if ($fields &&
+                    (!isset($fields['TEL']) ||
+                     (isset($fields['TEL']->Params['TYPE']) &&
+                      !isset($fields['TEL']->Params['TYPE']->ValEnum['CELL'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('CELL' => null));
                 } else {
@@ -1026,21 +1070,81 @@ class Turba_Driver
                 }
                 break;
             case 'homeCellPhone':
-                if ($version == '2.1') {
-                    $vcard->setAttribute('TEL', $val, array('CELL' => null, 'HOME' => null));
+                $parameters = array();
+                if ($fields) {
+                    if (!isset($fields['TEL'])) {
+                        break;
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['CELL'])) {
+                        if ($version == '2.1') {
+                            $parameters['CELL'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'CELL';
+                        }
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['HOME'])) {
+                        if ($version == '2.1') {
+                            $parameters['HOME'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'HOME';
+                        }
+                    }
+                    if (empty($parameters)) {
+                        break;
+                    }
                 } else {
-                    $vcard->setAttribute('TEL', $val, array('TYPE' => 'CELL', 'TYPE' => 'HOME'));
+                    if ($version == '2.1') {
+                        $parameters = array('CELL' => null, 'HOME' => null);
+                    } else {
+                        $parameters = array('TYPE' => 'CELL', 'TYPE' => 'HOME');
+                    }
                 }
+                $vcard->setAttribute('TEL', $val, $parameters);
                 break;
             case 'workCellPhone':
-                if ($version == '2.1') {
-                    $vcard->setAttribute('TEL', $val, array('CELL' => null, 'WORK' => null));
+                $parameters = array();
+                if ($fields) {
+                    if (!isset($fields['TEL'])) {
+                        break;
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['CELL'])) {
+                        if ($version == '2.1') {
+                            $parameters['CELL'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'CELL';
+                        }
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['WORK'])) {
+                        if ($version == '2.1') {
+                            $parameters['WORK'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'WORK';
+                        }
+                    }
+                    if (empty($parameters)) {
+                        break;
+                    }
                 } else {
-                    $vcard->setAttribute('TEL', $val, array('TYPE' => 'CELL', 'TYPE' => 'WORK'));
+                    if ($version == '2.1') {
+                        $parameters = array('CELL' => null, 'WORK' => null);
+                    } else {
+                        $parameters = array('TYPE' => 'CELL', 'TYPE' => 'WORK');
+                    }
                 }
+                $vcard->setAttribute('TEL', $val, $parameters);
                 break;
 
             case 'videoCall':
+                if ($fields &&
+                    (!isset($fields['TEL']) ||
+                     (isset($fields['TEL']->Params['TYPE']) &&
+                      !isset($fields['TEL']->Params['TYPE']->ValEnum['VIDEO'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('VIDEO' => null));
                 } else {
@@ -1048,24 +1152,87 @@ class Turba_Driver
                 }
                 break;
             case 'homeVideoCall':
-                if ($version == '2.1') {
-                    $vcard->setAttribute('TEL', $val, array('VIDEO' => null, 'HOME' => null));
+                $parameters = array();
+                if ($fields) {
+                    if (!isset($fields['TEL'])) {
+                        break;
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['VIDEO'])) {
+                        if ($version == '2.1') {
+                            $parameters['VIDEO'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'VIDEO';
+                        }
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['HOME'])) {
+                        if ($version == '2.1') {
+                            $parameters['HOME'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'HOME';
+                        }
+                    }
+                    if (empty($parameters)) {
+                        break;
+                    }
                 } else {
-                    $vcard->setAttribute('TEL', $val, array('TYPE' => 'VIDEO', 'TYPE' => 'HOME'));
+                    if ($version == '2.1') {
+                        $parameters = array('VIDEO' => null, 'HOME' => null);
+                    } else {
+                        $parameters = array('TYPE' => 'VIDEO', 'TYPE' => 'HOME');
+                    }
                 }
+                $vcard->setAttribute('TEL', $val, $parameters);
                 break;
             case 'workVideoCall':
-                if ($version == '2.1') {
-                    $vcard->setAttribute('TEL', $val, array('VIDEO' => null, 'WORK' => null));
+                $parameters = array();
+                if ($fields) {
+                    if (!isset($fields['TEL'])) {
+                        break;
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['VIDEO'])) {
+                        if ($version == '2.1') {
+                            $parameters['VIDEO'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'VIDEO';
+                        }
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['WORK'])) {
+                        if ($version == '2.1') {
+                            $parameters['WORK'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'WORK';
+                        }
+                    }
+                    if (empty($parameters)) {
+                        break;
+                    }
                 } else {
-                    $vcard->setAttribute('TEL', $val, array('TYPE' => 'VIDEO', 'TYPE' => 'WORK'));
+                    if ($version == '2.1') {
+                        $parameters = array('VIDEO' => null, 'WORK' => null);
+                    } else {
+                        $parameters = array('TYPE' => 'VIDEO', 'TYPE' => 'WORK');
+                    }
                 }
+                $vcard->setAttribute('TEL', $val, $parameters);
                 break;
 
             case 'sip':
+                if ($fields && !isset($fields['X-SIP'])) {
+                    break;
+                }
                 $vcard->setAttribute('X-SIP', $val);
                 break;
             case 'ptt':
+                if ($fields &&
+                    (!isset($fields['X-SIP']) ||
+                     (isset($fields['X-SIP']->Params['TYPE']) &&
+                      !isset($fields['X-SIP']->Params['TYPE']->ValEnum['POC'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('X-SIP', $val, array('POC' => null));
                 } else {
@@ -1073,6 +1240,12 @@ class Turba_Driver
                 }
                 break;
             case 'voip':
+                if ($fields &&
+                    (!isset($fields['X-SIP']) ||
+                     (isset($fields['X-SIP']->Params['TYPE']) &&
+                      !isset($fields['X-SIP']->Params['TYPE']->ValEnum['VOIP'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('X-SIP', $val, array('VOIP' => null));
                 } else {
@@ -1080,6 +1253,12 @@ class Turba_Driver
                 }
                 break;
             case 'shareView':
+                if ($fields &&
+                    (!isset($fields['X-SIP']) ||
+                     (isset($fields['X-SIP']->Params['TYPE']) &&
+                      !isset($fields['X-SIP']->Params['TYPE']->ValEnum['SWIS'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('X-SIP', $val, array('SWIS' => null));
                 } else {
@@ -1088,10 +1267,19 @@ class Turba_Driver
                 break;
 
             case 'instantMessenger':
+                if ($fields && !isset($fields['X-WV-ID'])) {
+                    break;
+                }
                 $vcard->setAttribute('X-WV-ID', $val);
                 break;
 
             case 'fax':
+                if ($fields &&
+                    (!isset($fields['TEL']) ||
+                     (isset($fields['TEL']->Params['TYPE']) &&
+                      !isset($fields['TEL']->Params['TYPE']->ValEnum['FAX'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('FAX' => null));
                 } else {
@@ -1099,13 +1287,72 @@ class Turba_Driver
                 }
                 break;
             case 'homeFax':
-                if ($version == '2.1') {
-                    $vcard->setAttribute('TEL', $val, array('FAX' => null, 'HOME' => null));
+                $parameters = array();
+                if ($fields) {
+                    if (!isset($fields['TEL'])) {
+                        break;
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['FAX'])) {
+                        if ($version == '2.1') {
+                            $parameters['FAX'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'FAX';
+                        }
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['HOME'])) {
+                        if ($version == '2.1') {
+                            $parameters['HOME'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'HOME';
+                        }
+                    }
+                    if (empty($parameters)) {
+                        break;
+                    }
                 } else {
-                    $vcard->setAttribute('TEL', $val, array('TYPE' => 'FAX', 'TYPE' => 'HOME'));
+                    if ($version == '2.1') {
+                        $parameters = array('FAX' => null, 'HOME' => null);
+                    } else {
+                        $parameters = array('TYPE' => 'FAX', 'TYPE' => 'HOME');
+                    }
                 }
+                $vcard->setAttribute('TEL', $val, $parameters);
                 break;
             case 'workFax':
+                $parameters = array();
+                if ($fields) {
+                    if (!isset($fields['TEL'])) {
+                        break;
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['FAX'])) {
+                        if ($version == '2.1') {
+                            $parameters['FAX'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'FAX';
+                        }
+                    }
+                    if (!isset($fields['TEL']->Params['TYPE']) ||
+                        isset($fields['TEL']->Params['TYPE']->ValEnum['WORK'])) {
+                        if ($version == '2.1') {
+                            $parameters['WORK'] = null;
+                        } else {
+                            $parameters['TYPE'] = 'WORK';
+                        }
+                    }
+                    if (empty($parameters)) {
+                        break;
+                    }
+                } else {
+                    if ($version == '2.1') {
+                        $parameters = array('FAX' => null, 'WORK' => null);
+                    } else {
+                        $parameters = array('TYPE' => 'FAX', 'TYPE' => 'WORK');
+                    }
+                }
+                $vcard->setAttribute('TEL', $val, $parameters);
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('FAX' => null, 'WORK' => null));
                 } else {
@@ -1114,6 +1361,12 @@ class Turba_Driver
                 break;
 
             case 'pager':
+                if ($fields &&
+                    (!isset($fields['TEL']) ||
+                     (isset($fields['TEL']->Params['TYPE']) &&
+                      !isset($fields['TEL']->Params['TYPE']->ValEnum['PAGER'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('TEL', $val, array('PAGER' => null));
                 } else {
@@ -1122,10 +1375,19 @@ class Turba_Driver
                 break;
 
             case 'email':
+                if ($fields && !isset($fields['EMAIL'])) {
+                    break;
+                }
                 $vcard->setAttribute('EMAIL',
                                      Horde_iCalendar_vcard::getBareEmail($val));
                 break;
             case 'homeEmail':
+                if ($fields &&
+                    (!isset($fields['EMAIL']) ||
+                     (isset($fields['EMAIL']->Params['TYPE']) &&
+                      !isset($fields['EMAIL']->Params['TYPE']->ValEnum['HOME'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('EMAIL',
                                          Horde_iCalendar_vcard::getBareEmail($val),
@@ -1137,6 +1399,12 @@ class Turba_Driver
                 }
                 break;
             case 'workEmail':
+                if ($fields &&
+                    (!isset($fields['EMAIL']) ||
+                     (isset($fields['EMAIL']->Params['TYPE']) &&
+                      !isset($fields['EMAIL']->Params['TYPE']->ValEnum['WORK'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('EMAIL',
                                          Horde_iCalendar_vcard::getBareEmail($val),
@@ -1148,6 +1416,9 @@ class Turba_Driver
                 }
                 break;
             case 'emails':
+                if ($fields && !isset($fields['EMAIL'])) {
+                    break;
+                }
                 $emails = explode(',', $val);
                 foreach ($emails as $email) {
                     $vcard->setAttribute('EMAIL',
@@ -1156,40 +1427,67 @@ class Turba_Driver
                 break;
 
             case 'title':
+                if ($fields && !isset($fields['TITLE'])) {
+                    break;
+                }
                 $vcard->setAttribute('TITLE', $val,
                                      Horde_Mime::is8bit($val) ? $charset : array());
                 break;
             case 'role':
+                if ($fields && !isset($fields['ROLE'])) {
+                    break;
+                }
                 $vcard->setAttribute('ROLE', $val,
                                      Horde_Mime::is8bit($val) ? $charset : array());
                 break;
 
             case 'notes':
+                if ($fields && !isset($fields['NOTE'])) {
+                    break;
+                }
                 $vcard->setAttribute('NOTE', $val,
                                      Horde_Mime::is8bit($val) ? $charset : array());
                 break;
 
             case 'businessCategory':
             case 'category':
+                if ($fields && !isset($fields['CATEGORIES'])) {
+                    break;
+                }
                 $vcard->setAttribute('CATEGORIES', $val);
                 break;
 
             case 'anniversary':
-                $vcard->setAttribute('X-ANNIVERSARY', $val);
+                if (!$fields || isset($fields['X-ANNIVERSARY'])) {
+                    $vcard->setAttribute('X-ANNIVERSARY', $val);
+                }
                 break;
 
             case 'spouse':
-                $vcard->setAttribute('X-SPOUSE', $val);
+                if (!$fields || isset($fields['X-SPOUSE'])) {
+                    $vcard->setAttribute('X-SPOUSE', $val);
+                }
                 break;
 
             case 'children':
-                $vcard->setAttribute('X-CHILDREN', $val);
+                if (!$fields || isset($fields['X-CHILDREN'])) {
+                    $vcard->setAttribute('X-CHILDREN', $val);
+                }
                 break;
 
             case 'website':
+                if ($fields && !isset($fields['URL'])) {
+                    break;
+                }
                 $vcard->setAttribute('URL', $val);
                 break;
             case 'homeWebsite':
+                if ($fields &&
+                    (!isset($fields['URL']) ||
+                     (isset($fields['URL']->Params['TYPE']) &&
+                      !isset($fields['URL']->Params['TYPE']->ValEnum['HOME'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('URL', $val, array('HOME' => null));
                 } else {
@@ -1197,6 +1495,12 @@ class Turba_Driver
                 }
                 break;
             case 'workWebsite':
+                if ($fields &&
+                    (!isset($fields['URL']) ||
+                     (isset($fields['URL']->Params['TYPE']) &&
+                      !isset($fields['URL']->Params['TYPE']->ValEnum['WORK'])))) {
+                    break;
+                }
                 if ($version == '2.1') {
                     $vcard->setAttribute('URL', $val, array('WORK' => null));
                 } else {
@@ -1205,14 +1509,23 @@ class Turba_Driver
                 break;
 
             case 'birthday':
+                if ($fields && !isset($fields['BDAY'])) {
+                    break;
+                }
                 $vcard->setAttribute('BDAY', $val);
                 break;
 
             case 'timezone':
+                if ($fields && !isset($fields['TZ'])) {
+                    break;
+                }
                 $vcard->setAttribute('TZ', $val, array('VALUE' => 'text'));
                 break;
 
             case 'latitude':
+                if ($fields && !isset($fields['GEO'])) {
+                    break;
+                }
                 if (isset($hash['longitude'])) {
                     $vcard->setAttribute('GEO',
                                          array('latitude' => $val,
@@ -1220,6 +1533,12 @@ class Turba_Driver
                 }
                 break;
             case 'homeLatitude':
+                if ($fields &&
+                    (!isset($fields['GEO']) ||
+                     (isset($fields['GEO']->Params['TYPE']) &&
+                      !isset($fields['GEO']->Params['TYPE']->ValEnum['HOME'])))) {
+                    break;
+                }
                 if (isset($hash['homeLongitude'])) {
                     if ($version == '2.1') {
                         $vcard->setAttribute('GEO',
@@ -1235,6 +1554,12 @@ class Turba_Driver
                 }
                 break;
             case 'workLatitude':
+                if ($fields &&
+                    (!isset($fields['GEO']) ||
+                     (isset($fields['GEO']->Params['TYPE']) &&
+                      !isset($fields['GEO']->Params['TYPE']->ValEnum['HOME'])))) {
+                    break;
+                }
                 if (isset($hash['workLongitude'])) {
                     if ($version == '2.1') {
                         $vcard->setAttribute('GEO',
@@ -1252,11 +1577,19 @@ class Turba_Driver
 
             case 'photo':
             case 'logo':
+                $name = Horde_String::upper($key);
                 $params = array('ENCODING' => 'b');
                 if (isset($hash[$key . 'type'])) {
                     $params['TYPE'] = $hash[$key . 'type'];
                 }
-                $vcard->setAttribute(Horde_String::upper($key),
+                if ($fields &&
+                    (!isset($fields[$name]) ||
+                     !isset($params['TYPE'])) ||
+                     (isset($fields[$name]->Params['TYPE']) &&
+                      !isset($fields[$name]->Params['TYPE']->ValEnum[$params['TYPE']]))) {
+                    break;
+                }
+                $vcard->setAttribute($name,
                                      base64_encode($val),
                                      $params);
                 break;
@@ -1293,9 +1626,11 @@ class Turba_Driver
             $val = Horde_String::convertCharset($val, Horde_Nls::getCharset(), 'utf-8');
             $a = Horde_String::convertCharset($a, Horde_Nls::getCharset(), 'utf-8');
         }
-        $vcard->setAttribute('N', $val, Horde_Mime::is8bit($val) ? $charset : array(), false, $a);
+        if (!$fields || isset($fields['N'])) {
+            $vcard->setAttribute('N', $val, Horde_Mime::is8bit($val) ? $charset : array(), false, $a);
+        }
 
-        if (!$formattedname) {
+        if (!$formattedname && (!$fields || isset($fields['FN']))) {
             $val = empty($hash['firstname']) ? $hash['lastname'] : $hash['firstname'] . ' ' . $hash['lastname'];
             $vcard->setAttribute('FN', $val, Horde_Mime::is8bit($val) ? $charset : array());
         }
@@ -1307,7 +1642,7 @@ class Turba_Driver
         if (array_key_exists('department', $hash)) {
             $org[] = $hash['department'];
         }
-        if (count($org)) {
+        if (count($org) && (!$fields || isset($fields['ORG']))) {
             $val = implode(';', $org);
             if ($version != '2.1') {
                 $val = Horde_String::convertCharset($val, Horde_Nls::getCharset(), 'utf-8');
@@ -1316,14 +1651,15 @@ class Turba_Driver
             $vcard->setAttribute('ORG', $val, Horde_Mime::is8bit($val) ? $charset : array(), false, $org);
         }
 
-        if (array_key_exists('commonAddress', $hash) ||
-            array_key_exists('commonStreet', $hash) ||
-            array_key_exists('commonPOBox', $hash) ||
-            array_key_exists('commonExtended', $hash) ||
-            array_key_exists('commonCity', $hash) ||
-            array_key_exists('commonProvince', $hash) ||
-            array_key_exists('commonPostalCode', $hash) ||
-            array_key_exists('commonCountry', $hash)) {
+        if ((!$fields || isset($fields['ADR'])) &&
+            (array_key_exists('commonAddress', $hash) ||
+             array_key_exists('commonStreet', $hash) ||
+             array_key_exists('commonPOBox', $hash) ||
+             array_key_exists('commonExtended', $hash) ||
+             array_key_exists('commonCity', $hash) ||
+             array_key_exists('commonProvince', $hash) ||
+             array_key_exists('commonPostalCode', $hash) ||
+             array_key_exists('commonCountry', $hash))) {
             /* We can't know if this particular Turba source uses a single
              * address field or multiple for
              * street/city/province/postcode/country. Try to deal with
@@ -1363,14 +1699,18 @@ class Turba_Driver
             $vcard->setAttribute('ADR', $val, $params, true, $a);
         }
 
-        if (array_key_exists('homeAddress', $hash) ||
-            array_key_exists('homeStreet', $hash) ||
-            array_key_exists('homePOBox', $hash) ||
-            array_key_exists('homeExtended', $hash) ||
-            array_key_exists('homeCity', $hash) ||
-            array_key_exists('homeProvince', $hash) ||
-            array_key_exists('homePostalCode', $hash) ||
-            array_key_exists('homeCountry', $hash)) {
+        if ((!$fields ||
+             (isset($fields['ADR']) &&
+              (!isset($fields['ADR']->Params['TYPE']) ||
+               isset($fields['ADR']->Params['TYPE']->ValEnum['HOME'])))) &&
+            (array_key_exists('homeAddress', $hash) ||
+             array_key_exists('homeStreet', $hash) ||
+             array_key_exists('homePOBox', $hash) ||
+             array_key_exists('homeExtended', $hash) ||
+             array_key_exists('homeCity', $hash) ||
+             array_key_exists('homeProvince', $hash) ||
+             array_key_exists('homePostalCode', $hash) ||
+             array_key_exists('homeCountry', $hash))) {
             if (isset($hash['homeAddress']) && !isset($hash['homeStreet'])) {
                 $hash['homeStreet'] = $hash['homeAddress'];
             }
@@ -1405,14 +1745,18 @@ class Turba_Driver
             $vcard->setAttribute('ADR', $val, $params, true, $a);
         }
 
-        if (array_key_exists('workAddress', $hash) ||
-            array_key_exists('workStreet', $hash) ||
-            array_key_exists('workPOBox', $hash) ||
-            array_key_exists('workExtended', $hash) ||
-            array_key_exists('workCity', $hash) ||
-            array_key_exists('workProvince', $hash) ||
-            array_key_exists('workPostalCode', $hash) ||
-            array_key_exists('workCountry', $hash)) {
+        if ((!$fields ||
+             (isset($fields['ADR']) &&
+              (!isset($fields['ADR']->Params['TYPE']) ||
+               isset($fields['ADR']->Params['TYPE']->ValEnum['WORK'])))) &&
+            (array_key_exists('workAddress', $hash) ||
+             array_key_exists('workStreet', $hash) ||
+             array_key_exists('workPOBox', $hash) ||
+             array_key_exists('workExtended', $hash) ||
+             array_key_exists('workCity', $hash) ||
+             array_key_exists('workProvince', $hash) ||
+             array_key_exists('workPostalCode', $hash) ||
+             array_key_exists('workCountry', $hash))) {
             if (isset($hash['workAddress']) && !isset($hash['workStreet'])) {
                 $hash['workStreet'] = $hash['workAddress'];
             }