Move responsibility for translating contact messages into the client code.
authorMichael J. Rubinsky <mrubinsk@horde.org>
Tue, 13 Apr 2010 14:31:22 +0000 (10:31 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Tue, 13 Apr 2010 14:31:22 +0000 (10:31 -0400)
Clean up the rest of the message objects, standardize on getter/setters,
remove dead code and obsolete tests.

14 files changed:
framework/ActiveSync/lib/Horde/ActiveSync/Driver/Horde.php
framework/ActiveSync/lib/Horde/ActiveSync/Driver/Horde/Connector/Registry.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Appointment.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Attendee.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Base.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Contact.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Exception.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Folder.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Recurrence.php
framework/ActiveSync/lib/Horde/ActiveSync/Message/Task.php
framework/ActiveSync/test/Horde/ActiveSync/HordeDriverTest.php
turba/lib/Api.php
turba/lib/Driver.php
turba/lib/tests/ApiTest.php

index edcd8be..efc045a 100644 (file)
@@ -216,8 +216,7 @@ class Horde_ActiveSync_Driver_Horde extends Horde_ActiveSync_Driver_Base
                 $events = $this->_connector->calendar_listEvents($startstamp, $endstamp, null);
             } catch (Horde_Exception $e) {
                 $this->_logger->err($e->GetMessage());
-
-                return false;
+                return array();
             }
             foreach ($events as $day) {
                 foreach($day as $e) {
@@ -231,8 +230,7 @@ class Horde_ActiveSync_Driver_Horde extends Horde_ActiveSync_Driver_Base
                 $contacts = $this->_connector->contacts_list();
             } catch (Horde_Exception $e) {
                 $this->_logger->err($e->GetMessage());
-
-                return false;
+                return array();
             }
 
             foreach ($contacts as $contact) {
@@ -249,7 +247,7 @@ class Horde_ActiveSync_Driver_Horde extends Horde_ActiveSync_Driver_Base
             break;
 
         default:
-            return false;
+            return array();
         }
 
         return $messages;
@@ -300,13 +298,12 @@ class Horde_ActiveSync_Driver_Horde extends Horde_ActiveSync_Driver_Base
 
         case self::CONTACTS_FOLDER:
             try {
-                $contact = $this->_connector->contacts_export($id);
+                return $this->_connector->contacts_export($id);
             } catch (Horde_Exception $e) {
                 $this->_logger->err($e->GetMessage());
                 return false;
             }
 
-           return self::_fromHash($contact);
             break;
 
         case self::TASKS_FOLDER:
@@ -415,10 +412,9 @@ class Horde_ActiveSync_Driver_Horde extends Horde_ActiveSync_Driver_Base
             break;
 
         case self::CONTACTS_FOLDER:
-            $content = self::_toHash($message);
             if (!$id) {
                 try {
-                    $id = $this->_connector->contacts_import($content);
+                    $id = $this->_connector->contacts_import($message);
                 } catch (Horde_Exception $e) {
                     $this->_logger->err($e->getMessage());
                     return false;
@@ -553,229 +549,4 @@ class Horde_ActiveSync_Driver_Horde extends Horde_ActiveSync_Driver_Base
         return $message;
     }
 
-    /**
-     * Create a hash suitable for importing into contacts/import or
-     * contacts/replace from a Horde_ActiveSync_Message_Base object.
-     *
-     * @param Horde_ActiveSync_Message_Contact $message
-     *
-     * @return array
-     */
-    private static function _toHash(Horde_ActiveSync_Message_Contact $message)
-    {
-        $charset = Horde_Nls::getCharset();
-        $formattedname = false;
-
-        /* Name */
-        $hash['name'] = Horde_String::convertCharset($message->fileas, 'utf-8', $charset);
-        $hash['lastname'] = Horde_String::convertCharset($message->lastname, 'utf-8', $charset);
-        $hash['firstname'] = Horde_String::convertCharset($message->firstname, 'utf-8', $charset);
-        $hash['middlenames'] = Horde_String::convertCharset($message->middlename, 'utf-8', $charset);
-        $hash['namePrefix'] = Horde_String::convertCharset($message->title, 'utf-8', $charset);
-        $hash['nameSuffix'] = Horde_String::convertCharset($message->suffix, 'utf-8', $charset);
-
-
-        // picture ($message->picture *should* already be base64 encdoed)
-        $hash['photo'] = base64_decode($message->picture);
-
-        /* Home */
-        $hash['homeStreet'] = Horde_String::convertCharset($message->homestreet, 'utf-8', $charset);
-        $hash['homeCity'] = Horde_String::convertCharset($message->homecity, 'utf-8', $charset);
-        $hash['homeProvince'] = Horde_String::convertCharset($message->homestate, 'utf-8', $charset);
-        $hash['homePostalCode'] = $message->homepostalcode;
-        $hash['homeCountry'] = Horde_String::convertCharset($message->homecountry, 'utf-8', $charset);
-
-        /* Business */
-        $hash['workStreet'] = Horde_String::convertCharset($message->businessstreet, 'utf-8', $charset);
-        $hash['workCity'] = Horde_String::convertCharset($message->businesscity, 'utf-8', $charset);
-        $hash['workProvince'] = Horde_String::convertCharset($message->businessstate, 'utf-8', $charset);
-        $hash['workPostalCode'] = $message->businesspostalcode;
-        $hash['workCountry'] = Horde_String::convertCharset($message->businesscountry, 'utf-8', $charset);
-
-        $hash['homePhone'] = $message->homephonenumber;
-        $hash['workPhone'] = $message->businessphonenumber;
-        $hash['fax'] = $message->businessfaxnumber;
-        $hash['pager'] = $message->pagernumber;
-        $hash['cellPhone'] = $message->mobilephonenumber;
-
-        /* Email addresses */
-        $hash['email'] = Horde_iCalendar_vcard::getBareEmail($message->email1address);
-
-        /* Job title */
-        $hash['title'] = Horde_String::convertCharset($message->jobtitle, 'utf-8', $charset);
-
-        $hash['company'] = Horde_String::convertCharset($message->companyname, 'utf-8', $charset);
-        $hash['department'] = Horde_String::convertCharset($message->department, 'utf-8', $charset);
-
-        /* Categories */
-        if (count($message->categories)) {
-            $hash['category']['value'] = Horde_String::convertCharset(implode(';', $message->categories), 'utf-8', $charset);
-            $hash['category']['new'] = true;
-        }
-
-        /* Children */
-        // @TODO
-
-        /* Spouse */
-        $hash['spouse'] = Horde_String::convertCharset($message->spouse, 'utf-8', $charset);
-
-        /* Notes */
-        $hash['notes'] = Horde_String::convertCharset($message->body, 'utf-8', $charset);
-
-        /* webpage */
-        $hash['website'] = Horde_String::convertCharset($message->webpage, 'utf-8', $charset);
-
-        /* Birthday and Anniversary */
-        if (!empty($message->birthday)) {
-            $bday = new Horde_Date($message->birthday);
-            $hash['birthday'] = $bday->format('Y-m-d');
-        } else {
-            $hash['birthday'] = null;
-        }
-        if (!empty($message->anniversary)) {
-            $anniversary = new Horde_Date($message->anniversary);
-            $hash['anniversary'] = $anniversary->format('Y-m-d');
-        } else {
-            $hash['anniversary'] = null;
-        }
-
-        /* Assistant */
-        $hash['assistant'] = Horde_String::convertCharset($message->assistantname, 'utf-8', $charset);
-
-        return $hash;
-    }
-
-    /**
-     * Import data from Horde's contacts API
-     *
-     * @param array $hash  A hash as returned from contacts/export
-     *
-     * @return Horde_ActiveSync_Message_Base object
-     */
-    private static function _fromHash($hash)
-    {
-        $message = new Horde_ActiveSync_Message_Contact();
-
-        $charset = Horde_Nls::getCharset();
-
-        foreach ($hash as $field => $value) {
-            switch ($field) {
-            case 'name':
-                $message->fileas = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'lastname':
-                $message->lastname = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'firstname':
-                $message->firstname = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'middlenames':
-                $message->middlename = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'namePrefix':
-                $message->title = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'nameSuffix':
-                $message->suffix = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-
-            case 'photo':
-                $message->picture = base64_encode($value['load']['data']);
-                break;
-
-            /* Address (TODO: check for a single home/workAddress field instead) */
-            case 'homeStreet':
-                $message->homestreet = Horde_String::convertCharset($hash['homeStreet'], $charset, 'utf-8');
-                break;
-            case 'homeCity':
-                $message->homecity = Horde_String::convertCharset($hash['homeCity'], $charset, 'utf-8');
-                break;
-            case 'homeProvince':
-                $message->homestate = Horde_String::convertCharset($hash['homeProvince'], $charset, 'utf-8');
-                break;
-            case 'homePostalCode':
-                $message->homepostalcode = Horde_String::convertCharset($hash['homePostalCode'], $charset, 'utf-8');
-                break;
-            case 'homeCountry':
-                $message->homecountry = Horde_String::convertCharset($hash['homeCountry'], $charset, 'utf-8');
-                break;
-            case 'workStreet':
-                $message->businessstreet = Horde_String::convertCharset($hash['workStreet'], $charset, 'utf-8');
-                break;
-            case 'workCity':
-                $message->businesscity = Horde_String::convertCharset($hash['workCity'], $charset, 'utf-8');
-                break;
-            case 'workProvince':
-                $message->businessstate = Horde_String::convertCharset($hash['workProvince'], $charset, 'utf-8');
-                break;
-            case 'workPostalCode':
-                $message->businesspostalcode = Horde_String::convertCharset($hash['workPostalCode'], $charset, 'utf-8');
-                break;
-            case 'workCountry':
-                $message->businesscountry = Horde_String::convertCharset($hash['workCountry'], $charset, 'utf-8');
-                break;
-            case 'homePhone':
-                /* Phone */
-                $message->homephonenumber = $hash['homePhone'];
-                break;
-            case 'cellPhone':
-                $message->mobilephonenumber = $hash['cellPhone'];
-                break;
-            case 'fax':
-                $message->businessfaxnumber = $hash['fax'];
-                break;
-            case 'workPhone':
-                $message->businessphonenumber = $hash['workPhone'];
-                break;
-            case 'pager':
-                $message->pagernumber = $hash['pager'];
-                break;
-
-            case 'email':
-                $message->email1address = Horde_iCalendar_vcard::getBareEmail($value);
-                break;
-
-            case 'title':
-                $message->jobtitle = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-
-            case 'company':
-                $message->companyname = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'departnemt':
-                $message->department = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-
-            case 'category':
-                // Categories FROM horde are a simple string value, going BACK to horde are an array with 'value' and 'new' keys
-                $message->categories = explode(';', Horde_String::convertCharset($value, $charset, 'utf-8'));
-                break;
-
-            case 'spouse':
-                $message->spouse = Horde_String::convertCharset($value, $charset, 'utf-8');
-                break;
-            case 'notes':
-                $message->body = Horde_String::convertCharset($value, $charset, 'utf-8');
-                $message->bodysize = strlen($message->body);
-                $message->bodytruncated = false;
-                break;
-            case 'website':
-                $message->webpage = $value;
-                break;
-
-            case 'birthday':
-            case 'anniversary':
-                if (!empty($value)) {
-                    $date = new Horde_Date($value);
-                    $message->{$field} = $date;
-                } else {
-                    $message->$field = null;
-                }
-                break;
-            }
-        }
-
-        return $message;
-    }
-
 }
index 3cae543..acf4062 100644 (file)
@@ -151,7 +151,7 @@ class Horde_ActiveSync_Driver_Horde_Connector_Registry
      */
     public function contacts_export($uid)
     {
-        return $this->_registry->contacts->export($uid, 'array');
+        return $this->_registry->contacts->export($uid, 'activesync');
     }
 
     /**
index bc4d34b..101ca7a 100644 (file)
@@ -97,7 +97,7 @@ class Horde_ActiveSync_Message_Appointment extends Horde_ActiveSync_Message_Base
      * @return Horde_ActiveSync_Message_Appointment
      */
     public function __construct($params = array()) {
-        $mapping = array(
+        $this->_mapping = array(
             self::POOMCAL_TIMEZONE => array (self::KEY_ATTRIBUTE => 'timezone'),
             self::POOMCAL_DTSTAMP => array (self::KEY_ATTRIBUTE => 'dtstamp', self::KEY_TYPE => self::TYPE_DATE),
             self::POOMCAL_STARTTIME => array (self::KEY_ATTRIBUTE => 'starttime', self::KEY_TYPE => self::TYPE_DATE),
@@ -122,7 +122,28 @@ class Horde_ActiveSync_Message_Appointment extends Horde_ActiveSync_Message_Base
             //self::POOMCAL_RESPONSETYPE => array(self::KEY_ATTRIBUTE => 'responsetype'),
         );
 
-        parent::__construct($mapping, $params);
+        $this->_properties = array(
+            'timezone' => false,
+            'dtstamp' => false,
+            'starttime' => false,
+            'subject' => false,
+            'uid' => false,
+            'organizername' => false,
+            'organizeremail' => false,
+            'location' => false,
+            'endtime' => false,
+            'recurrence' => false,
+            'sensitivity' => false,
+            'busystatus' => false,
+            'alldayevent' => false,
+            'reminder' => false,
+            'rtf' => false,
+            'meetingstatus' => false,
+            'body' => false,
+            'bodytruncated' => false,
+        );
+
+        parent::__construct($params);
     }
 
     /**
index f54252a..9ef2cf6 100644 (file)
@@ -28,14 +28,19 @@ class Horde_ActiveSync_Message_Attendee extends Horde_ActiveSync_Message_Base
      * @param array $params
      */
     function __construct($params = array()) {
-        $mapping = array(
+        $this->_mapping = array(
             Horde_ActiveSync_Message_Appointment::POOMCAL_EMAIL => array (self::KEY_ATTRIBUTE => 'email'),
             Horde_ActiveSync_Message_Appointment::POOMCAL_NAME => array (self::KEY_ATTRIBUTE => 'name'),
             //SYNC_POOMCAL_ATTENDEETYPE => array(self::KEY_ATTRIBUTE => 'type'),
             //SYNC_POOMCAL_ATTENDEESTATUS => array(self::KEY_ATTRIBUTE => 'status')
         );
 
-        parent::__construct($mapping, $params);
+        $this->_properties = array(
+            'email' => false,
+            'name' => false,
+        );
+
+        parent::__construct($params);
     }
 
 }
\ No newline at end of file
index 81127f9..9ca0af0 100644 (file)
@@ -60,7 +60,7 @@ class Horde_ActiveSync_Message_Base
      * //FIXME: use accessor methods, make this protected
      * @var Horde_ActiveSync_FLAG_* constant
      */
-    public $flags;
+    public $flags = false;
 
     /**
      * Logger
@@ -77,17 +77,22 @@ class Horde_ActiveSync_Message_Base
      *
      * @return Horde_ActiveSync_Message_Base
      */
-    public function __construct($mapping, $options)
+    public function __construct($options)
     {
-        $this->_mapping = $mapping;
-        $this->flags = false;
         if (!empty($options['logger'])) {
             $this->_logger = $options['logger'];
+        } else {
+            $this->_logger = new Horde_Support_Stub();
         }
     }
 
     public function __get($property)
     {
+        if (!array_key_exists($property, $this->_properties)) {
+            $this->_logger->err('Unknown property: ' . $property);
+            throw new InvalidArgumentException('Unknown property: ' . $property);
+        }
+
         if (!empty($this->_properties[$property])) {
             return $this->_properties[$property];
         } else {
@@ -97,9 +102,28 @@ class Horde_ActiveSync_Message_Base
 
     public function __set($property, $value)
     {
+        if (!array_key_exists($property, $this->_properties)) {
+            $this->_logger->err('Unknown property: ' . $property);
+            throw new InvalidArgumentException('Unknown property: ' . $property);
+        }
         $this->_properties[$property] = $value;
     }
 
+    public function __call($method, $arg)
+    {
+        /* Support calling set{Property}() */
+        if (strpos($method, 'set') === 0) {
+            $property = Horde_String::lower(substr($method, 3));
+            $this->_properties[$property] = $arg;
+        } elseif (strpos($method, 'get') === 0) {
+            return $this->_getAttribute(Horde_String::lower(substr($method, 3)));
+        }
+
+        throw new BadMethodCallException('Unknown method: ' . $method . ' in class: ' . __CLASS__);
+    }
+
+
+
     public function __isset($property)
     {
         return !empty($this->_properties[$property]);
@@ -329,6 +353,14 @@ class Horde_ActiveSync_Message_Base
         }
     }
 
+    /**
+     * Helper method to allow default values for unset properties.
+     *
+     * @param string $name  The property name
+     * @param stting $default The default value to return if $property is empty
+     *
+     * @return mixed
+     */
     protected function _getAttribute($name, $default = null)
     {
         if (!empty($this->_properties[$name])) {
index 2179a91..4476dbc 100644 (file)
  */
 class Horde_ActiveSync_Message_Contact extends Horde_ActiveSync_Message_Base
 {
+    /* Workaround for issues with arrays from __get() */
     public $categories = array();
     public $children = array();
 
-
     /* POOMCONTACTS */
     const ANNIVERSARY = "POOMCONTACTS:Anniversary";
     const ASSISTANTNAME = "POOMCONTACTS:AssistantName";
@@ -93,7 +93,8 @@ class Horde_ActiveSync_Message_Contact extends Horde_ActiveSync_Message_Base
      */
     public function __construct($params = array())
     {
-        $mapping = array (
+        /* Mappings for the encoder */
+        $this->_mapping = array (
             self::ANNIVERSARY => array (self::KEY_ATTRIBUTE =>  'anniversary', self::KEY_TYPE => self::TYPE_DATE_DASHES),
             self::ASSISTANTNAME => array (self::KEY_ATTRIBUTE => 'assistantname'),
             self::ASSISTNAMEPHONENUMBER => array (self::KEY_ATTRIBUTE => 'assistnamephonenumber'),
@@ -150,9 +151,67 @@ class Horde_ActiveSync_Message_Contact extends Horde_ActiveSync_Message_Base
             self::CATEGORIES => array (self::KEY_ATTRIBUTE => 'categories', self::KEY_VALUES => self::CATEGORY),
         );
 
+        /* Accepted property values */
+        $this->_properties = array(
+            'anniversary' => false,
+            'assistantname' => false,
+            'assistnamephonenumber' => false,
+            'birthday' => false,
+            'body' => false,
+            'bodysize' => false,
+            'bodytruncated' => false,
+            'business2phonenumber' => false,
+            'businesscity' => false,
+            'businesscountry' => false,
+            'businesspostalcode' => false,
+            'businessstate' => false,
+            'businessstreet' => false,
+            'businessfaxnumber' => false,
+            'businessphonenumber' => false,
+            'carphonenumber' => false,
+            'children' => false,
+            'companyname' => false,
+            'department' => false,
+            'email1address' => false,
+            'email2address' => false,
+            'email3address' => false,
+            'fileas' => false,
+            'firstname' => false,
+            'home2phonenumber' => false,
+            'homecity' => false,
+            'homecountry' => false,
+            'homepostalcode' => false,
+            'homestate' => false,
+            'homestreet' => false,
+            'homefaxnumber' => false,
+            'homephonenumber' => false,
+            'jobtitle' => false,
+            'lastname' => false,
+            'middlename' => false,
+            'mobilephonenumber' => false,
+            'officelocation' => false,
+            'othercity' => false,
+            'othercountry' => false,
+            'otherpostalcode' => false,
+            'otherstate' => false,
+            'otherstreet' => false,
+            'pagernumber' => false,
+            'radiophonenumber' => false,
+            'spouse' => false,
+            'suffix' => false,
+            'title' => false,
+            'webpage' => false,
+            'yomicompanyname' => false,
+            'yomifirstname' => false,
+            'yomilastname' => false,
+            'rtf' => false,
+            'picture' => false,
+            'categories' => false,
+        );
+
         /* Additional mappings for AS versions >= 2.5 */
         if (isset($params['protocolversion']) && $params['protocolversion'] >= 2.5) {
-            $mapping += array(
+            $this->_mapping += array(
                 self::CUSTOMERID => array (self::KEY_ATTRIBUTE => 'customerid'),
                 self::GOVERNMENTID => array (self::KEY_ATTRIBUTE => 'governmentid'),
                 self::IMADDRESS => array (self::KEY_ATTRIBUTE => 'imaddress'),
@@ -164,9 +223,22 @@ class Horde_ActiveSync_Message_Contact extends Horde_ActiveSync_Message_Base
                 self::NICKNAME => array (self::KEY_ATTRIBUTE => 'nickname'),
                 self::MMS => array (self::KEY_ATTRIBUTE => 'mms'),
             );
+
+            $this->_properties += array(
+                'customerid' => false,
+                'governmentid' => false,
+                'imaddress' => false,
+                'imaddress2' => false,
+                'imaddress3' => false,
+                'managername' => false,
+                'companymainphone' => false,
+                'accountname' => false,
+                'nickname' => false,
+                'mms' => false,
+            );
         }
 
-        parent::__construct($mapping, $params);
+        parent::__construct($params);
     }
 
     public function getClass()
index afa72fa..09db9df 100644 (file)
@@ -2,7 +2,7 @@
 /**
  * Horde_ActiveSync_Message_Exception class represents a single exception to a
  * recurring event. This is basically a Appointment object with some tweaks.
- * 
+ *
  * @copyright 2010 The Horde Project (http://www.horde.org)
  *
  * @author Michael J. Rubinsky <mrubinsk@horde.org>
@@ -18,7 +18,7 @@ class Horde_ActiveSync_Message_Exception extends Horde_ActiveSync_Message_Appoin
      * @return Horde_ActiveSync_Message_Appointment
      */
     public function __construct($params = array())
-    {   
+    {
         parent::__construct($params);
 
         /* Some additional properties for Exceptions */
@@ -27,6 +27,11 @@ class Horde_ActiveSync_Message_Exception extends Horde_ActiveSync_Message_Appoin
             self::KEY_TYPE => self::TYPE_DATE);
 
         $this->_mapping[Horde_ActiveSync_Message_Appointment::POOMCAL_DELETED] = array(self::KEY_ATTRIBUTE => 'deleted');
+
+        $this->_properties += array(
+            'exceptionstarttime' => false,
+            'deleted' => false,
+        );
     }
 
     /**
index b147558..83682f0 100644 (file)
@@ -17,14 +17,21 @@ class Horde_ActiveSync_Message_Folder extends Horde_ActiveSync_Message_Base
 
     public function __construct($params = array())
     {
-        $mapping = array (
+        $this->_mapping = array (
             Horde_ActiveSync::FOLDERHIERARCHY_SERVERENTRYID => array (self::KEY_ATTRIBUTE => 'serverid'),
             Horde_ActiveSync::FOLDERHIERARCHY_PARENTID => array (self::KEY_ATTRIBUTE => 'parentid'),
             Horde_ActiveSync::FOLDERHIERARCHY_DISPLAYNAME => array (self::KEY_ATTRIBUTE => 'displayname'),
             Horde_ActiveSync::FOLDERHIERARCHY_TYPE => array (self::KEY_ATTRIBUTE => 'type')
         );
 
-        parent::__construct($mapping, $params);
+        $this->_properties = array(
+            'serverid' => false,
+            'parentid' => false,
+            'displayname' => false,
+            'type' => false,
+        );
+
+        parent::__construct($params);
     }
 
     public function getClass()
index 40840cc..34ee003 100644 (file)
@@ -20,7 +20,7 @@ class Horde_ActiveSync_Message_Recurrence extends Horde_ActiveSync_Message_Base
 
     function __construct($params = array())
     {
-        $mapping = array (
+        $this->_mapping = array (
             Horde_ActiveSync_Message_Appointment::POOMCAL_TYPE => array (self::KEY_ATTRIBUTE => 'type'),
             Horde_ActiveSync_Message_Appointment::POOMCAL_UNTIL => array (self::KEY_ATTRIBUTE => 'until', self::KEY_TYPE => self::TYPE_DATE),
             Horde_ActiveSync_Message_Appointment::POOMCAL_OCCURRENCES => array (self::KEY_ATTRIBUTE => 'occurrences'),
@@ -31,7 +31,18 @@ class Horde_ActiveSync_Message_Recurrence extends Horde_ActiveSync_Message_Base
             Horde_ActiveSync_Message_Appointment::POOMCAL_MONTHOFYEAR => array (self::KEY_ATTRIBUTE => 'monthofyear')
         );
 
-        parent::__construct($mapping, $params);
+        $this->_properties = array(
+            'type' => false,
+            'until' => false,
+            'occurrences' => false,
+            'interval' => false,
+            'dayofweek' => false,
+            'dayofmonth' => false,
+            'weekofmonth' => false,
+            'monthofyear' => false,
+        );
+
+        parent::__construct($params);
     }
 
 }
\ No newline at end of file
index acee8a1..4ec04e1 100644 (file)
@@ -58,7 +58,7 @@ class Horde_ActiveSync_Message_Task extends Horde_ActiveSync_Message_Base
      * @param array $params
      */
     function __construct($params = array()) {
-        $mapping = array (
+        $this->_mapping = array (
             self::POOMTASKS_BODY => array (self::KEY_ATTRIBUTE => 'body'),
             self::POOMTASKS_COMPLETE => array (self::KEY_ATTRIBUTE => 'complete'),
             self::POOMTASKS_DATECOMPLETED => array (self::KEY_ATTRIBUTE => 'datecompleted', self::KEY_TYPE => self::TYPE_DATE_DASHES),
@@ -78,7 +78,27 @@ class Horde_ActiveSync_Message_Task extends Horde_ActiveSync_Message_Base
             self::POOMTASKS_CATEGORIES => array (self::KEY_ATTRIBUTE => 'categories', self::KEY_VALUES => self::POOMTASKS_CATEGORY),
         );
 
-        parent::__construct($mapping, $params);
+        $this->_properties = array(
+            'body' => false,
+            'complete' => false,
+            'datecompleted' => false,
+            'duedate' => false,
+            'utcduedate' => false,
+            'importance' => false,
+            'recurrence' => false,
+            'regenerate' => false,
+            'deadoccur' => false,
+            'reminderset' => false,
+            'remindertime' => false,
+            'sensitiviy' => false,
+            'startdate' => false,
+            'utcstartdate' => false,
+            'subject' => false,
+            'rtf' => false,
+            'categories' => false,
+        );
+
+        parent::__construct($params);
     }
 
     /**
index ed9431f..52ca48b 100644 (file)
@@ -75,152 +75,72 @@ class Horde_ActiveSync_HordeDriverTest extends Horde_Test_Case
     }
 
     /**
-     * Test retrieving a message from storage.
-     * Mocks the registry response.
-     *
-     * @TODO: Calendar data, more complete test of vCard attribtues.
-     *
+     * Tests that getMessage() requests the correct object type based on
+     * the folder class we are requesting.
      */
     public function testGetMessage()
     {
         require_once 'Horde/ActiveSync.php';
 
-        $contact = array(
-            '__key' => '9b07c14b086932e69cc7eb1baed0cc87',
-            '__owner' => 'mike',
-            '__type' => 'Object',
-            '__members' => '',
-            '__uid' => '20100205111228.89913meqtp5u09rg@localhost',
-            'firstname' => 'Michael',
-            'lastname' => 'Rubinsky',
-            'middlenames' => 'Joseph',
-            'namePrefix' => 'Dr',
-            'nameSuffix' => 'PharmD',
-            'name' => 'Michael Joseph Rubinsky',
-            'alias' => 'Me',
-            'birthday' => '1970-03-20',
-            'homeStreet' => '123 Main St.',
-            'homePOBox' => '',
-            'homeCity' => 'Anywhere',
-            'homeProvince' => 'NJ',
-            'homePostalCode' => '08080',
-            'homeCountry' => 'US',
-            'workStreet' => 'Kings Hwy',
-            'workPOBox' => '',
-            'workCity' => 'Somewhere',
-            'workProvince' => 'NJ',
-            'workPostalCode' => '08052',
-            'workCountry' => 'US',
-            'timezone' => 'America/New_York',
-            'email' => 'mrubinsk@horde.org',
-            'homePhone' => '(856)555-1234',
-            'workPhone' => '(856)555-5678',
-            'cellPhone' => '(609)555-9876',
-            'fax' => '',
-            'pager' => '',
-            'title' => '',
-            'role' => '',
-            'company' => '',
-            'category' => '',
-            'notes' => '',
-            'website' => '',
-            'freebusyUrl' => '',
-            'pgpPublicKey' => '',
-            'smimePublicKey' => '',
-        );
+        $contact = new Horde_ActiveSync_Message_Contact();
+        $event = new Horde_ActiveSync_Message_Appointment();
+        $task = new Horde_ActiveSync_Message_Task();
 
         if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
             error_reporting(E_ALL & ~E_DEPRECATED);
         }
-        /* This test REQUIRES that the NLS system be initialized, so skip this
-         * if we don't have a configured horde
-         */
-        if (!file_exists(dirname(__FILE__) . '/../../../../../horde/config/conf.php')) {
-            $this->markTestIncomplete('Test requires the NLS system');
-            return;
-        }
-        require_once dirname(__FILE__) . '/../../../../../horde/lib/core.php';
-        Horde_Nls::setLanguage();
 
-        $fixture = array('contacts_export' => $contact);
+        /* Mock the registry connector */
+        $fixture = array(
+            'contacts_export' => $contact,
+            'calendar_export' => $event,
+            'tasks_export' => $task
+        );
         $connector = new Horde_ActiveSync_MockConnector(array('fixture' => $fixture));
+
+        /* We don't need to remember any state for this test, mock it */
         $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_File');
+
+        /* Get the driver, and test it */
         $driver = new Horde_ActiveSync_Driver_Horde(array('connector' => $connector,
                                                           'state_basic' => $state));
 
-        $results = $driver->getMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER,
-                                       '20070112030603.249j42k3k068@test.theupstairsroom.com',
-                                       0);
+        $results = $driver->getMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER, 'xxx', 0);
         $this->assertType('Horde_ActiveSync_Message_Contact', $results);
-        $this->assertEquals('Dr', $results->title);
-        $this->assertEquals('PharmD', $results->suffix);
-        $this->assertEquals('Michael Joseph Rubinsky', $results->fileas);
-        $this->assertEquals('mrubinsk@horde.org', $results->email1address);
-        $this->assertEquals('1970-03-20', $results->birthday->format('Y-m-d'));
-        $this->assertEquals('(856)555-1234', $results->homephonenumber);
-        $this->assertEquals('(856)555-5678', $results->businessphonenumber);
-        $this->assertEquals('(609)555-9876', $results->mobilephonenumber);
-        $this->assertEquals('123 Main St.', $results->homestreet);
-        $this->assertEquals('Anywhere', $results->homecity);
-        $this->assertEquals('NJ', $results->homestate);
-        $this->assertEquals('08080', $results->homepostalcode);
-        $this->assertEquals('US', $results->homecountry);
-        $this->assertEquals('Kings Hwy', $results->businessstreet);
-        $this->assertEquals('Somewhere', $results->businesscity);
-        $this->assertEquals('NJ', $results->businessstate);
-        $this->assertEquals('08052', $results->businesspostalcode);
-        $this->assertEquals('US', $results->businesscountry);
+
+        $results = $driver->getMessage(Horde_ActiveSync_Driver_Horde::APPOINTMENTS_FOLDER, 'xxx', 0);
+        $this->assertType('Horde_ActiveSync_Message_Appointment', $results);
+
+        $results = $driver->getMessage(Horde_ActiveSync_Driver_Horde::TASKS_FOLDER, 'xxx', 0);
+        $this->assertType('Horde_ActiveSync_Message_Task', $results);
     }
 
     /**
-     * Test that the values present in the contact message are always utf-8.
+     * Test ChangeMessage: Only thing to really test for the changeMessage
+     * method is that it calls the correct API method, with the correct object
+     * type. No data conversion is done in the driver, it's the responsiblity of
+     * the client code.
      */
-    public function testStreamerUTF8()
+    public function testChangeMessage()
     {
-        if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
-            error_reporting(E_ALL & ~E_DEPRECATED);
-        }
+        $this->markTestIncomplete('Test still being written');
+        /* Setup mock connector method return values for adding a new contact */
+        $connector = $this->getMockSkipConstructor('Horde_ActiveSync_Driver_Horde_Connector_Registry');
+        $connector->expects($this->once())->method('contacts_import')->will($this->returnValue(1));
+        $connector->expects($this->at(1))->method('contacts_getActionTimestamp')->will($this->returnValue(array('todo')));
 
-        /* This test REQUIRES that the NLS system be initialized, so skip this
-         * if we don't have a configured horde
-         */
-        if (!file_exists(dirname(__FILE__) . '/../../../../../horde/config/conf.php')) {
-            $this->markTestIncomplete('Test requires the NLS system');
-            return;
-        }
-        require_once dirname(__FILE__) . '/../../../../../horde/lib/core.php';
-        Horde_Nls::setLanguage();
+        /* Setup mock connector return for modifying an existing contact */
+        $connector->expects($this->once())->method('contacts_replace')->will($this->returnValue(2));
+        $connector->expects($this->at(1))->method('contacts_getActionTimestamp')->will($this->returnValue(array('todo')));
 
-        $contact = array(
-            '__uid' => '20100205111228.89913meqtp5u09rg@localhost',
-            'firstname' => Horde_String::convertCharset('Grüb', Horde_Nls::getCharset(), 'iso-8859-1')
-        );
+        /* TODO: appointments and todos */
 
-        $fixture = array('contacts_export' => $contact);
-        $connector = new Horde_ActiveSync_MockConnector(array('fixture' => $fixture));
+        /* We don't need to remember any state for this test, mock it */
         $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_File');
+
+        /* Get the driver, and test it */
         $driver = new Horde_ActiveSync_Driver_Horde(array('connector' => $connector,
                                                           'state_basic' => $state));
-
-        $results = $driver->getMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER,
-                                       '20070112030603.249j42k3k068@test.theupstairsroom.com',
-                                       0);
-
-        $this->assertEquals(Horde_String::convertCharset('Grüb', Horde_Nls::getCharset(), 'utf-8'), $results->firstname);
-    }
-
-    /**
-     * Test ChangeMessage:
-     *
-     * This tests converting the contact streamer object to a hash suitable for
-     * passing to the contacts/import method. Because it only returns the UID
-     * for the newly added/edited entry, we can't check the results here. The
-     * check is done in the MockConnector object, throwing an exception if it
-     * fails.
-     *
-     */
-    public function testChangeMessage()
-    {
         // fixtures
         $message = new Horde_ActiveSync_Message_Contact();
         $message->fileas = 'Michael Joseph Rubinsky';
@@ -242,14 +162,8 @@ class Horde_ActiveSync_HordeDriverTest extends Horde_Test_Case
             error_reporting(E_ALL & ~E_DEPRECATED);
         }
 
-        $connector = new Horde_ActiveSync_MockConnector(array('fixture' => array()));
-        $state = $this->getMockSkipConstructor('Horde_ActiveSync_State_File');
-        $driver = new Horde_ActiveSync_Driver_Horde(array('connector' => $connector,
-                                                          'state_basic' => $state));
-
         try {
-            $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER,
-                                              0, $message);
+            $results = $driver->ChangeMessage(Horde_ActiveSync_Driver_Horde::CONTACTS_FOLDER, 0, $message);
         } catch (Horde_ActiveSync_Exception $e) {
             $this->fail($e->getMessage());
         }
index c990027..d66d3bd 100644 (file)
@@ -596,8 +596,8 @@ class Turba_Api extends Horde_Registry_Api
      *
      * @param string $content      The content of the contact.
      * @param string $contentType  What format is the data in? Currently
-     *                             supports array, text/directory, text/vcard
-     *                             and text/x-vcard.
+     *                             supports array, text/directory, text/vcard,
+     *                             text/x-vcard, and activesync.
      * @param string $source       The source into which the contact will be
      *                             imported.
      *
@@ -684,6 +684,10 @@ class Turba_Api extends Horde_Registry_Api
                 }
                 break;
 
+            case 'activesync':
+                $hash = $driver->fromASContact($content);
+                break;
+
             default:
                 throw new Horde_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
             }
@@ -809,6 +813,13 @@ class Turba_Api extends Horde_Registry_Api
                 }
 
                 return $attributes;
+
+            case 'activesync':
+                foreach ($result->objects as $object) {
+                    $return = $object;
+                }
+
+                return $driver->toASContact($return);
             }
 
             throw new Horde_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
@@ -979,7 +990,7 @@ class Turba_Api extends Horde_Registry_Api
      * @param string $content        The content of the contact.
      * @param string $contentType    What format is the data in? Currently
      *                               supports array, text/directory,
-     *                               text/vcard and text/x-vcard.
+     *                               text/vcard, text/x-vcard and activesync.
      * @param string|array $sources  The source(s) where the contact will be
      *                               replaced.
      *
@@ -1056,6 +1067,9 @@ class Turba_Api extends Horde_Registry_Api
                     throw new Horde_Exception(_("Only one vcard supported."));
                 }
                 break;
+            case 'activesync':
+                $content = $driver->fromASContact($content);
+                break;
 
             default:
                 throw new Horde_Exception(sprintf(_("Unsupported Content-Type: %s"), $contentType));
index 854e905..18443e0 100644 (file)
@@ -2290,6 +2290,231 @@ class Turba_Driver
     }
 
     /**
+     * Convert the contact to an ActiveSync contact message
+     *
+     * @param Turba_Object $object  The turba object to convert
+     *
+     * @return Horde_ActiveSync_Message_Contact
+     */
+    public function toASContact(Turba_Object $object)
+    {
+        $message = new Horde_ActiveSync_Message_Contact(array('logger' => $GLOBALS['injector']->getInstance('Horde_Log_Logger')));
+        $charset = Horde_Nls::getCharset();
+        $hash = $object->getAttributes();
+        //var_dump($hash);
+        foreach ($hash as $field => $value) {
+           switch ($field) {
+            case 'name':
+                $message->fileas = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'lastname':
+                $message->lastname = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'firstname':
+                $message->firstname = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'middlenames':
+                $message->middlename = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'namePrefix':
+                $message->title = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'nameSuffix':
+                $message->suffix = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+
+            case 'photo':
+                $message->picture = base64_encode($value);
+                break;
+
+            /* Address (TODO: check for a single home/workAddress field instead) */
+            case 'homeStreet':
+                $message->homestreet = Horde_String::convertCharset($hash['homeStreet'], $charset, 'utf-8');
+                break;
+            case 'homeCity':
+                $message->homecity = Horde_String::convertCharset($hash['homeCity'], $charset, 'utf-8');
+                break;
+            case 'homeProvince':
+                $message->homestate = Horde_String::convertCharset($hash['homeProvince'], $charset, 'utf-8');
+                break;
+            case 'homePostalCode':
+                $message->homepostalcode = Horde_String::convertCharset($hash['homePostalCode'], $charset, 'utf-8');
+                break;
+            case 'homeCountry':
+                $message->homecountry = Horde_String::convertCharset($hash['homeCountry'], $charset, 'utf-8');
+                break;
+            case 'workStreet':
+                $message->businessstreet = Horde_String::convertCharset($hash['workStreet'], $charset, 'utf-8');
+                break;
+            case 'workCity':
+                $message->businesscity = Horde_String::convertCharset($hash['workCity'], $charset, 'utf-8');
+                break;
+            case 'workProvince':
+                $message->businessstate = Horde_String::convertCharset($hash['workProvince'], $charset, 'utf-8');
+                break;
+            case 'workPostalCode':
+                $message->businesspostalcode = Horde_String::convertCharset($hash['workPostalCode'], $charset, 'utf-8');
+                break;
+            case 'workCountry':
+                $message->businesscountry = Horde_String::convertCharset($hash['workCountry'], $charset, 'utf-8');
+                break;
+            case 'homePhone':
+                /* Phone */
+                $message->homephonenumber = $hash['homePhone'];
+                break;
+            case 'cellPhone':
+                $message->mobilephonenumber = $hash['cellPhone'];
+                break;
+            case 'fax':
+                $message->businessfaxnumber = $hash['fax'];
+                break;
+            case 'workPhone':
+                $message->businessphonenumber = $hash['workPhone'];
+                break;
+            case 'pager':
+                $message->pagernumber = $hash['pager'];
+                break;
+
+            case 'email':
+                $message->email1address = Horde_iCalendar_vcard::getBareEmail($value);
+                break;
+
+            case 'title':
+                $message->jobtitle = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+
+            case 'company':
+                $message->companyname = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'departnemt':
+                $message->department = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+
+            case 'category':
+                // Categories FROM horde are a simple string value, going BACK to horde are an array with 'value' and 'new' keys
+                $message->categories = explode(';', Horde_String::convertCharset($value, $charset, 'utf-8'));
+                break;
+
+            case 'spouse':
+                $message->spouse = Horde_String::convertCharset($value, $charset, 'utf-8');
+                break;
+            case 'notes':
+                $message->body = Horde_String::convertCharset($value, $charset, 'utf-8');
+                $message->bodysize = strlen($message->body);
+                $message->bodytruncated = false;
+                break;
+            case 'website':
+                $message->webpage = $value;
+                break;
+
+            case 'birthday':
+            case 'anniversary':
+                if (!empty($value)) {
+                    $date = new Horde_Date($value);
+                    $message->{$field} = $date;
+                } else {
+                    $message->$field = null;
+                }
+                break;
+            }
+        }
+
+        return $message;
+    }
+
+    /**
+     * Convert an ActiveSync contact message into a hash suitable for importing
+     * via add.
+     *
+     * @param Horde_ActiveSync_Message_Contact $message  The contact message object
+     *
+     * @return array  A contact hash
+     */
+    public function fromASContact($message)
+    {
+        $hash = array();
+        $charset = Horde_Nls::getCharset();
+        $formattedname = false;
+
+        /* Name */
+        $hash['name'] = Horde_String::convertCharset($message->fileas, 'utf-8', $charset);
+        $hash['lastname'] = Horde_String::convertCharset($message->lastname, 'utf-8', $charset);
+        $hash['firstname'] = Horde_String::convertCharset($message->firstname, 'utf-8', $charset);
+        $hash['middlenames'] = Horde_String::convertCharset($message->middlename, 'utf-8', $charset);
+        $hash['namePrefix'] = Horde_String::convertCharset($message->title, 'utf-8', $charset);
+        $hash['nameSuffix'] = Horde_String::convertCharset($message->suffix, 'utf-8', $charset);
+
+        // picture ($message->picture *should* already be base64 encdoed)
+        $hash['photo'] = base64_decode($message->picture);
+
+        /* Home */
+        $hash['homeStreet'] = Horde_String::convertCharset($message->homestreet, 'utf-8', $charset);
+        $hash['homeCity'] = Horde_String::convertCharset($message->homecity, 'utf-8', $charset);
+        $hash['homeProvince'] = Horde_String::convertCharset($message->homestate, 'utf-8', $charset);
+        $hash['homePostalCode'] = $message->homepostalcode;
+        $hash['homeCountry'] = Horde_String::convertCharset($message->homecountry, 'utf-8', $charset);
+
+        /* Business */
+        $hash['workStreet'] = Horde_String::convertCharset($message->businessstreet, 'utf-8', $charset);
+        $hash['workCity'] = Horde_String::convertCharset($message->businesscity, 'utf-8', $charset);
+        $hash['workProvince'] = Horde_String::convertCharset($message->businessstate, 'utf-8', $charset);
+        $hash['workPostalCode'] = $message->businesspostalcode;
+        $hash['workCountry'] = Horde_String::convertCharset($message->businesscountry, 'utf-8', $charset);
+
+        $hash['homePhone'] = $message->homephonenumber;
+        $hash['workPhone'] = $message->businessphonenumber;
+        $hash['fax'] = $message->businessfaxnumber;
+        $hash['pager'] = $message->pagernumber;
+        $hash['cellPhone'] = $message->mobilephonenumber;
+
+        /* Email addresses */
+        $hash['email'] = Horde_iCalendar_vcard::getBareEmail($message->email1address);
+
+        /* Job title */
+        $hash['title'] = Horde_String::convertCharset($message->jobtitle, 'utf-8', $charset);
+
+        $hash['company'] = Horde_String::convertCharset($message->companyname, 'utf-8', $charset);
+        $hash['department'] = Horde_String::convertCharset($message->department, 'utf-8', $charset);
+
+        /* Categories */
+        if (count($message->categories)) {
+            $hash['category']['value'] = Horde_String::convertCharset(implode(';', $message->categories), 'utf-8', $charset);
+            $hash['category']['new'] = true;
+        }
+
+        /* Children */
+        // @TODO
+
+        /* Spouse */
+        $hash['spouse'] = Horde_String::convertCharset($message->spouse, 'utf-8', $charset);
+
+        /* Notes */
+        $hash['notes'] = Horde_String::convertCharset($message->body, 'utf-8', $charset);
+
+        /* webpage */
+        $hash['website'] = Horde_String::convertCharset($message->webpage, 'utf-8', $charset);
+
+        /* Birthday and Anniversary */
+        if (!empty($message->birthday)) {
+            $bday = new Horde_Date($message->birthday);
+            $hash['birthday'] = $bday->format('Y-m-d');
+        } else {
+            $hash['birthday'] = null;
+        }
+        if (!empty($message->anniversary)) {
+            $anniversary = new Horde_Date($message->anniversary);
+            $hash['anniversary'] = $anniversary->format('Y-m-d');
+        } else {
+            $hash['anniversary'] = null;
+        }
+
+        /* Assistant */
+        $hash['assistant'] = Horde_String::convertCharset($message->assistantname, 'utf-8', $charset);
+
+        return $hash;
+    }
+
+    /**
      * Checks if the current user has the requested permissions on this
      * address book.
      *
index fecb4cf..e080261 100644 (file)
@@ -15,7 +15,10 @@ class Turba_ApiTest extends Turba_TestBase {
         require_once TURBA_BASE . '/lib/api.php';
         $this->setUpDatabase();
     }
-
+    function testSomething()
+    {
+     echo 'fail';
+    }
     function test_search_api_should_return_results()
     {
         global $registry;