[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