]> err.no Git - sope/commitdiff
added iCal renderer
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Tue, 19 Oct 2004 22:09:35 +0000 (22:09 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Tue, 19 Oct 2004 22:09:35 +0000 (22:09 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@280 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-ical/NGiCal/ChangeLog
sope-ical/NGiCal/GNUmakefile
sope-ical/NGiCal/Version
sope-ical/NGiCal/iCalCalendar.h
sope-ical/NGiCal/iCalEntityObject.h
sope-ical/NGiCal/iCalEntityObject.m
sope-ical/NGiCal/iCalEvent.h
sope-ical/NGiCal/iCalEvent.m
sope-ical/NGiCal/iCalObject.h
sope-ical/NGiCal/iCalRenderer.h [new file with mode: 0644]
sope-ical/NGiCal/iCalRenderer.m [new file with mode: 0644]

index 100ac04968704f43260a7a9427629826120a2248..bfcdcefe06629ee601c40043df2d3b0e0c2bb73d 100644 (file)
@@ -1,3 +1,12 @@
+2004-10-20  Helge Hess  <helge.hess@opengroupware.org>
+
+       * v4.3.32
+
+       * iCalEvent.m: added -vEvent method to produce an iCalendar
+         representation of an event
+
+       * added iCalRenderer class based on the SOGo render by ZNeK
+
 2004-10-14  Marcus Mueller  <znek@mulle-kybernetik.com>
 
        * NGiCal.xmap: added "categories" mapping (v4.3.31)
index ea872bbbdfd31fbe15305706f2924b78a6d33ed5..cbcb84dc6e328378ad89dbeea3c1b28b51f89afb 100644 (file)
@@ -27,6 +27,7 @@ libNGiCal_HEADER_FILES =      \
        iCalTrigger.h           \
        iCalDataSource.h        \
        iCalEventChanges.h      \
+       iCalRenderer.h          \
 
 #      IcalResponse.h          \
 
@@ -48,6 +49,7 @@ libNGiCal_OBJC_FILES =        \
        iCalTrigger.m           \
        iCalDataSource.m        \
        iCalEventChanges.m      \
+       iCalRenderer.m          \
 
 #      NSString+ICal.m         \
 #      IcalElements.m
index 5c4b8ca3c6f320770fb9618fa34aafa4ee39c9d1..d5af3010e57533290654674cd600f75bc35d9a6d 100644 (file)
@@ -1,5 +1,5 @@
-# $Id: Version 12 2004-08-20 19:49:55Z helge $
+# version file
 
 MAJOR_VERSION=4
 MINOR_VERSION=3
-SUBMINOR_VERSION:=31
+SUBMINOR_VERSION:=32
index 38c6746158f8c18097085ea44386d7e90f56c436..b53f858f21ca293b53a2ab2e82108416458e28c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
-  Copyright (C) 2000-2003 SKYRIX Software AG
+  Copyright (C) 2000-2004 SKYRIX Software AG
 
-  This file is part of OGo
+  This file is part of OpenGroupware.org.
 
   OGo is free software; you can redistribute it and/or modify it under
   the terms of the GNU Lesser General Public License as published by the
@@ -18,7 +18,6 @@
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #ifndef __NGiCal_iCalCalendar_H__
 #define __NGiCal_iCalCalendar_H__
index c7c85f42412d2f7131e712e232ffc35396f341f9..1c844b939c9938236339dcc46fbb9f859da4c1ed 100644 (file)
@@ -18,7 +18,6 @@
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #ifndef __NGiCal_iCalEntityObject_H__
 #define __NGiCal_iCalEntityObject_H__
index 905fbc68b5c3ed7ee6c84bf0196cd7a3c2acd9f7..5130417b6f3a27759607fa08bf0e2c9366656dc2 100644 (file)
@@ -18,7 +18,6 @@
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #include "iCalEntityObject.h"
 #include "iCalPerson.h"
index 19f74fcb0ec0508f8c7b1a2a8ab83d1a6f873275..b6bfa955c468d9df87e271fb3115625cd7e91706 100644 (file)
@@ -1,7 +1,7 @@
 /*
-  Copyright (C) 2000-2003 SKYRIX Software AG
+  Copyright (C) 2000-2004 SKYRIX Software AG
 
-  This file is part of OGo
+  This file is part of OpenGroupware.org.
 
   OGo is free software; you can redistribute it and/or modify it under
   the terms of the GNU Lesser General Public License as published by the
@@ -18,7 +18,6 @@
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #ifndef __NGiCal_iCalEvent_H__
 #define __NGiCal_iCalEvent_H__
 - (BOOL)hasDuration;
 - (NSTimeInterval)durationAsTimeInterval;
 
+/* calculating changes */
+
 - (iCalEventChanges *)getChangesRelativeToEvent:(iCalEvent *)_event;
 
+/* generating iCal content */
+
+- (NSString *)vEventString;
+
 @end 
 
 #endif /* __NGiCal_iCalEvent_H__ */
index b88259e5fc6f4e34aee57c2e9ee2e805a4d0e5b1..72fb3a95d7e3bc2bea1717639d7da878a9bab78e 100644 (file)
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #include "iCalEvent.h"
 #include "iCalPerson.h"
 #include "iCalEventChanges.h"
+#include "iCalRenderer.h"
 #include "common.h"
 
 @interface NSString(DurationTimeInterval)
                            toEvent:self];
 }
 
+/* generating iCal content */
+
+- (NSString *)vEventString {
+  return [[iCalRenderer sharedICalendarRenderer] vEventStringForEvent:self];
+}
+
 @end /* iCalEvent */
 
 @implementation NSString(DurationTimeInterval)
index 0ed2228b496c1476695c6aebfe1780410cc56e64..2b6983281e855031f927ac0bdf73ac09533cbde5 100644 (file)
@@ -18,7 +18,6 @@
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #ifndef __NGiCal_iCalObject_H__
 #define __NGiCal_iCalObject_H__
diff --git a/sope-ical/NGiCal/iCalRenderer.h b/sope-ical/NGiCal/iCalRenderer.h
new file mode 100644 (file)
index 0000000..e9857a5
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+  Copyright (C) 2004 SKYRIX Software AG
+
+  This file is part of OpenGroupware.org.
+
+  OGo is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with OGo; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#ifndef        __NGiCal_iCalRenderer_H_
+#define        __NGiCal_iCalRenderer_H_
+
+#import <Foundation/NSObject.h>
+
+/*
+  iCalRenderer
+
+  Transform an iCalEvent into an iCalendar formatted string.
+*/
+
+@class NSString, NSCharacterSet;
+@class iCalEvent;
+
+@interface iCalRenderer : NSObject
+
++ (id)sharedICalendarRenderer;
+
+- (NSString *)vEventStringForEvent:(iCalEvent *)_apt;
+- (NSString *)iCalendarStringForEvent:(iCalEvent *)_apt;
+
+@end
+
+#import <Foundation/NSString.h>
+
+@interface NSString (SOGoiCal)
+
+- (NSString *)iCalDQUOTESafeString;
+- (NSString *)iCalSafeString;
+- (NSString *)iCalEscapedStringWithEscapeSet:(NSCharacterSet *)_es;
+    
+@end
+
+#endif /* __NGiCal_iCalRenderer_H_ */
diff --git a/sope-ical/NGiCal/iCalRenderer.m b/sope-ical/NGiCal/iCalRenderer.m
new file mode 100644 (file)
index 0000000..dec0e08
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+  Copyright (C) 2004 SKYRIX Software AG
+
+  This file is part of OpenGroupware.org.
+
+  OGo is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  OGo is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+  License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with OGo; see the file COPYING.  If not, write to the
+  Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+  02111-1307, USA.
+*/
+
+#include "iCalRenderer.h"
+#include "iCalEvent.h"
+#include "iCalPerson.h"
+#include "common.h"
+
+@interface NSDate(UsedPrivates)
+- (NSString *)icalString; // declared in NGiCal
+@end
+
+@implementation iCalRenderer
+
+static iCalRenderer *renderer = nil;
+
+/* assume length of 1K - reasonable ? */
+static unsigned DefaultICalStringCapacity = 1024;
+
++ (id)sharedICalendarRenderer {
+  if (renderer == nil)
+    renderer = [[self alloc] init];
+  return renderer;
+}
+
+/* renderer */
+
+- (void)addPreambleForAppointment:(iCalEvent *)_apt
+  toString:(NSMutableString *)s
+{
+  [s appendString:@"BEGIN:VCALENDAR\r\nMETHOD:REQUEST\r\n"];
+  [s appendString:@"PRODID:NGiCal/4.3\r\n"];
+  [s appendString:@"VERSION:2.0\r\n"];
+}
+- (void)addPostambleForAppointment:(iCalEvent *)_apt
+  toString:(NSMutableString *)s
+{
+  [s appendString:@"END:VCALENDAR\r\n"];
+}
+
+- (void)addOrganizer:(iCalPerson *)p toString:(NSMutableString *)s {
+  NSString *x;
+  
+  if (![p isNotNull]) return;
+  
+  [s appendString:@"ORGANIZER;CN=\""];
+  if ((x = [p cn]))
+    [s appendString:[x iCalDQUOTESafeString]];
+  
+  [s appendString:@"\""];
+  if ((x = [p email])) {
+    [s appendString:@":"]; /* sic! */
+    [s appendString:[x iCalSafeString]];
+  }
+  [s appendString:@"\r\n"];
+}
+
+- (void)addAttendees:(NSArray *)persons toString:(NSMutableString *)s {
+  unsigned   i, count;
+  iCalPerson *p;
+
+  count   = [persons count];
+  for (i = 0; i < count; i++) {
+    NSString *x;
+    
+    p = [persons objectAtIndex:i];
+    [s appendString:@"ATTENDEE;"];
+    
+    if ((x = [p role])) {
+      [s appendString:@"ROLE="];
+      [s appendString:[x iCalSafeString]];
+      [s appendString:@";"];
+    }
+    
+    [s appendString:@"CN=\""];
+    if ((x = [p cn])) {
+      [s appendString:[x iCalDQUOTESafeString]];
+    }
+    [s appendString:@"\""];
+    if ([(x = [p email]) isNotNull]) {
+      [s appendString:@":"]; /* sic! */
+      [s appendString:[x iCalSafeString]];
+    }
+    [s appendString:@"\r\n"];
+  }
+}
+
+- (void)addVEventForAppointment:(iCalEvent *)event
+  toString:(NSMutableString *)s
+{
+  [s appendString:@"BEGIN:VEVENT\r\n"];
+  
+  [s appendString:@"SUMMARY:"];
+  [s appendString:[[event summary] iCalSafeString]];
+  [s appendString:@"\r\n"];
+  if ([[event location] length] > 0) {
+    [s appendString:@"LOCATION:"];
+    [s appendString:[[event location] iCalSafeString]];
+    [s appendString:@"\r\n"];
+  }
+  [s appendString:@"UID:"];
+  [s appendString:[event uid]];
+  [s appendString:@"\r\n"];
+  
+  [s appendString:@"DTSTART:"];
+  [s appendString:[[event startDate] icalString]];
+  [s appendString:@"\r\n"];
+  
+  if ([event hasEndDate]) {
+    [s appendString:@"DTEND:"];
+    [s appendString:[[event endDate] icalString]];
+    [s appendString:@"\r\n"];
+  }
+  if ([event hasDuration]) {
+    [s appendString:@"DURATION:"];
+    [s appendString:[event duration]];
+    [s appendString:@"\r\n"];
+  }
+  if ([[event priority] length] > 0) {
+    [s appendString:@"PRIORITY:"];
+    [s appendString:[event priority]];
+    [s appendString:@"\r\n"];
+  }
+  if ([[event categories] length] > 0) {
+    NSString *catString;
+    
+    catString = [event categories];
+    [s appendString:@"CATEGORIES:"];
+    [s appendString:catString];
+    [s appendString:@"\r\n"];
+  }
+  if ([[event comment] length] > 0) {
+    [s appendString:@"DESCRIPTION:"]; /* this is what iCal.app does */
+    [s appendString:[[event comment] iCalSafeString]];
+    [s appendString:@"\r\n"];
+  }
+
+  [s appendString:@"STATUS:"];
+  [s appendString:[event status]];
+  [s appendString:@"\r\n"];
+
+  
+  /* what's all this? */
+  [s appendString:@"TRANSP:OPAQUE\r\n"]; /* transparency */
+  [s appendString:@"CLASS:PRIVATE\r\n"]; /* classification [like 'top secret'] */
+  
+  [self addOrganizer:[event organizer] toString:s];
+  [self addAttendees:[event attendees] toString:s];
+  
+  /* postamble */
+  [s appendString:@"END:VEVENT\r\n"];
+}
+
+- (BOOL)isValidAppointment:(iCalEvent *)_apt {
+  if (![_apt isNotNull])
+    return NO;
+  
+  if ([[_apt uid] length] == 0) {
+    [self logWithFormat:
+           @"WARNING: got apt without uid, rejecting iCal generation: %@", 
+           _apt];
+    return NO;
+  }
+  if ([[[_apt startDate] icalString] length] == 0) {
+    [self logWithFormat:
+           @"WARNING: got apt without start date, "
+           @"rejecting iCal generation: %@",
+           _apt];
+    return NO;
+  }
+  
+  return YES;
+}
+
+- (NSString *)vEventStringForEvent:(iCalEvent *)_apt {
+  NSMutableString *s;
+  
+  if (![self isValidAppointment:_apt])
+    return nil;
+  
+  s = [NSMutableString stringWithCapacity:DefaultICalStringCapacity];
+  [self addVEventForAppointment:_apt toString:s];
+  return s;
+}
+
+- (NSString *)iCalendarStringForEvent:(iCalEvent *)_apt {
+  NSMutableString *s;
+  
+  if (![self isValidAppointment:_apt])
+    return nil;
+  
+  s = [NSMutableString stringWithCapacity:DefaultICalStringCapacity];
+  [self addPreambleForAppointment:_apt  toString:s];
+  [self addVEventForAppointment:_apt    toString:s];
+  [self addPostambleForAppointment:_apt toString:s];
+  return s;
+}
+
+@end /* iCalRenderer */
+
+@interface NSString (SOGoiCal_Private)
+- (NSString *)iCalCleanString;
+@end
+
+@interface SOGoICalStringEscaper : NSObject <NGStringEscaping>
+{
+}
++ (id)sharedEscaper;
+@end
+
+@implementation SOGoICalStringEscaper
++ (id)sharedEscaper {
+  static id sharedInstance = nil;
+  if (!sharedInstance) {
+    sharedInstance = [[self alloc] init];
+  }
+  return sharedInstance;
+}
+
+- (NSString *)stringByEscapingString:(NSString *)_s {
+  unichar c;
+
+  if (!_s || [_s length] == 0)
+    return nil;
+
+  c = [_s characterAtIndex:0];
+  if (c == '\n') {
+    return @"\\n";
+  }
+  else if (c == '\r') {
+    return nil; /* effectively remove char */
+  }
+  return [NSString stringWithFormat:@"\\%@", _s];
+}
+
+@end
+
+@implementation NSString (SOGoiCal)
+
+#if 0
+- (NSString *)iCalFoldedString {
+  /* RFC2445, 4.1 Content Lines
+  
+  The iCalendar object is organized into individual lines of text,
+  called content lines. Content lines are delimited by a line break,
+  which is a CRLF sequence (US-ASCII decimal 13, followed by US-ASCII
+                            decimal 10).
+  Lines of text SHOULD NOT be longer than 75 octets, excluding the line
+  break. Long content lines SHOULD be split into a multiple line
+  representations using a line "folding" technique. That is, a long
+  line can be split between any two characters by inserting a CRLF
+  immediately followed by a single linear white space character (i.e.,
+  SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9).
+  Any sequence of CRLF followed immediately by a single linear white space
+  character is ignored (i.e., removed) when processing the content type.
+  */
+}
+#endif
+
+/* strip off any characters from string which are not allowed in iCal */
+- (NSString *)iCalCleanString {
+  static NSCharacterSet *replaceSet = nil;
+
+  if (replaceSet == nil) {
+    replaceSet = [NSCharacterSet characterSetWithCharactersInString:@"\r"];
+    [replaceSet retain];
+  }
+  
+  return [self stringByEscapingCharactersFromSet:replaceSet
+               usingStringEscaping:[SOGoICalStringEscaper sharedEscaper]];
+}
+
+- (NSString *)iCalDQUOTESafeString {
+  static NSCharacterSet *escapeSet = nil;
+  
+  if (escapeSet == nil) {
+    escapeSet = [NSCharacterSet characterSetWithCharactersInString:@"\\\""];
+    [escapeSet retain];
+  }
+  return [self iCalEscapedStringWithEscapeSet:escapeSet];
+}
+
+- (NSString *)iCalSafeString {
+  static NSCharacterSet *escapeSet = nil;
+  
+  if (escapeSet == nil) {
+    escapeSet = 
+      [[NSCharacterSet characterSetWithCharactersInString:@"\n,;\\\""] retain];
+  }
+  return [self iCalEscapedStringWithEscapeSet:escapeSet];
+}
+
+/* Escape unsafe characters */
+- (NSString *)iCalEscapedStringWithEscapeSet:(NSCharacterSet *)_es {
+  NSString *s;
+
+  s = [self iCalCleanString];
+  return [s stringByEscapingCharactersFromSet:_es
+            usingStringEscaping:[SOGoICalStringEscaper sharedEscaper]];
+}
+
+@end /* NSString (SOGoiCal) */