[sync] patches 1/2

Karsten Fourmont fourmont at gmx.de
Tue Jul 13 05:06:45 PDT 2004


Hi,

strange. Maybe the list handler didn't like the text/x-patch mime type IMP
suggested. Or the total attachment size was just too big. So here's the
first half again with .txt extension.

 Karsten
-------------- next part --------------
? iCalendar/iCalendar/vnote.php
Index: iCalendar/iCalendar.php
===================================================================
RCS file: /repository/framework/iCalendar/iCalendar.php,v
retrieving revision 1.45
diff -u -r1.45 iCalendar.php
--- iCalendar/iCalendar.php	7 Jul 2004 03:12:25 -0000	1.45
+++ iCalendar/iCalendar.php	11 Jul 2004 20:39:14 -0000
@@ -89,6 +89,31 @@
         }
     }
 
+
+    /**
+     * Sets parameter(s) for an (already existing) attribute.
+     * The parameter set is merged into the existing set.
+     *
+     * @param string  $name   The name of the attribute.
+     * @param array   $params Array containing any addition
+     *                        parameters for this attribute.
+     * @return bool           True on success, false on no attribute $name
+     */
+
+    function setParameter($name, $params)
+    {
+        $keys = array_keys($this->_attributes);
+        foreach ($keys as $key) {
+            if ($this->_attributes[$key]['name'] == $name) {
+                $this->_attributes[$key]['params'] = 
+                   array_merge($this->_attributes[$key]['params'] , $params);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * Get the value of an attribute.
      *
@@ -294,6 +319,17 @@
         // Unfold any folded lines.
         $vCal = preg_replace ('/(\r|\n)+ /', '', $vCal);
 
+        // Unfold braindead "quoted printable" folded lines like:
+        //  BODY;ENCODING=QUOTED-PRINTABLE:=
+        //  another=20line=
+        //  last=20line
+        if (preg_match_all('/^([^:]+;\s*ENCODING=QUOTED-PRINTABLE(.*=\r?\n)+(.*[^=])?\r?\n)/mU', $vCal, $matches)) {
+            foreach($matches[1] as $s) {
+                $r = preg_replace('/=\r?\n/', '', $s);
+                $vCal=str_replace($vCal, $s, $r);
+            }
+        }
+
         // Parse the remaining attributes.
         if (preg_match_all('/(.*):(.*)(\r|\n)+/', $vCal, $matches)) {
             foreach ($matches[0] as $attribute) {
@@ -310,6 +346,24 @@
                     }
                 }
 
+                // charset and encoding handling.
+                if (isset($params['ENCODING']) &&
+                       $params['ENCODING'] == 'QUOTED-PRINTABLE') {
+                    $value = quoted_printable_decode($value);
+                }
+
+                if (isset($params['QUOTED-PRINTABLE'])) {
+                    $value = quoted_printable_decode($value);
+                }
+
+                if (isset($params['CHARSET'])) {
+                    $value = String::convertCharset($value, $params['CHARSET']);
+                } else {
+                    // As per RFC 2279, assume UTF8 if we don't have an
+                    // explicit charset parameter.
+                    $value = String::convertCharset($value, 'utf-8');
+                }
+
                 switch ($tag) {
                 case 'DESCRIPTION':
                     $value = preg_replace('/\\\\,/', ',', $value);
@@ -464,6 +518,7 @@
             case 'DTSTAMP':
             case 'COMPLETED':
             case 'CREATED':
+            case 'DCREATED':
             case 'LAST-MODIFIED':
                 $value = $this->_exportDateTime($value);
                 break;
@@ -548,8 +603,16 @@
             case 'RRULE':
             }
 
-            $attr_string = "$name$params_str:$value";
-            $result .= $this->_foldLine($attr_string) . $this->_newline;
+            if (!empty($params['ENCODING']) 
+                    && $params['ENCODING'] == 'QUOTED-PRINTABLE' && strlen(trim($value))>0) {
+                $value = str_replace("\r", '', $value);
+                $result .= "$name$params_str:=" . $this->_newline
+                        .  $this->quoted_printable_encode($value)
+                        .  $this->_newline;
+            } else {
+                $attr_string = "$name$params_str:$value";
+                $result .= $this->_foldLine($attr_string) . $this->_newline;
+            }
         }
 
         foreach ($this->getComponents() as $component) {
@@ -878,4 +941,38 @@
         return $line;
     }
 
+
+     /**
+        Convert an 8bit string to a quoted-printable string 
+        according to RFC2045, section 6.7 
+
+        Uses imap_8bit if installed.
+
+     * @param  string $input The string to be encoded
+     * @return string        The quoted-printable encoded string.
+     *
+     */
+      
+    function quoted_printable_encode( $input = "") {
+
+        // if we have imap installed, use it:
+        if (function_exists('imap_8bit')) {
+            return imap_8bit($input);
+        }
+
+        // rather dump replacment: just encode everything:
+        $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
+
+        $output = "";
+        $len = strlen($input);
+        for ($i = 0; $i < $len; ++$i) {
+            $c = substr($input, $i, 1 );
+            $dec = ord($c);
+            $output .= '=' . $hex[ floor($dec/16) ] . $hex[ floor($dec%16) ];
+            if( ($i+1) % 25 == 0) {
+                $output .= "=\r\n";
+            }
+        }
+        return $output;
+    }
 }
Index: iCalendar/package.xml
===================================================================
RCS file: /repository/framework/iCalendar/package.xml,v
retrieving revision 1.7
diff -u -r1.7 package.xml
--- iCalendar/package.xml	4 Dec 2003 01:18:14 -0000	1.7
+++ iCalendar/package.xml	11 Jul 2004 20:39:14 -0000
@@ -29,6 +29,7 @@
         <file name="vevent.php"/>
         <file name="vfreebusy.php"/>
         <file name="vjournal.php"/>
+        <file name="vnote.php"/>
         <file name="vtimezone.php"/>
         <file name="vtodo.php"/>
       </dir>
-------------- next part --------------
Index: lib/Driver.php
===================================================================
RCS file: /repository/kronolith/lib/Driver.php,v
retrieving revision 1.76
diff -u -r1.76 Driver.php
--- lib/Driver.php	30 Jun 2004 22:00:46 -0000	1.76
+++ lib/Driver.php	11 Jul 2004 20:42:54 -0000
@@ -558,6 +558,99 @@
         return $vcal;
     }
 
+   /**
+     * Export this event in iCalendar format.
+     * This function can later replace toiCalendar.
+     *
+     * @param object vcal      a Horde_iCalendar object that acts as container.
+     * @param object Identity  $identity  The Identity object of the organizer.
+     *
+     * @return object  Horde_iCalendar_vevent object for this event
+     */
+     
+    function tovEvent(&$calendar, $identity)
+    {
+        global $prefs;
+
+        // Get a reference to the calendar object.
+        $kronolith = &$this->getDriver();
+
+        $vevent = &Horde_iCalendar::newComponent('vevent', $calendar);
+        
+
+        if ($this->isAllDay()) {
+            $vevent->setAttribute('DTSTART', $this->startTimestamp, array( 'VALUE' => 'DATE'));
+            $vevent->setAttribute('DTEND', $this->endTimestamp, array( 'VALUE' => 'DATE'));
+        } else {
+            $vevent->setAttribute('DTSTART', $this->startTimestamp);
+            $vevent->setAttribute('DTEND', $this->endTimestamp);
+        }
+
+        $vevent->setAttribute('DTSTAMP', time());
+        $vevent->setAttribute('UID', $kronolith->getGUID($this->eventID));
+        $vevent->setAttribute('SUMMARY', $this->title);
+        $vevent->setAttribute('DESCRIPTION', $this->description);
+        $vevent->setAttribute('CATEGORIES', $this->getCategory());
+        $vevent->setAttribute('LOCATION', $this->location);
+        $vevent->setAttribute('TRANSP', 'OPAQUE');
+        $vevent->setAttribute('ORGANIZER',
+                              'MAILTO:' . $identity->getValue('from_addr'),
+                              array('CN' => $identity->getValue('fullname')));
+
+        // Recurrence.
+        if ($this->recurType) {
+            $rrule = '';
+            switch ($this->recurType) {
+            case KRONOLITH_RECUR_NONE:
+                break;
+
+            case KRONOLITH_RECUR_DAILY:
+                $rrule = 'FREQ=DAILY;INTERVAL='  . $this->recurInterval;
+                break;
+
+            case KRONOLITH_RECUR_WEEKLY:
+                $rrule = 'FREQ=WEEKLY;INTERVAL=' . $this->recurInterval . ';BYDAY=';
+                $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+
+                for ($i = $flag = 0; $i <= 7 ; $i++) {
+                    if ($this->recurOnDay(pow(2, $i))) {
+                        if ($flag) {
+                            $rrule .= ',';
+                        }
+                        $rrule .= $vcaldays[$i];
+                        $flag = true;
+                    }
+                }
+                break;
+
+            case KRONOLITH_RECUR_DAY_OF_MONTH:
+                $rrule = 'FREQ=MONTHLY;INTERVAL=' . $this->recurInterval;
+                break;
+
+            case KRONOLITH_RECUR_WEEK_OF_MONTH:
+                $vcaldays = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA');
+                $rrule = 'FREQ=MONTHLY;INTERVAL=' . $this->recurInterval . ';BYDAY=' .
+                    ((date('W', $this->startTimestamp) - date('W', mktime(0, 0, 0, date('n', $this->startTimestamp), 1,
+                                                                          date('Y', $this->startTimestamp)))) + 1) .
+                    $vcaldays[date('w', $this->startTimestamp)];
+                break;
+
+            case KRONOLITH_RECUR_YEARLY:
+                $rrule = 'FREQ=YEARLY;INTERVAL=' . $this->recurInterval;
+                break;
+            }
+
+            if (!empty($rrule) && !empty($this->recurEndTimestamp)) {
+                $rrule .= ';UNTIL=' . $calendar->_exportDate($this->recurEnd);
+            }
+            if (!empty($rrule)) {
+                $vevent->setAttribute('RRULE', $rrule);
+            }
+        }
+
+        return $vevent;
+    }
+
     /**
      * Update the properties of this event from a
      * Horde_iCalendar_vevent object.
Index: lib/api.php
===================================================================
RCS file: /repository/kronolith/lib/api.php,v
retrieving revision 1.117
diff -u -r1.117 api.php
--- lib/api.php	2 Jul 2004 22:07:49 -0000	1.117
+++ lib/api.php	11 Jul 2004 20:42:55 -0000
@@ -195,12 +195,19 @@
  * Export an event, identified by GUID, in the requested contentType.
  *
  * @param string $guid         Identify the event to export.
- * @param string $contentType  What format should the data be in? Currently supports:
+ * @param mixed  $contentType  What format should the data be in?
+ *                             Either a string with one of:
  *                             text/x-icalendar
  *                             text/x-vcalendar
+ *                             or an array with options:
+ *                             'ContentType':  as above
+ *                             'ENCODING': (optional) character encoding 
+ *                                         for strings fields
+ *                             'CHARSET':  (optional) charset. Like UTF-8
  *
  * @return string  The requested data.
  */
+ 
 function _kronolith_export($guid, $contentType)
 {
     require_once dirname(__FILE__) . '/base.php';
@@ -215,16 +222,45 @@
         return PEAR::raiseError(_("Permission Denied"));
     }
 
+    if( is_array($contentType)) {
+        $options = $contentType;
+        $contentType = $options['ContentType'];
+    } else {
+        $options = array();
+    }
+
     switch ($contentType) {
     case 'text/calendar':
     case 'text/x-icalendar':
     case 'text/x-vcalendar':
-        require_once 'Horde/Data.php';
-        $vcs = &Horde_Data::singleton('icalendar');
         $identity = &$kronolith_shares->getIdentityByShare($kronolith_shares->getShare($event->getCalendar()));
-        $data = array($event->toiCalendar($vcs, $identity));
-        return $vcs->exportData($data);
 
+        require_once 'Horde/iCalendar.php';
+
+        // Create the new iCalendar.
+        $vCal = &new Horde_iCalendar();
+
+        // Create new vevent.
+        $vnote = & $event->tovEvent($vCal, $identity);
+        
+        if(!empty($options['ENCODING'])) {
+            $o['ENCODING'] = $options['ENCODING'];
+        }
+        if(!empty($options['CHARSET'])) {
+            $o['CHARSET'] = $options['CHARSET'];
+        }
+
+        // Set encoding options for all string values. 
+        if(isset($o) && is_array($o)) {
+            $vnote->setParameter('SUMMARY', $o);
+            $vnote->setParameter('DESCRIPTION', $o);
+            $vnote->setParameter('LOCATION', $o);
+        }
+
+        $vCal->addComponent($vnote);
+        
+        return $vCal->exportvCalendar();
+        
     default:
         return PEAR::raiseError(_("Unsupported Content-Type."));
     }
-------------- next part --------------
Index: lib/Driver.php
===================================================================
RCS file: /repository/mnemo/lib/Driver.php,v
retrieving revision 1.23
diff -u -r1.23 Driver.php
--- lib/Driver.php	7 Apr 2004 14:43:37 -0000	1.23
+++ lib/Driver.php	11 Jul 2004 20:44:46 -0000
@@ -165,4 +165,84 @@
         return $instances[$signature];
     }
 
+
+  /**
+     * Export this memo in iCalendar format.
+     *
+     * @param array  memo      the memo (hash array) to export
+     * @param object vcal      a Horde_iCalendar object that acts as container.
+     *
+     * @return object  Horde_iCalendar_vnote object for this event
+     */
+     
+    function toiCalendar($memo, &$calendar)
+    {
+        require_once 'Horde/History.php';
+        
+        global $prefs;
+
+        $vnote = &Horde_iCalendar::newComponent('vnote', $calendar);
+
+        $guid = $this->getGUID($memo['memo_id']);
+        $vnote->setAttribute('UID', $guid);
+        
+        $vnote->setAttribute('BODY', $memo['body']);
+
+        /* Get the note's history. */
+        $history = &Horde_History::singleton();
+        $log = $history->getHistory($guid);
+        foreach ($log->getData() as $entry) {
+            switch ($entry['action']) {
+            case 'add':
+                $created = $entry['ts'];
+                break;
+
+            case 'modify':
+                $modified = $entry['ts'];
+                break;
+            }
+        }
+        if(!empty($created)) {
+            $vnote->setAttribute('DCREATED', $created);
+        }
+        if(!empty($modified)) {
+            $vnote->setAttribute('LAST-MODIFIED', $modified);
+        }
+
+        if(!empty($memo['category'])) {
+            $vnote->setAttribute('CATEGORIES', $memo['category']);
+        }
+        
+        return $vnote;
+    }
+    
+    /**
+     * create a memo (hash array) from an 
+     * Horde_iCalendar_vnote object.
+     *
+     * @param Horde_iCalendar_vnote $vnote  The iCalendar data to update from.
+     *
+     * @return array memo (hash array) created from vnote
+     */
+    function fromiCalendar($vnote)
+    {
+        $r = array();
+        
+        $body = $vnote->getAttribute('BODY');
+        if (!is_array($body) && !is_a($body, 'PEAR_Error')) {
+            $r['body'] = $body;
+        } else {
+            $r['body'] = '';
+        }
+
+        $r['desc'] = $this->getMemoDescription($r['body']);
+        
+        $cat = $vnote->getAttribute('CATEGORIES');
+        if (!is_array($cat) && !is_a($cat, 'PEAR_Error')) {
+            $r['category'] = $cat;
+        }
+
+        return $r;        
+    }
+    
 }
Index: lib/api.php
===================================================================
RCS file: /repository/mnemo/lib/api.php,v
retrieving revision 1.50
diff -u -r1.50 api.php
--- lib/api.php	2 Jul 2004 22:07:49 -0000	1.50
+++ lib/api.php	11 Jul 2004 20:44:47 -0000
@@ -129,18 +129,25 @@
         break;
 
     case 'text/x-vnote':
-        require_once 'Horde/Data.php';
-        $vnote = &Horde_Data::singleton('vnote');
-        $notes = $vnote->importData($content);
+        require_once 'Horde/iCalendar.php';
 
-        if (count($notes) != 1) {
-            return PEAR::raiseError('one note expected');
+        // Create the new iCalendar.
+        $vCal = &new Horde_iCalendar();
+        $vCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN');
+        $vCal->setAttribute('METHOD', 'PUBLISH');
+
+        // Create new note.
+        $vnote = &Horde_iCalendar::newComponent('vnote', $vCal);
+
+        if (!$vnote->parsevCalendar($content)) {
+            return PEAR::raiseError(_("There was an error importing the vNote data."));
         }
+        $note = $storage->fromiCalendar($vnote);
 
-        $note = $vnote->toHash($notes[0]);
-        $noteId = $storage->add($storage->getMemoDescription($note['body']), $note['body']);
+        $noteId = $storage->add($note['desc'], 
+                $note['body'], !empty($note['category']) ? $note['category'] : '');
         break;
-
+    
     default:
         return PEAR::raiseError(_("Unsupported Content-Type."));
     }
@@ -156,9 +163,15 @@
  * Export a memo, identified by GUID, in the requested contentType.
  *
  * @param string $guid         Identify the memo to export.
- * @param string $contentType  What format should the data be in? Currently supports:
- *                             text/plain
- *                             text/x-vnote
+ * @param mixed  $contentType  What format should the data be in?
+ *                             Either a string with one of:
+ *                              'text/plain'
+ *                              'text/x-vnote'
+ *                             or an array with options:
+ *                             'ContentType':  as above
+ *                             'ENCODING': (optional) character encoding 
+ *                                         for strings fields
+ *                             'CHARSET':  (optional) charset. Like UTF-8
  *
  * @return string  The requested data.
  */
@@ -176,15 +189,43 @@
         return PEAR::raiseError(_("Permission Denied"));
     }
 
+    if( is_array($contentType)) {
+        $options = $contentType;
+        $contentType = $options['ContentType'];
+    } else {
+        $options = array();
+    }
+
     switch ($contentType) {
     case 'text/plain':
         return $memo['body'];
 
     case 'text/x-vnote':
-        require_once 'Horde/Data.php';
-        $vnote = &Horde_Data::singleton('vnote');
-        return $vnote->exportData($vnote->fromHash($memo));
+        require_once 'Horde/iCalendar.php';
 
+        // Create the new iCalendar.
+        $vCal = &new Horde_iCalendar();
+        $vCal->setAttribute('VERSION', '1.1');
+        $vCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN');
+        $vCal->setAttribute('METHOD', 'PUBLISH');
+
+        // Create new note.
+        $vnote = $storage->toiCalendar($memo,$vCal);
+        
+        if(!empty($options['ENCODING'])) {
+            $o['ENCODING'] = $options['ENCODING'];
+        }
+        if(!empty($options['CHARSET'])) {
+            $o['CHARSET'] = $options['CHARSET'];
+        }
+
+        // Set encoding options for all string values. 
+        // For vnote only body:
+        if(isset($o) && is_array($o)) {
+            $vnote->setParameter('BODY', $o);
+        }
+        
+        return $vnote->exportvCalendar();
     default:
         return PEAR::raiseError(_("Unsupported Content-Type."));
     }
@@ -249,7 +290,7 @@
     if (is_a($memo, 'PEAR_Error')) {
         return $memo;
     }
-
+    
     if (!array_key_exists($memo['memolist_id'], Mnemo::listNotepads(false, PERMS_EDIT))) {
         return PEAR::raiseError(_("Permission Denied"));
     }
@@ -259,17 +300,23 @@
         return $storage->modify($memo['memo_id'], $storage->getMemoDescription($content), $content, null);
 
     case 'text/x-vnote':
-        require_once 'Horde/Data.php';
-        $vnote = &Horde_Data::singleton('vnote');
-        $notes = $vnote->importData($content);
+        require_once 'Horde/iCalendar.php';
 
-        if (count($notes) != 1) {
-            return PEAR::raiseError('one note expected');
-        }
+        // Create the new iCalendar.
+        $vCal = &new Horde_iCalendar();
+        $vCal->setAttribute('PRODID', '-//The Horde Project//Mnemo //EN');
+        $vCal->setAttribute('METHOD', 'PUBLISH');
+
+        // Create new note.
+        $vnote = &Horde_iCalendar::newComponent('vnote', $vCal);
 
-        $note = $vnote->toHash($notes[0]);
-        return $storage->modify($memo['memo_id'], $storage->getMemoDescription($note['body']), $note['body'], null);
+        if (!$vnote->parsevCalendar($content)) {
+            return PEAR::raiseError(_("There was an error importing the vNote data."));
+        }
+        $note = $storage->fromiCalendar($vnote);
 
+        return $storage->modify($memo['memo_id'], $note['desc'],
+                $note['body'],!empty($note['category']) ? $note['category'] : '');
     default:
         return PEAR::raiseError(_("Unsupported Content-Type."));
     }


More information about the sync mailing list