]> err.no Git - scalable-opengroupware.org/commitdiff
improved the iCal rendering
authorznek <znek@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Wed, 6 Oct 2004 19:28:12 +0000 (19:28 +0000)
committerznek <znek@d1b88da0-ebda-0310-925b-ed51d893ca5b>
Wed, 6 Oct 2004 19:28:12 +0000 (19:28 +0000)
git-svn-id: http://svn.opengroupware.org/SOGo/trunk@368 d1b88da0-ebda-0310-925b-ed51d893ca5b

SOGo/SOGo.xcode/project.pbxproj
SOGo/UI/Scheduler/ChangeLog
SOGo/UI/Scheduler/UIxAppointmentEditor.m
SOGo/UI/Scheduler/Version
SOGoLogic/ChangeLog
SOGoLogic/GNUmakefile
SOGoLogic/NSString+iCal.h [new file with mode: 0644]
SOGoLogic/NSString+iCal.m [new file with mode: 0644]
SOGoLogic/SOGoAppointment.m
SOGoLogic/SOGoAppointmentICalRenderer.m
SOGoLogic/Version

index 5b56d6cd48b209ecc645ebaeec568dc8c6112030..32da5bb276777e2a6f6635b03e5430c25f55b8ea 100644 (file)
                                AD73BE4B06CF88BF00226A2D,
                                AD071D1206CD2BCB00A9EEF4,
                                AD071D1306CD2BCB00A9EEF4,
+                               ADA6333607140E0D0058C21C,
+                               ADA6333707140E0D0058C21C,
                        );
                        isa = PBXGroup;
                        name = Classes;
                        refType = 4;
                        sourceTree = "<group>";
                };
+               ADA6333607140E0D0058C21C = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = "NSString+iCal.h";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               ADA6333707140E0D0058C21C = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = "NSString+iCal.m";
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
                ADCDE53106ADA8AC00BFCE2B = {
                        fileEncoding = 5;
                        indentWidth = 8;
index a7d13b0d496d07cbb4d338ec1c6e76a6815e3792..f840def63212d536e92209c0a97e9e3afe5d6ff9 100644 (file)
@@ -1,3 +1,9 @@
+2004-10-06  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * UIxAppointmentEditor.m: changed iCal template to use RFC2445
+         conforming line delimiters. Changed the testAction to aid in
+         debugging our iCal rendering. (v0.9.85)
+
 2004-10-05  Marcus Mueller  <znek@mulle-kybernetik.com>
 
        * v0.9.84
index 58ca1ff0dd43525968b4a324e9dbf65bff0fdbb6..0a3525e877b2d1030e4e872d0bb69234f8fd6b36 100644 (file)
 
 - (NSString *)iCalStringTemplate {
   static NSString *iCalStringTemplate = \
-    @"BEGIN:VCALENDAR\n"
-    @"METHOD:REQUEST\n"
-    @"PRODID:OpenGroupware.org SOGo 0.9\n"
-    @"VERSION:2.0\n"
-    @"BEGIN:VEVENT\n"
-    @"UID:%@\n"
-    @"CLASS:PRIVATE\n"
-    @"STATUS:CONFIRMED\n"
-    @"DTSTAMP:%@\n"
-    @"DTSTART:%@\n"
-    @"DTEND:%@\n"
-    @"TRANSP:OPAQUE\n"
-    @"SEQUENCE:1\n"
-    @"PRIORITY:5\n"
+    @"BEGIN:VCALENDAR\r\n"
+    @"METHOD:REQUEST\r\n"
+    @"PRODID:OpenGroupware.org SOGo 0.9\r\n"
+    @"VERSION:2.0\r\n"
+    @"BEGIN:VEVENT\r\n"
+    @"UID:%@\r\n"
+    @"CLASS:PRIVATE\r\n"
+    @"STATUS:CONFIRMED\r\n"
+    @"DTSTAMP:%@\r\n"
+    @"DTSTART:%@\r\n"
+    @"DTEND:%@\r\n"
+    @"TRANSP:OPAQUE\r\n"
+    @"SEQUENCE:1\r\n"
+    @"PRIORITY:5\r\n"
     @"%@"
-    @"END:VEVENT\n"
+    @"END:VEVENT\r\n"
     @"END:VCALENDAR";
 
   NSCalendarDate *lStartDate, *lEndDate;
 
 - (NSString *)iCalParticipantsStringFromQueryParameters {
   static NSString *iCalParticipantString = \
-    @"ATTENDEE;ROLE=REQ-PARTICIPANT;CN=\"%@\":mailto:%@\n";
+    @"ATTENDEE;ROLE=REQ-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
   
   return [self iCalStringFromQueryParameter:@"ps"
                format:iCalParticipantString];
 
 - (NSString *)iCalResourcesStringFromQueryParameters {
   static NSString *iCalResourceString = \
-    @"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":mailto:%@\n";
+    @"ATTENDEE;ROLE=NON-PARTICIPANT;CN=\"%@\":mailto:%@\r\n";
 
   return [self iCalStringFromQueryParameter:@"rs"
                format:iCalResourceString];
 
 - (id)testAction {
   /* for testing only */
-  WORequest *req;
-    
-  NSLog(@"%s BEEN HERE!", __PRETTY_FUNCTION__);
+  WORequest       *req;
+  SOGoAppointment *apt;
+  NSString        *content;
 
   req = [[self context] request];
-  NSLog(@"%@", [req formValues]);
-  [self logWithFormat:@"aptStartDate:%@ aptEndDate:%@",
-        [self aptStartDate],
-        [self aptEndDate]];
+  apt = [[SOGoAppointment alloc] initWithICalString:[self iCalString]];
+  [self saveValuesIntoAppointment:apt];
+  content = [apt iCalString];
+  [self logWithFormat:@"%s -- iCal:\n%@",
+    __PRETTY_FUNCTION__,
+    content];
+  [apt release];
   return self;
 }
 
index da6507ef58b97d41b162f26208e682986230c555..dd616d8e4aca4617a112b4608242cf46647a746a 100644 (file)
@@ -1,6 +1,6 @@
 # $Id$
 
-SUBMINOR_VERSION:=84
+SUBMINOR_VERSION:=85
 
 # v0.9.84 requires libSOGoLogic    v0.9.12
 # v0.9.70 requires libNGExtensions v4.3.107
index 622a81175ed37d74f9768580278087e36e998e5b..f753756f81c6573fca3158474c15e495d388eef8 100644 (file)
@@ -1,3 +1,14 @@
+2004-10-06  Marcus Mueller  <znek@mulle-kybernetik.com>
+
+       * v0.9.13
+
+       * SOGoAppointmentICalRenderer.m: fixed the renderer to generate RFC2445
+         conforming output.
+
+       * NSString+iCal.[hm]: necessary utility methods for the renderer to
+         generate RFC2445 conforming content.
+         NOTE: this should eventually get moved to NGiCal.
+
 2004-10-05  Marcus Mueller  <znek@mulle-kybernetik.com>
 
        * v0.9.12
index cb125a08885ee0c10d1acef01d06ed8039397868..70483fc6bb0d5a74518bd22cbc10094aa109aaf4 100644 (file)
@@ -12,12 +12,14 @@ libSOGoLogic_SOVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
 libSOGoLogic_HEADER_FILES += \
        SOGoAppointment.h               \
        SOGoAppointmentICalRenderer.h   \
-       AgenorUserManager.h
+       AgenorUserManager.h             \
+       NSString+iCal.h
 
 libSOGoLogic_OBJC_FILES += \
        SOGoAppointment.m               \
        SOGoAppointmentICalRenderer.m   \
-       AgenorUserManager.m
+       AgenorUserManager.m             \
+       NSString+iCal.m
 
 -include GNUmakefile.preamble
 include $(GNUSTEP_MAKEFILES)/library.make
diff --git a/SOGoLogic/NSString+iCal.h b/SOGoLogic/NSString+iCal.h
new file mode 100644 (file)
index 0000000..2d7cfdc
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+// $Id$
+
+
+#ifndef        __NSString_iCal_H_
+#define        __NSString_iCal_H_
+
+
+#import <Foundation/Foundation.h>
+
+
+@interface NSString (SOGoiCal)
+
+- (NSString *)iCalDQUOTESafeString;
+- (NSString *)iCalSafeString;
+- (NSString *)iCalEscapedStringWithEscapeSet:(NSCharacterSet *)_es;
+    
+@end
+
+#endif /* __NSString_iCal_H_ */
diff --git a/SOGoLogic/NSString+iCal.m b/SOGoLogic/NSString+iCal.m
new file mode 100644 (file)
index 0000000..8b21ed2
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+  Copyright (C) 2000-2004 SKYRIX Software AG
+
+  This file is part of OGo
+
+  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.
+*/
+// $Id$
+
+
+#import "NSString+iCal.h"
+
+
+@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
+
+- (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,;\""];
+        [escapeSet retain];
+    }
+    return [self iCalEscapedStringWithEscapeSet:escapeSet];
+}
+
+- (NSString *)iCalEscapedStringWithEscapeSet:(NSCharacterSet *)_es {
+    /* Escape unsafe characters */
+    NSMutableString *safeString;
+    NSRange r, er;
+    BOOL needsEscaping;
+    unsigned length;
+    
+    length = [self length];
+    r = NSMakeRange(0, length);
+    er = [self rangeOfCharacterFromSet:_es options:0 range:r];
+    needsEscaping = er.length > 0 ? YES : NO;
+    if(!needsEscaping) {
+        return self; /* cheap */
+    }
+    /* wild guess */
+    safeString = [NSMutableString stringWithCapacity:length + 10];
+    if(needsEscaping) {
+        NSRange todoRange;
+        /*
+         r         == previous range, upto er.location
+         er        == escape range
+         todoRange == what we still need to scan
+         */
+        length = r.length;
+        do {
+            NSString *s;
+
+            r.length = (er.location - 1) - r.location;
+            s = [self substringWithRange:r];
+            [safeString appendString:s];
+            [safeString appendString:@"\\"];
+            if([self characterAtIndex:er.location] == '\n') {
+                s = @"n";
+            }
+            else {
+                s = [self substringWithRange:er];
+            }
+            [safeString appendString:s];
+            r.location          = NSMaxRange(er);
+            todoRange.location  = r.location;
+            todoRange.length    = length - r.location;
+            er = [self rangeOfCharacterFromSet:_es
+                                       options:0
+                                         range:todoRange];
+        }
+        while(er.length > 0);
+        if(todoRange.length > 0) {
+            [safeString appendString:[self substringWithRange:todoRange]];
+        }
+    }
+    return safeString;
+}
+
+@end
index 15f3db7a60cfa238fbca3a2db3231d2decd83afb..114103302b593f6b9b98969680fa9d00435dd2ef 100644 (file)
 // $Id$
 
 #include "SOGoAppointment.h"
-#include "SOGoAppointmentICalRenderer.h"
 #include <SaxObjC/SaxObjC.h>
 #include <NGiCal/NGiCal.h>
 #include <EOControl/EOControl.h>
+#include "SOGoAppointmentICalRenderer.h"
 #include "common.h"
 
 @interface SOGoAppointment (PrivateAPI)
index b33c269fded0370eb50e2c97323abbd33655250c..57e9aa845bb2ba6e26b70fd789fa1b5852446eab 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "SOGoAppointmentICalRenderer.h"
 #include "SOGoAppointment.h"
+#include "NSString+iCal.h"
 #include <NGiCal/NGiCal.h>
 #include "common.h"
 
@@ -49,20 +50,20 @@ static SOGoAppointmentICalRenderer *renderer = nil;
 
   calendar = [_apt calendar];
   
-  [s appendString:@"BEGIN:VCALENDAR\nMETHOD:REQUEST\n"];
+  [s appendString:@"BEGIN:VCALENDAR\r\nMETHOD:REQUEST\r\n"];
   
   [s appendString:@"PRODID:"];
   [s appendString:[calendar isNotNull] ? [calendar prodId] : @"SOGo/0.9"];
-  [s appendString:@"\n"];
+  [s appendString:@"\r\n"];
   
   [s appendString:@"VERSION:"];
   [s appendString:[calendar isNotNull] ? [calendar version] : @"2.0"];
-  [s appendString:@"\n"];
+  [s appendString:@"\r\n"];
 }
 - (void)addPostambleForAppointment:(SOGoAppointment *)_apt
   toString:(NSMutableString *)s
 {
-  [s appendString:@"END:VCALENDAR\n"];
+  [s appendString:@"END:VCALENDAR\r\n"];
 }
 
 - (void)addOrganizer:(iCalPerson *)p toString:(NSMutableString *)s {
@@ -72,14 +73,14 @@ static SOGoAppointmentICalRenderer *renderer = nil;
   
   [s appendString:@"ORGANIZER;CN=\""];
   if ((x = [p cn]))
-    [s appendString:x];
+    [s appendString:[x iCalDQUOTESafeString]];
   
   [s appendString:@"\""];
   if ((x = [p email])) {
     [s appendString:@":"]; /* sic! */
-    [s appendString:x];
+    [s appendString:[x iCalSafeString]];
   }
-  [s appendString:@"\n"];
+  [s appendString:@"\r\n"];
 }
 
 - (void)addAttendees:(NSArray *)persons toString:(NSMutableString *)s {
@@ -95,20 +96,20 @@ static SOGoAppointmentICalRenderer *renderer = nil;
     
     if ((x = [p role])) {
       [s appendString:@"ROLE="];
-      [s appendString:x];
+      [s appendString:[x iCalSafeString]];
       [s appendString:@";"];
     }
     
     [s appendString:@"CN=\""];
     if ((x = [p cn])) {
-      [s appendString:x];
+      [s appendString:[x iCalDQUOTESafeString]];
     }
     [s appendString:@"\""];
     if ([(x = [p email]) isNotNull]) {
       [s appendString:@":"]; /* sic! */
-      [s appendString:x];
+      [s appendString:[x iCalSafeString]];
     }
-    [s appendString:@"\n"];
+    [s appendString:@"\r\n"];
   }
 }
 
@@ -119,38 +120,38 @@ static SOGoAppointmentICalRenderer *renderer = nil;
 
   event = [_apt event];
   
-  [s appendString:@"BEGIN:VEVENT\n"];
+  [s appendString:@"BEGIN:VEVENT\r\n"];
   
   [s appendString:@"SUMMARY:"];
-  [s appendString:[_apt summary]];
-  [s appendString:@"\n"];
+  [s appendString:[[_apt summary] iCalSafeString]];
+  [s appendString:@"\r\n"];
   if ([_apt hasLocation]) {
     [s appendString:@"LOCATION:"];
-    [s appendString:[_apt location]];
-    [s appendString:@"\n"];
+    [s appendString:[[_apt location] iCalSafeString]];
+    [s appendString:@"\r\n"];
   }
   [s appendString:@"UID:"];
   [s appendString:[_apt uid]];
-  [s appendString:@"\n"];
+  [s appendString:@"\r\n"];
   
   [s appendString:@"DTSTART:"];
   [s appendString:[[_apt startDate] icalString]];
-  [s appendString:@"\n"];
+  [s appendString:@"\r\n"];
   
   if ([_apt hasEndDate]) {
     [s appendString:@"DTEND:"];
     [s appendString:[[_apt endDate] icalString]];
-    [s appendString:@"\n"];
+    [s appendString:@"\r\n"];
   }
   if ([_apt hasDuration]) {
     [s appendString:@"DURATION:"];
     [s appendString:[event duration]];
-    [s appendString:@"\n"];
+    [s appendString:@"\r\n"];
   }
   if([_apt hasPriority]) {
     [s appendString:@"PRIORITY:"];
     [s appendString:[_apt priority]];
-    [s appendString:@"\n"];
+    [s appendString:@"\r\n"];
   }
   if([_apt hasCategories]) {
     NSString *catString;
@@ -158,28 +159,28 @@ static SOGoAppointmentICalRenderer *renderer = nil;
     catString = [[_apt categories] componentsJoinedByString:@","];
     [s appendString:@"CATEGORIES:"];
     [s appendString:catString];
-    [s appendString:@"\n"];
+    [s appendString:@"\r\n"];
   }
   if([_apt hasComment]) {
-    [s appendString:@"COMMENT:"];
-    [s appendString:[_apt comment]];
-    [s appendString:@"\n"];
+    [s appendString:@"DESCRIPTION:"]; /* this is what iCal.app does */
+    [s appendString:[[_apt comment] iCalSafeString]];
+    [s appendString:@"\r\n"];
   }
 
   [s appendString:@"STATUS:"];
   [s appendString:[_apt status]];
-  [s appendString:@"\n"];
+  [s appendString:@"\r\n"];
 
   
   /* what's all this? */
-  [s appendString:@"TRANSP:OPAQUE\n"]; /* transparency */
-  [s appendString:@"CLASS:PRIVATE\n"]; /* classification [like 'top secret'] */
+  [s appendString:@"TRANSP:OPAQUE\r\n"]; /* transparency */
+  [s appendString:@"CLASS:PRIVATE\r\n"]; /* classification [like 'top secret'] */
   
   [self addOrganizer:[_apt organizer] toString:s];
   [self addAttendees:[_apt attendees] toString:s];
   
   /* postamble */
-  [s appendString:@"END:VEVENT\n"];
+  [s appendString:@"END:VEVENT\r\n"];
 }
 
 - (NSString *)stringForAppointment:(SOGoAppointment *)_apt {
index 9cef79939ea704d51f0e6725b9964991d0cafe31..9637b5fa76492adc9ea85333941998a6e223827d 100644 (file)
@@ -1,3 +1,5 @@
 # $Id$
 
-SUBMINOR_VERSION:=12
+SUBMINOR_VERSION:=13
+
+# v0.9.13 requires libFoundation v1.0.62