Monotone-Parent: 29948ba19f24f47aa6c1b2c0764586b89ff9493f
Monotone-Revision: 1a5434f30282a4932bf29227da4cf2da44ef5783 Monotone-Author: wsourdeau@inverse.ca Monotone-Date: 2008-07-11T22:28:12 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
45f0686d92
commit
6c5003d7bc
14
ChangeLog
14
ChangeLog
|
@ -1,3 +1,17 @@
|
|||
2008-07-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/Appointments/SOGoAppointmentFolder.m
|
||||
([SOGoAppointmentFolder
|
||||
-fetchFields:_fieldsfrom:_startDateto:_endDatetitle:titlecomponent:_componentadditionalFilters:filters]):
|
||||
take exceptional modifications into account.
|
||||
|
||||
* SoObjects/Appointments/iCalToDo+SOGo.m: new class module with
|
||||
category methods for iCalToDo.
|
||||
([iCalToDo -quickRecord]): same as for method below.
|
||||
|
||||
* SoObjects/Appointments/iCalEvent+SOGo.m ([iCalEvent
|
||||
-quickRecord]): new method taken from OCSiCalFieldExtractor.
|
||||
|
||||
2008-07-10 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* SoObjects/SOGo/NSString+DAV.m ([NSString -asWebDAVTuple]): new
|
||||
|
|
|
@ -17,9 +17,6 @@ ADDITIONAL_INCLUDE_DIRS += -I../SOPE
|
|||
ADDITIONAL_LIB_DIRS += -L../SOPE/GDLContentStore/obj
|
||||
|
||||
libOGoContentStore_OBJC_FILES += \
|
||||
iCalEntityObject+OCS.m \
|
||||
iCalRepeatableEntityObject+OCS.m \
|
||||
\
|
||||
OCSiCalFieldExtractor.m \
|
||||
OCSContactFieldExtractor.m \
|
||||
|
||||
|
|
|
@ -19,34 +19,21 @@
|
|||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
|
||||
#import "iCalEntityObject+OCS.h"
|
||||
#import "iCalRepeatableEntityObject+OCS.h"
|
||||
#import <SoObjects/Appointments/iCalRepeatableEntityObject+SOGo.h>
|
||||
|
||||
#import "OCSiCalFieldExtractor.h"
|
||||
|
||||
@implementation OCSiCalFieldExtractor
|
||||
|
||||
static NSCalendarDate *distantFuture = nil;
|
||||
static NSNumber *distantFutureNumber = nil;
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (!distantFuture)
|
||||
{
|
||||
distantFuture = [[NSCalendarDate distantFuture] retain];
|
||||
/* INT_MAX due to Postgres constraint */
|
||||
distantFutureNumber = [[NSNumber numberWithUnsignedInt: INT_MAX] retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id) sharedICalFieldExtractor
|
||||
{
|
||||
static OCSiCalFieldExtractor *extractor = nil;
|
||||
|
@ -59,287 +46,6 @@ static NSNumber *distantFutureNumber = nil;
|
|||
|
||||
/* operations */
|
||||
|
||||
- (NSNumber *) numberForDate: (NSCalendarDate *) _date
|
||||
{
|
||||
return ((_date == distantFuture)
|
||||
? distantFutureNumber
|
||||
: [NSNumber numberWithUnsignedInt: [_date timeIntervalSince1970]]);
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) extractQuickFieldsFromEvent: (iCalEvent *) _event
|
||||
{
|
||||
NSMutableDictionary *row;
|
||||
NSCalendarDate *startDate, *endDate;
|
||||
NSArray *attendees;
|
||||
NSString *uid, *title, *location, *status;
|
||||
NSNumber *sequence, *dateNumber;
|
||||
id organizer;
|
||||
id participants, partmails;
|
||||
NSMutableString *partstates;
|
||||
unsigned int i, count;
|
||||
BOOL isAllDay;
|
||||
iCalAccessClass accessClass;
|
||||
|
||||
if (_event == nil)
|
||||
return nil;
|
||||
|
||||
/* extract values */
|
||||
|
||||
startDate = [_event startDate];
|
||||
endDate = [_event endDate];
|
||||
uid = [_event uid];
|
||||
title = [_event summary];
|
||||
if (![title isNotNull])
|
||||
title = @"";
|
||||
location = [_event location];
|
||||
sequence = [_event sequence];
|
||||
accessClass = [_event symbolicAccessClass];
|
||||
isAllDay = [_event isAllDay];
|
||||
status = [[_event status] uppercaseString];
|
||||
|
||||
attendees = [_event attendees];
|
||||
partmails = [attendees valueForKey: @"rfc822Email"];
|
||||
partmails = [partmails componentsJoinedByString: @"\n"];
|
||||
participants = [attendees valueForKey: @"cn"];
|
||||
participants = [participants componentsJoinedByString: @"\n"];
|
||||
|
||||
/* build row */
|
||||
|
||||
row = [NSMutableDictionary dictionaryWithCapacity:8];
|
||||
|
||||
[row setObject: @"vevent" forKey: @"c_component"];
|
||||
|
||||
if ([uid isNotNull])
|
||||
[row setObject:uid forKey: @"c_uid"];
|
||||
else
|
||||
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
|
||||
|
||||
|
||||
[row setObject: [NSNumber numberWithBool: isAllDay]
|
||||
forKey: @"c_isallday"];
|
||||
[row setObject: [NSNumber numberWithBool: [_event isRecurrent]]
|
||||
forKey: @"c_iscycle"];
|
||||
[row setObject: [NSNumber numberWithBool: [_event isOpaque]]
|
||||
forKey: @"c_isopaque"];
|
||||
[row setObject: [NSNumber numberWithInt: [_event priorityNumber]]
|
||||
forKey: @"c_priority"];
|
||||
|
||||
[row setObject: title forKey: @"c_title"];
|
||||
if ([location isNotNull]) [row setObject: location forKey: @"c_location"];
|
||||
if ([sequence isNotNull]) [row setObject: sequence forKey: @"c_sequence"];
|
||||
|
||||
if ([startDate isNotNull])
|
||||
[row setObject: [self numberForDate: startDate]
|
||||
forKey: @"c_startdate"];
|
||||
if ([endDate isNotNull])
|
||||
{
|
||||
if (endDate == distantFuture)
|
||||
dateNumber = distantFutureNumber;
|
||||
else
|
||||
{
|
||||
if (isAllDay)
|
||||
i = 1;
|
||||
else
|
||||
i = 0;
|
||||
dateNumber
|
||||
= [NSNumber numberWithUnsignedInt:
|
||||
[endDate timeIntervalSince1970] - i];
|
||||
}
|
||||
[row setObject: dateNumber forKey: @"c_enddate"];
|
||||
}
|
||||
|
||||
if ([_event isRecurrent]) {
|
||||
NSCalendarDate *date;
|
||||
|
||||
date = [_event lastPossibleRecurrenceStartDate];
|
||||
if (!date) {
|
||||
/* this could also be *nil*, but in the end it makes the fetchspecs
|
||||
more complex - thus we set it to a "reasonable" distant future */
|
||||
date = distantFuture;
|
||||
}
|
||||
[row setObject:[self numberForDate:date] forKey: @"c_cycleenddate"];
|
||||
[row setObject:[_event cycleInfo] forKey: @"c_cycleinfo"];
|
||||
}
|
||||
|
||||
if ([participants length] > 0)
|
||||
[row setObject: participants forKey: @"c_participants"];
|
||||
if ([partmails length] > 0)
|
||||
[row setObject: partmails forKey: @"c_partmails"];
|
||||
|
||||
if ([status isNotNull]) {
|
||||
int code = 1;
|
||||
|
||||
if ([status isEqualToString: @"TENTATIVE"])
|
||||
code = 2;
|
||||
else if ([status isEqualToString: @"CANCELLED"])
|
||||
code = 0;
|
||||
[row setObject:[NSNumber numberWithInt:code] forKey: @"c_status"];
|
||||
}
|
||||
else {
|
||||
/* confirmed by default */
|
||||
[row setObject: [NSNumber numberWithInt:1] forKey: @"c_status"];
|
||||
}
|
||||
|
||||
[row setObject: [NSNumber numberWithUnsignedInt: accessClass]
|
||||
forKey: @"c_classification"];
|
||||
|
||||
organizer = [_event organizer];
|
||||
if (organizer) {
|
||||
NSString *email;
|
||||
|
||||
email = [organizer valueForKey: @"rfc822Email"];
|
||||
if (email)
|
||||
[row setObject:email forKey: @"c_orgmail"];
|
||||
}
|
||||
|
||||
/* construct partstates */
|
||||
count = [attendees count];
|
||||
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
|
||||
for ( i = 0; i < count; i++) {
|
||||
iCalPerson *p;
|
||||
iCalPersonPartStat stat;
|
||||
|
||||
p = [attendees objectAtIndex:i];
|
||||
stat = [p participationStatus];
|
||||
if(i != 0)
|
||||
[partstates appendString: @"\n"];
|
||||
[partstates appendFormat: @"%d", stat];
|
||||
}
|
||||
[row setObject:partstates forKey: @"c_partstates"];
|
||||
[partstates release];
|
||||
return row;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) extractQuickFieldsFromTodo: (iCalToDo *) _task
|
||||
{
|
||||
NSMutableDictionary *row;
|
||||
NSCalendarDate *startDate, *dueDate;
|
||||
NSArray *attendees;
|
||||
NSString *uid, *title, *location, *status;
|
||||
NSNumber *sequence;
|
||||
id organizer, date;
|
||||
id participants, partmails;
|
||||
NSMutableString *partstates;
|
||||
unsigned i, count, code;
|
||||
iCalAccessClass accessClass;
|
||||
|
||||
if (_task == nil)
|
||||
return nil;
|
||||
|
||||
/* extract values */
|
||||
|
||||
startDate = [_task startDate];
|
||||
dueDate = [_task due];
|
||||
uid = [_task uid];
|
||||
title = [_task summary];
|
||||
if (![title isNotNull])
|
||||
title = @"";
|
||||
location = [_task location];
|
||||
sequence = [_task sequence];
|
||||
accessClass = [_task symbolicAccessClass];
|
||||
status = [[_task status] uppercaseString];
|
||||
|
||||
attendees = [_task attendees];
|
||||
partmails = [attendees valueForKey: @"rfc822Email"];
|
||||
partmails = [partmails componentsJoinedByString: @"\n"];
|
||||
participants = [attendees valueForKey: @"cn"];
|
||||
participants = [participants componentsJoinedByString: @"\n"];
|
||||
|
||||
/* build row */
|
||||
|
||||
row = [NSMutableDictionary dictionaryWithCapacity:8];
|
||||
|
||||
[row setObject: @"vtodo" forKey: @"c_component"];
|
||||
|
||||
if ([uid isNotNull])
|
||||
[row setObject:uid forKey: @"c_uid"];
|
||||
else
|
||||
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
|
||||
|
||||
[row setObject:[NSNumber numberWithBool:[_task isRecurrent]]
|
||||
forKey: @"c_iscycle"];
|
||||
[row setObject:[NSNumber numberWithInt:[_task priorityNumber]]
|
||||
forKey: @"c_priority"];
|
||||
|
||||
[row setObject: [NSNumber numberWithBool: NO]
|
||||
forKey: @"c_isallday"];
|
||||
[row setObject: [NSNumber numberWithBool: NO]
|
||||
forKey: @"c_isopaque"];
|
||||
|
||||
[row setObject: title forKey: @"c_title"];
|
||||
if ([location isNotNull]) [row setObject: location forKey: @"c_location"];
|
||||
if ([sequence isNotNull]) [row setObject: sequence forKey: @"c_sequence"];
|
||||
|
||||
if ([startDate isNotNull])
|
||||
date = [self numberForDate: startDate];
|
||||
else
|
||||
date = [NSNull null];
|
||||
[row setObject: date forKey: @"c_startdate"];
|
||||
|
||||
if ([dueDate isNotNull])
|
||||
date = [self numberForDate: dueDate];
|
||||
else
|
||||
date = [NSNull null];
|
||||
[row setObject: date forKey: @"c_enddate"];
|
||||
|
||||
if ([_task isRecurrent])
|
||||
{
|
||||
[row setObject: [self numberForDate: distantFuture]
|
||||
forKey: @"c_cycleenddate"];
|
||||
[row setObject: [_task cycleInfo]
|
||||
forKey: @"c_cycleinfo"];
|
||||
}
|
||||
|
||||
if ([participants length] > 0)
|
||||
[row setObject:participants forKey: @"c_participants"];
|
||||
if ([partmails length] > 0)
|
||||
[row setObject:partmails forKey: @"c_partmails"];
|
||||
|
||||
if ([status isNotNull]) {
|
||||
code = 0; /* NEEDS-ACTION */
|
||||
if ([status isEqualToString: @"COMPLETED"])
|
||||
code = 1;
|
||||
else if ([status isEqualToString: @"IN-PROCESS"])
|
||||
code = 2;
|
||||
else if ([status isEqualToString: @"CANCELLED"])
|
||||
code = 3;
|
||||
[row setObject: [NSNumber numberWithInt: code] forKey: @"c_status"];
|
||||
}
|
||||
else {
|
||||
/* confirmed by default */
|
||||
[row setObject:[NSNumber numberWithInt:1] forKey: @"c_status"];
|
||||
}
|
||||
|
||||
[row setObject: [NSNumber numberWithUnsignedInt: accessClass]
|
||||
forKey: @"c_classification"];
|
||||
|
||||
organizer = [_task organizer];
|
||||
if (organizer) {
|
||||
NSString *email;
|
||||
|
||||
email = [organizer valueForKey: @"rfc822Email"];
|
||||
if (email)
|
||||
[row setObject:email forKey: @"c_orgmail"];
|
||||
}
|
||||
|
||||
/* construct partstates */
|
||||
count = [attendees count];
|
||||
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
|
||||
for ( i = 0; i < count; i++) {
|
||||
iCalPerson *p;
|
||||
iCalPersonPartStat stat;
|
||||
|
||||
p = [attendees objectAtIndex:i];
|
||||
stat = [p participationStatus];
|
||||
if(i != 0)
|
||||
[partstates appendString: @"\n"];
|
||||
[partstates appendFormat: @"%d", stat];
|
||||
}
|
||||
[row setObject:partstates forKey: @"c_partstates"];
|
||||
[partstates release];
|
||||
return row;
|
||||
}
|
||||
|
||||
- (CardGroup *) firstElementFromCalendar: (iCalCalendar *) ical
|
||||
{
|
||||
NSArray *elements;
|
||||
|
@ -349,13 +55,7 @@ static NSNumber *distantFutureNumber = nil;
|
|||
elements = [ical allObjects];
|
||||
count = [elements count];
|
||||
if (count)
|
||||
{
|
||||
if (count > 1)
|
||||
[self logWithFormat:
|
||||
@"WARNING: given calendar contains more than one event: %@",
|
||||
ical];
|
||||
element = [elements objectAtIndex: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self logWithFormat: @"ERROR: given calendar contains no elements: %@", ical];
|
||||
|
@ -365,34 +65,32 @@ static NSNumber *distantFutureNumber = nil;
|
|||
return element;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content {
|
||||
NSDictionary *fields;
|
||||
- (NSMutableDictionary *) extractQuickFieldsFromContent: (NSString *) _content
|
||||
{
|
||||
NSMutableDictionary *fields;
|
||||
id cal;
|
||||
|
||||
if ([_content length] == 0)
|
||||
return nil;
|
||||
|
||||
cal = [iCalCalendar parseSingleFromSource: _content];
|
||||
|
||||
fields = nil;
|
||||
|
||||
if ([_content length])
|
||||
{
|
||||
cal = [iCalCalendar parseSingleFromSource: _content];
|
||||
if (cal)
|
||||
{
|
||||
if ([cal isKindOfClass:[iCalCalendar class]])
|
||||
if ([cal isKindOfClass: [iCalCalendar class]])
|
||||
cal = [self firstElementFromCalendar: cal];
|
||||
|
||||
if ([cal isKindOfClass:[iCalEvent class]])
|
||||
fields = [[self extractQuickFieldsFromEvent:cal] retain];
|
||||
else if ([cal isKindOfClass:[iCalToDo class]])
|
||||
fields = [[self extractQuickFieldsFromTodo:cal] retain];
|
||||
else if ([cal isNotNull]) {
|
||||
if ([cal isKindOfClass: [iCalRepeatableEntityObject class]])
|
||||
fields = [cal quickRecord];
|
||||
else if ([cal isNotNull])
|
||||
[self logWithFormat: @"ERROR: unexpected iCalendar parse result: %@",
|
||||
cal];
|
||||
}
|
||||
}
|
||||
else
|
||||
[self logWithFormat: @"ERROR: parsing source didn't return anything"];
|
||||
}
|
||||
|
||||
return [fields autorelease];
|
||||
return fields;
|
||||
}
|
||||
|
||||
@end /* OCSiCalFieldExtractor */
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 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 __OGoContentStore_iCalEntityObject_OCS_H_
|
||||
#define __OGoContentStore_iCalEntityObject_OCS_H_
|
||||
|
||||
#include <NGCards/NGCards.h>
|
||||
|
||||
@interface iCalEntityObject (OCS)
|
||||
|
||||
- (int)priorityNumber;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __OGoContentStore_iCalEntityObject_OCS_H_ */
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 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.
|
||||
*/
|
||||
|
||||
#import "iCalEntityObject+OCS.h"
|
||||
|
||||
@implementation iCalEntityObject (OCS)
|
||||
|
||||
- (int)priorityNumber {
|
||||
NSString *prio;
|
||||
|
||||
prio = [self priority];
|
||||
if(prio) {
|
||||
NSRange r;
|
||||
|
||||
r = [prio rangeOfString:@";"];
|
||||
if(r.length > 0) {
|
||||
prio = [prio substringToIndex:r.location];
|
||||
}
|
||||
return [prio intValue];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@end
|
|
@ -26,59 +26,4 @@
|
|||
|
||||
@implementation iCalRepeatableEntityObject (OCS)
|
||||
|
||||
- (NSArray *) _indexedRules: (NSArray *) rules
|
||||
{
|
||||
NSMutableArray *ma;
|
||||
unsigned int i, count;
|
||||
NSString *valuesString;
|
||||
|
||||
ma = nil;
|
||||
count = [rules count];
|
||||
if (count > 0)
|
||||
{
|
||||
ma = [NSMutableArray arrayWithCapacity:count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
rule = [rules objectAtIndex:i];
|
||||
#warning we could return an NSArray instead and feed it as such to the iCalRecurrenceRule in SOGoAppointmentFolder...
|
||||
valuesString = [[rule values] componentsJoinedByString: @";"];
|
||||
[ma addObject: valuesString];
|
||||
}
|
||||
}
|
||||
|
||||
return ma;
|
||||
}
|
||||
|
||||
- (NSString *) cycleInfo
|
||||
{
|
||||
NSArray *rules;
|
||||
NSString *value;
|
||||
NSMutableDictionary *cycleInfo;
|
||||
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
cycleInfo = [NSMutableDictionary dictionaryWithCapacity: 3];
|
||||
|
||||
/* rules */
|
||||
rules = [self _indexedRules: [self recurrenceRules]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"rules"];
|
||||
|
||||
rules = [self _indexedRules: [self exceptionRules]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"exRules"];
|
||||
|
||||
rules = [self _indexedRules: [self exceptionDates]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"exDates"];
|
||||
|
||||
value = [cycleInfo description];
|
||||
}
|
||||
else
|
||||
value = nil;
|
||||
|
||||
return value;
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
2008-07-11 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* iCalEntityObject.m ([iCalEntityObject -setRecurrenceId:newRecId])
|
||||
([iCalEntityObject -recurrenceId]): new accessors to handle the
|
||||
"RECURRENCE-ID" fields in recurrence exceptions.
|
||||
|
||||
2008-07-07 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
|
||||
* CardElement.m ([CardElement -addValue:aValue])
|
||||
|
|
|
@ -191,7 +191,7 @@
|
|||
{
|
||||
NSMutableArray *ma;
|
||||
|
||||
ma = [NSMutableArray new];
|
||||
ma = [NSMutableArray array];
|
||||
[ma addObjectsFromArray: [self events]];
|
||||
[ma addObjectsFromArray: [self todos]];
|
||||
[ma addObjectsFromArray: [self journals]];
|
||||
|
|
|
@ -79,6 +79,9 @@ typedef enum
|
|||
- (NSCalendarDate *) startDate;
|
||||
- (BOOL) hasStartDate;
|
||||
|
||||
- (void) setRecurrenceId: (NSCalendarDate *) newRecId;
|
||||
- (NSCalendarDate *) recurrenceId;
|
||||
|
||||
- (void) setLastModified: (NSCalendarDate *) _value;
|
||||
- (NSCalendarDate *) lastModified;
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
tagClass = [CardElement class];
|
||||
else if ([classTag isEqualToString: @"DTSTAMP"]
|
||||
|| [classTag isEqualToString: @"DTSTART"]
|
||||
|| [classTag isEqualToString: @"RECURRENCE-ID"]
|
||||
|| [classTag isEqualToString: @"CREATED"]
|
||||
|| [classTag isEqualToString: @"LAST-MODIFIED"])
|
||||
tagClass = [iCalDateTime class];
|
||||
|
@ -257,6 +258,18 @@
|
|||
dateTime];
|
||||
}
|
||||
|
||||
- (void) setRecurrenceId: (NSCalendarDate *) newRecId
|
||||
{
|
||||
[(iCalDateTime *) [self uniqueChildWithTag: @"recurrence-id"]
|
||||
setDateTime: newRecId];
|
||||
}
|
||||
|
||||
- (NSCalendarDate *) recurrenceId
|
||||
{
|
||||
return [(iCalDateTime *) [self uniqueChildWithTag: @"recurrence-id"]
|
||||
dateTime];
|
||||
}
|
||||
|
||||
- (BOOL) hasStartDate
|
||||
{
|
||||
return ([[self childrenWithTag: @"dtstart"] count] > 0);
|
||||
|
|
|
@ -11,9 +11,11 @@ Appointments_OBJC_FILES = \
|
|||
Product.m \
|
||||
NSArray+Appointments.m \
|
||||
iCalEntityObject+SOGo.m \
|
||||
iCalRepeatableEntityObject+SOGo.m \
|
||||
iCalEvent+SOGo.m \
|
||||
iCalEventChanges+SOGo.m \
|
||||
iCalPerson+SOGo.m \
|
||||
iCalToDo+SOGo.m \
|
||||
\
|
||||
SOGoCalendarComponent.m \
|
||||
SOGoAppointmentObject.m \
|
||||
|
|
|
@ -59,12 +59,14 @@
|
|||
#import <SOGo/SOGoCache.h>
|
||||
// #import <SOGo/SOGoCustomGroupFolder.h>
|
||||
#import <SOGo/LDAPUserManager.h>
|
||||
#import <SOGo/NSDictionary+Utilities.h>
|
||||
#import <SOGo/SOGoPermissions.h>
|
||||
#import <SOGo/SOGoUser.h>
|
||||
#import <SOGo/SOGoUserFolder.h>
|
||||
#import <SOGo/SOGoWebDAVAclManager.h>
|
||||
#import <SoObjects/SOGo/iCalEntityObject+Utilities.h>
|
||||
#import <SOGo/iCalEntityObject+Utilities.h>
|
||||
|
||||
#import "iCalEntityObject+SOGo.h"
|
||||
#import "SOGoAppointmentObject.h"
|
||||
#import "SOGoAppointmentFolders.h"
|
||||
#import "SOGoFreeBusyObject.h"
|
||||
|
@ -98,7 +100,10 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
didInit = YES;
|
||||
|
||||
if (!sogoAppointmentFolderKlass)
|
||||
{
|
||||
sogoAppointmentFolderKlass = self;
|
||||
[iCalEntityObject initializeSOGoExtensions];
|
||||
}
|
||||
|
||||
if (!reportQueryFields)
|
||||
reportQueryFields = [[NSArray alloc] initWithObjects: @"c_name",
|
||||
|
@ -554,7 +559,6 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
}
|
||||
|
||||
- (NSMutableDictionary *) fixupRecord: (NSDictionary *) _record
|
||||
fetchRange: (NGCalendarDateRange *) _r
|
||||
{
|
||||
NSMutableDictionary *md;
|
||||
static NSString *fields[] = { @"c_startdate", @"startDate",
|
||||
|
@ -598,8 +602,7 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
ma = [NSMutableArray arrayWithCapacity: max];
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
row = [self fixupRecord: [records objectAtIndex: count]
|
||||
fetchRange: r];
|
||||
row = [self fixupRecord: [records objectAtIndex: count]];
|
||||
if (row)
|
||||
[ma addObject: row];
|
||||
}
|
||||
|
@ -632,6 +635,117 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
return md;
|
||||
}
|
||||
|
||||
- (int) _indexOfRecordMatchingDate: (NSCalendarDate *) matchDate
|
||||
inArray: (NSArray *) recordArray
|
||||
{
|
||||
int count, max, recordIndex;
|
||||
NSDictionary *currentRecord;
|
||||
|
||||
recordIndex = -1;
|
||||
|
||||
count = 0;
|
||||
max = [recordArray count];
|
||||
while (recordIndex == -1 && count < max)
|
||||
{
|
||||
currentRecord = [recordArray objectAtIndex: count];
|
||||
if ([[currentRecord objectForKey: @"startDate"]
|
||||
isEqual: matchDate])
|
||||
recordIndex = count;
|
||||
}
|
||||
|
||||
return recordIndex;
|
||||
}
|
||||
|
||||
- (void) _fixExceptionRecord: (NSMutableDictionary *) recRecord
|
||||
fromRow: (NSDictionary *) row
|
||||
{
|
||||
NSArray *objects;
|
||||
static NSArray *fields = nil;
|
||||
|
||||
if (!fields)
|
||||
{
|
||||
fields = [NSArray arrayWithObjects: @"c_name", nil];
|
||||
[fields retain];
|
||||
}
|
||||
|
||||
objects = [row objectsForKeys: fields notFoundMarker: @""];
|
||||
[recRecord setObjects: objects forKeys: fields];
|
||||
}
|
||||
|
||||
- (void) _appendCycleException: (iCalRepeatableEntityObject *) component
|
||||
fromRow: (NSDictionary *) row
|
||||
forRange: (NGCalendarDateRange *) dateRange
|
||||
toArray: (NSMutableArray *) ma
|
||||
{
|
||||
NSCalendarDate *startDate, *recurrenceId;
|
||||
NSMutableDictionary *newRecord;
|
||||
NGCalendarDateRange *newRecordRange;
|
||||
int recordIndex;
|
||||
|
||||
newRecord = nil;
|
||||
|
||||
recurrenceId = [component recurrenceId];
|
||||
if ([dateRange containsDate: recurrenceId])
|
||||
{
|
||||
recordIndex = [self _indexOfRecordMatchingDate: recurrenceId
|
||||
inArray: ma];
|
||||
if (recordIndex > -1)
|
||||
{
|
||||
startDate = [component startDate];
|
||||
if ([dateRange containsDate: startDate])
|
||||
{
|
||||
newRecord = [self fixupRecord: [component quickRecord]];
|
||||
[ma replaceObjectAtIndex: recordIndex withObject: newRecord];
|
||||
}
|
||||
else
|
||||
[ma removeObjectAtIndex: recordIndex];
|
||||
}
|
||||
else
|
||||
[self errorWithFormat:
|
||||
@"missing exception record for recurrence-id: %@",
|
||||
recurrenceId];
|
||||
}
|
||||
else
|
||||
{
|
||||
newRecord = [self fixupRecord: [component quickRecord]];
|
||||
newRecordRange = [NGCalendarDateRange calendarDateRangeWithStartDate:
|
||||
[newRecord objectForKey:
|
||||
@"startDate"]
|
||||
endDate: [newRecord objectForKey:
|
||||
@"endDate"]];
|
||||
if ([dateRange doesIntersectWithDateRange: newRecordRange])
|
||||
[ma addObject: newRecord];
|
||||
}
|
||||
|
||||
if (newRecord)
|
||||
[self _fixExceptionRecord: newRecord fromRow: row];
|
||||
}
|
||||
|
||||
- (void) _appendCycleExceptionsFromRow: (NSDictionary *) row
|
||||
forRange: (NGCalendarDateRange *) dateRange
|
||||
toArray: (NSMutableArray *) ma
|
||||
{
|
||||
NSArray *elements, *components;
|
||||
unsigned int count, max;
|
||||
NSString *content;
|
||||
|
||||
content = [row objectForKey: @"c_content"];
|
||||
if ([content length])
|
||||
{
|
||||
elements = [iCalCalendar parseFromSource: content];
|
||||
if ([elements count])
|
||||
{
|
||||
components = [[elements objectAtIndex: 0] allObjects];
|
||||
max = [components count];
|
||||
for (count = 1; count < max; count++)
|
||||
[self _appendCycleException: [components objectAtIndex: count]
|
||||
fromRow: row
|
||||
forRange: dateRange
|
||||
toArray: ma];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) _flattenCycleRecord: (NSDictionary *) _row
|
||||
forRange: (NGCalendarDateRange *) _r
|
||||
intoArray: (NSMutableArray *) _ma
|
||||
|
@ -660,7 +774,7 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
return;
|
||||
}
|
||||
|
||||
row = [self fixupRecord:_row fetchRange: _r];
|
||||
row = [self fixupRecord: _row];
|
||||
[row removeObjectForKey: @"c_cycleinfo"];
|
||||
[row setObject: sharedYes forKey: @"isRecurrentEvent"];
|
||||
|
||||
|
@ -685,6 +799,10 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
if (fixedRow)
|
||||
[_ma addObject:fixedRow];
|
||||
}
|
||||
|
||||
[self _appendCycleExceptionsFromRow: row
|
||||
forRange: _r
|
||||
toArray: _ma];
|
||||
}
|
||||
|
||||
- (NSArray *) fixupCyclicRecords: (NSArray *) _records
|
||||
|
@ -693,14 +811,14 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
// TODO: is the result supposed to be sorted by date?
|
||||
NSMutableArray *ma;
|
||||
NSDictionary *row;
|
||||
unsigned int i, count;
|
||||
unsigned int count, max;
|
||||
|
||||
count = [_records count];
|
||||
ma = [NSMutableArray arrayWithCapacity: count];
|
||||
if (count > 0)
|
||||
for (i = 0; i < count; i++)
|
||||
max = [_records count];
|
||||
ma = [NSMutableArray arrayWithCapacity: max];
|
||||
|
||||
for (count = 0; count < max; count++)
|
||||
{
|
||||
row = [_records objectAtIndex: i];
|
||||
row = [_records objectAtIndex: count];
|
||||
[self _flattenCycleRecord: row forRange: _r intoArray: ma];
|
||||
}
|
||||
|
||||
|
@ -844,9 +962,10 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
{
|
||||
if (r)
|
||||
records = [self fixupCyclicRecords: records fetchRange: r];
|
||||
if (!ma)
|
||||
ma = [NSMutableArray arrayWithCapacity: [records count]];
|
||||
if (ma)
|
||||
[ma addObjectsFromArray: records];
|
||||
else
|
||||
ma = [NSMutableArray arrayWithArray: records];
|
||||
}
|
||||
else if (!ma)
|
||||
{
|
||||
|
@ -891,6 +1010,8 @@ static Class sogoAppointmentFolderKlass = Nil;
|
|||
#warning we should use the EOFetchSpecification for that!!! (see doPROPFIND:)
|
||||
|
||||
#warning components in calendar-data query are ignored
|
||||
|
||||
#warning the two following methods should be replaced with the new dav rendering mechanism
|
||||
- (NSString *) _nodeTagForProperty: (NSString *) property
|
||||
{
|
||||
NSString *namespace, *nodeName, *nsRep;
|
||||
|
|
|
@ -27,8 +27,13 @@
|
|||
|
||||
@class SOGoUser;
|
||||
|
||||
NSCalendarDate *iCalDistantFuture;
|
||||
NSNumber *iCalDistantFutureNumber;
|
||||
|
||||
@interface iCalEntityObject (SOGoExtensions)
|
||||
|
||||
+ (void) initializeSOGoExtensions;
|
||||
|
||||
- (BOOL) userIsParticipant: (SOGoUser *) user;
|
||||
- (BOOL) userIsOrganizer: (SOGoUser *) user;
|
||||
|
||||
|
@ -38,6 +43,10 @@
|
|||
- (id) itipEntryWithMethod: (NSString *) method;
|
||||
|
||||
- (NSArray *) attendeesWithoutUser: (SOGoUser *) user;
|
||||
- (NSMutableDictionary *) quickRecord;
|
||||
|
||||
- (int) priorityNumber;
|
||||
- (NSNumber *) quickRecordDateAsNumber: (NSCalendarDate *) _date;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSString.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGCards/iCalCalendar.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
|
@ -36,6 +37,16 @@
|
|||
|
||||
@implementation iCalEntityObject (SOGoExtensions)
|
||||
|
||||
+ (void) initializeSOGoExtensions;
|
||||
{
|
||||
if (!iCalDistantFuture)
|
||||
{
|
||||
iCalDistantFuture = [[NSCalendarDate distantFuture] retain];
|
||||
/* INT_MAX due to Postgres constraint */
|
||||
iCalDistantFutureNumber = [[NSNumber numberWithUnsignedInt: INT_MAX] retain];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) userIsParticipant: (SOGoUser *) user
|
||||
{
|
||||
NSEnumerator *participants;
|
||||
|
@ -128,4 +139,38 @@
|
|||
return newAttendees;
|
||||
}
|
||||
|
||||
- (NSNumber *) quickRecordDateAsNumber: (NSCalendarDate *) _date
|
||||
{
|
||||
return ((_date == iCalDistantFuture)
|
||||
? iCalDistantFutureNumber
|
||||
: [NSNumber numberWithUnsignedInt: [_date timeIntervalSince1970]]);
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) quickRecord
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (int) priorityNumber
|
||||
{
|
||||
NSString *prio;
|
||||
NSRange r;
|
||||
int priorityNumber;
|
||||
|
||||
prio = [self priority];
|
||||
if (prio)
|
||||
{
|
||||
r = [prio rangeOfString: @";"];
|
||||
if (r.length)
|
||||
prio = [prio substringToIndex:r.location];
|
||||
priorityNumber = [prio intValue];
|
||||
}
|
||||
else
|
||||
priorityNumber = 0;
|
||||
|
||||
return priorityNumber;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -25,9 +25,12 @@
|
|||
|
||||
#import <NGCards/iCalEvent.h>
|
||||
|
||||
@class NSMutableDictionary;
|
||||
|
||||
@interface iCalEvent (SOGoExtensions)
|
||||
|
||||
- (BOOL) isStillRelevant;
|
||||
- (NSMutableDictionary *) quickRecord;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -20,7 +20,18 @@
|
|||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <NGCards/iCalEvent.h>
|
||||
#import <NGCards/iCalPerson.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
#import "iCalEvent+SOGo.h"
|
||||
|
||||
|
@ -35,4 +46,150 @@
|
|||
return ([[self endDate] earlierDate: now] == now);
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *) quickRecord
|
||||
{
|
||||
NSMutableDictionary *row;
|
||||
NSCalendarDate *startDate, *endDate;
|
||||
NSArray *attendees;
|
||||
NSString *uid, *title, *location, *status;
|
||||
NSNumber *sequence, *dateNumber;
|
||||
id organizer;
|
||||
id participants, partmails;
|
||||
NSMutableString *partstates;
|
||||
unsigned int i, count, boolTmp;
|
||||
BOOL isAllDay;
|
||||
iCalAccessClass accessClass;
|
||||
|
||||
/* extract values */
|
||||
|
||||
startDate = [self startDate];
|
||||
endDate = [self endDate];
|
||||
uid = [self uid];
|
||||
title = [self summary];
|
||||
if (![title isNotNull])
|
||||
title = @"";
|
||||
location = [self location];
|
||||
sequence = [self sequence];
|
||||
accessClass = [self symbolicAccessClass];
|
||||
isAllDay = [self isAllDay];
|
||||
status = [[self status] uppercaseString];
|
||||
|
||||
attendees = [self attendees];
|
||||
partmails = [attendees valueForKey: @"rfc822Email"];
|
||||
partmails = [partmails componentsJoinedByString: @"\n"];
|
||||
participants = [attendees valueForKey: @"cn"];
|
||||
participants = [participants componentsJoinedByString: @"\n"];
|
||||
|
||||
/* build row */
|
||||
|
||||
row = [NSMutableDictionary dictionaryWithCapacity:8];
|
||||
|
||||
[row setObject: @"vevent" forKey: @"c_component"];
|
||||
|
||||
if ([uid isNotNull])
|
||||
[row setObject:uid forKey: @"c_uid"];
|
||||
else
|
||||
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
|
||||
|
||||
boolTmp = ((isAllDay) ? 1 : 0);
|
||||
[row setObject: [NSNumber numberWithInt: boolTmp]
|
||||
forKey: @"c_isallday"];
|
||||
boolTmp = (([self isRecurrent]) ? 1 : 0);
|
||||
[row setObject: [NSNumber numberWithInt: boolTmp]
|
||||
forKey: @"c_iscycle"];
|
||||
boolTmp = (([self isOpaque]) ? 1 : 0);
|
||||
[row setObject: [NSNumber numberWithInt: boolTmp]
|
||||
forKey: @"c_isopaque"];
|
||||
[row setObject: [NSNumber numberWithInt: [self priorityNumber]]
|
||||
forKey: @"c_priority"];
|
||||
|
||||
[row setObject: title forKey: @"c_title"];
|
||||
if ([location isNotNull]) [row setObject: location forKey: @"c_location"];
|
||||
if ([sequence isNotNull]) [row setObject: sequence forKey: @"c_sequence"];
|
||||
|
||||
if ([startDate isNotNull])
|
||||
[row setObject: [self quickRecordDateAsNumber: startDate]
|
||||
forKey: @"c_startdate"];
|
||||
if ([endDate isNotNull])
|
||||
{
|
||||
if (endDate == iCalDistantFuture)
|
||||
dateNumber = iCalDistantFutureNumber;
|
||||
else
|
||||
{
|
||||
if (isAllDay)
|
||||
i = 1;
|
||||
else
|
||||
i = 0;
|
||||
dateNumber
|
||||
= [NSNumber numberWithUnsignedInt:
|
||||
[endDate timeIntervalSince1970] - i];
|
||||
}
|
||||
[row setObject: dateNumber forKey: @"c_enddate"];
|
||||
}
|
||||
|
||||
if ([self isRecurrent]) {
|
||||
NSCalendarDate *date;
|
||||
|
||||
date = [self lastPossibleRecurrenceStartDate];
|
||||
if (!date) {
|
||||
/* this could also be *nil*, but in the end it makes the fetchspecs
|
||||
more complex - thus we set it to a "reasonable" distant future */
|
||||
date = iCalDistantFuture;
|
||||
}
|
||||
[row setObject:[self quickRecordDateAsNumber:date] forKey: @"c_cycleenddate"];
|
||||
[row setObject:[self cycleInfo] forKey: @"c_cycleinfo"];
|
||||
}
|
||||
|
||||
if ([participants length] > 0)
|
||||
[row setObject: participants forKey: @"c_participants"];
|
||||
if ([partmails length] > 0)
|
||||
[row setObject: partmails forKey: @"c_partmails"];
|
||||
|
||||
if ([status isNotNull]) {
|
||||
int code = 1;
|
||||
|
||||
if ([status isEqualToString: @"TENTATIVE"])
|
||||
code = 2;
|
||||
else if ([status isEqualToString: @"CANCELLED"])
|
||||
code = 0;
|
||||
[row setObject:[NSNumber numberWithInt:code] forKey: @"c_status"];
|
||||
}
|
||||
else {
|
||||
/* confirmed by default */
|
||||
[row setObject: [NSNumber numberWithInt:1] forKey: @"c_status"];
|
||||
}
|
||||
|
||||
[row setObject: [NSNumber numberWithUnsignedInt: accessClass]
|
||||
forKey: @"c_classification"];
|
||||
|
||||
organizer = [self organizer];
|
||||
if (organizer)
|
||||
{
|
||||
NSString *email;
|
||||
|
||||
email = [organizer valueForKey: @"rfc822Email"];
|
||||
if (email)
|
||||
[row setObject:email forKey: @"c_orgmail"];
|
||||
}
|
||||
|
||||
/* construct partstates */
|
||||
count = [attendees count];
|
||||
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
iCalPerson *p;
|
||||
iCalPersonPartStat stat;
|
||||
|
||||
p = [attendees objectAtIndex:i];
|
||||
stat = [p participationStatus];
|
||||
if (i)
|
||||
[partstates appendString: @"\n"];
|
||||
[partstates appendFormat: @"%d", stat];
|
||||
}
|
||||
[row setObject:partstates forKey: @"c_partstates"];
|
||||
[partstates release];
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/* iCalRepeatableEntityObject+SOGo.h - this file is part of SOGo
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
Copyright (C) 2008 Inverse groupe conseil
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#import <NGCards/iCalRepeatableEntityObject.h>
|
||||
|
||||
#import "iCalEntityObject+SOGo.h"
|
||||
|
||||
@class NSString;
|
||||
|
||||
@interface iCalRepeatableEntityObject (SOGoExtensions)
|
||||
|
||||
- (NSString *) cycleInfo;
|
||||
|
||||
@end
|
|
@ -0,0 +1,89 @@
|
|||
/* iCalRepeatableEntityObject+SOGo.m - this file is part of SOGo
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
Copyright (C) 2008 Inverse groupe conseil
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#import <NGCards/iCalRecurrenceRule.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
@implementation iCalRepeatableEntityObject (SOGoExtensions)
|
||||
|
||||
- (NSArray *) _indexedRules: (NSArray *) rules
|
||||
{
|
||||
NSMutableArray *ma;
|
||||
unsigned int i, count;
|
||||
NSString *valuesString;
|
||||
|
||||
ma = nil;
|
||||
count = [rules count];
|
||||
if (count > 0)
|
||||
{
|
||||
ma = [NSMutableArray arrayWithCapacity:count];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
iCalRecurrenceRule *rule;
|
||||
|
||||
rule = [rules objectAtIndex:i];
|
||||
#warning we could return an NSArray instead and feed it as such to the iCalRecurrenceRule in SOGoAppointmentFolder...
|
||||
valuesString = [[rule values] componentsJoinedByString: @";"];
|
||||
[ma addObject: valuesString];
|
||||
}
|
||||
}
|
||||
|
||||
return ma;
|
||||
}
|
||||
|
||||
- (NSString *) cycleInfo
|
||||
{
|
||||
NSArray *rules;
|
||||
NSString *value;
|
||||
NSMutableDictionary *cycleInfo;
|
||||
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
cycleInfo = [NSMutableDictionary dictionaryWithCapacity: 3];
|
||||
|
||||
/* rules */
|
||||
rules = [self _indexedRules: [self recurrenceRules]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"rules"];
|
||||
|
||||
rules = [self _indexedRules: [self exceptionRules]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"exRules"];
|
||||
|
||||
rules = [self _indexedRules: [self exceptionDates]];
|
||||
if (rules)
|
||||
[cycleInfo setObject: rules forKey: @"exDates"];
|
||||
|
||||
value = [cycleInfo description];
|
||||
}
|
||||
else
|
||||
value = nil;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@end
|
|
@ -0,0 +1,36 @@
|
|||
/* iCalToDo+SOGo.h - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2007 Inverse groupe conseil
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef ICALTODO_SOGO_H
|
||||
#define ICALTODO_SOGO_H
|
||||
|
||||
#import <NGCards/iCalToDo.h>
|
||||
|
||||
@class NSMutableArray;
|
||||
|
||||
@interface iCalToDo (SOGoExtensions)
|
||||
|
||||
- (NSMutableDictionary *) quickRecord;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* ICALTODO_SOGO_H */
|
|
@ -0,0 +1,168 @@
|
|||
/* iCalEvent+SOGo.m - this file is part of SOGo
|
||||
*
|
||||
* Copyright (C) 2008 Inverse groupe conseil
|
||||
* Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
*
|
||||
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This file 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
#import <NGExtensions/NSNull+misc.h>
|
||||
#import <NGExtensions/NSObject+Logs.h>
|
||||
|
||||
#import <NGCards/iCalPerson.h>
|
||||
|
||||
#import "iCalRepeatableEntityObject+SOGo.h"
|
||||
|
||||
#import "iCalToDo+SOGo.h"
|
||||
|
||||
@implementation iCalToDo (SOGoExtensions)
|
||||
|
||||
- (NSMutableDictionary *) quickRecord
|
||||
{
|
||||
NSMutableDictionary *row;
|
||||
NSCalendarDate *startDate, *dueDate;
|
||||
NSArray *attendees;
|
||||
NSString *uid, *title, *location, *status;
|
||||
NSNumber *sequence;
|
||||
id organizer, date;
|
||||
id participants, partmails;
|
||||
NSMutableString *partstates;
|
||||
unsigned i, count, code;
|
||||
iCalAccessClass accessClass;
|
||||
|
||||
/* extract values */
|
||||
|
||||
startDate = [self startDate];
|
||||
dueDate = [self due];
|
||||
uid = [self uid];
|
||||
title = [self summary];
|
||||
if (![title isNotNull])
|
||||
title = @"";
|
||||
location = [self location];
|
||||
sequence = [self sequence];
|
||||
accessClass = [self symbolicAccessClass];
|
||||
status = [[self status] uppercaseString];
|
||||
|
||||
attendees = [self attendees];
|
||||
partmails = [attendees valueForKey: @"rfc822Email"];
|
||||
partmails = [partmails componentsJoinedByString: @"\n"];
|
||||
participants = [attendees valueForKey: @"cn"];
|
||||
participants = [participants componentsJoinedByString: @"\n"];
|
||||
|
||||
/* build row */
|
||||
|
||||
row = [NSMutableDictionary dictionaryWithCapacity:8];
|
||||
|
||||
[row setObject: @"vtodo" forKey: @"c_component"];
|
||||
|
||||
if ([uid isNotNull])
|
||||
[row setObject:uid forKey: @"c_uid"];
|
||||
else
|
||||
[self logWithFormat: @"WARNING: could not extract a uid from event!"];
|
||||
|
||||
[row setObject:[NSNumber numberWithBool:[self isRecurrent]]
|
||||
forKey: @"c_iscycle"];
|
||||
[row setObject:[NSNumber numberWithInt:[self priorityNumber]]
|
||||
forKey: @"c_priority"];
|
||||
|
||||
[row setObject: [NSNumber numberWithBool: NO]
|
||||
forKey: @"c_isallday"];
|
||||
[row setObject: [NSNumber numberWithBool: NO]
|
||||
forKey: @"c_isopaque"];
|
||||
|
||||
[row setObject: title forKey: @"c_title"];
|
||||
if ([location isNotNull]) [row setObject: location forKey: @"c_location"];
|
||||
if ([sequence isNotNull]) [row setObject: sequence forKey: @"c_sequence"];
|
||||
|
||||
if ([startDate isNotNull])
|
||||
date = [self quickRecordDateAsNumber: startDate];
|
||||
else
|
||||
date = [NSNull null];
|
||||
[row setObject: date forKey: @"c_startdate"];
|
||||
|
||||
if ([dueDate isNotNull])
|
||||
date = [self quickRecordDateAsNumber: dueDate];
|
||||
else
|
||||
date = [NSNull null];
|
||||
[row setObject: date forKey: @"c_enddate"];
|
||||
|
||||
if ([self isRecurrent])
|
||||
{
|
||||
[row setObject: [self quickRecordDateAsNumber: iCalDistantFuture]
|
||||
forKey: @"c_cycleenddate"];
|
||||
[row setObject: [self cycleInfo]
|
||||
forKey: @"c_cycleinfo"];
|
||||
}
|
||||
|
||||
if ([participants length] > 0)
|
||||
[row setObject:participants forKey: @"c_participants"];
|
||||
if ([partmails length] > 0)
|
||||
[row setObject:partmails forKey: @"c_partmails"];
|
||||
|
||||
if ([status isNotNull]) {
|
||||
code = 0; /* NEEDS-ACTION */
|
||||
if ([status isEqualToString: @"COMPLETED"])
|
||||
code = 1;
|
||||
else if ([status isEqualToString: @"IN-PROCESS"])
|
||||
code = 2;
|
||||
else if ([status isEqualToString: @"CANCELLED"])
|
||||
code = 3;
|
||||
[row setObject: [NSNumber numberWithInt: code] forKey: @"c_status"];
|
||||
}
|
||||
else {
|
||||
/* confirmed by default */
|
||||
[row setObject:[NSNumber numberWithInt:1] forKey: @"c_status"];
|
||||
}
|
||||
|
||||
[row setObject: [NSNumber numberWithUnsignedInt: accessClass]
|
||||
forKey: @"c_classification"];
|
||||
|
||||
organizer = [self organizer];
|
||||
if (organizer) {
|
||||
NSString *email;
|
||||
|
||||
email = [organizer valueForKey: @"rfc822Email"];
|
||||
if (email)
|
||||
[row setObject:email forKey: @"c_orgmail"];
|
||||
}
|
||||
|
||||
/* construct partstates */
|
||||
count = [attendees count];
|
||||
partstates = [[NSMutableString alloc] initWithCapacity:count * 2];
|
||||
for ( i = 0; i < count; i++) {
|
||||
iCalPerson *p;
|
||||
iCalPersonPartStat stat;
|
||||
|
||||
p = [attendees objectAtIndex:i];
|
||||
stat = [p participationStatus];
|
||||
if(i != 0)
|
||||
[partstates appendString: @"\n"];
|
||||
[partstates appendFormat: @"%d", stat];
|
||||
}
|
||||
[row setObject:partstates forKey: @"c_partstates"];
|
||||
[partstates release];
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
@end
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#import <Foundation/NSDictionary.h>
|
||||
|
||||
@class NSArray;
|
||||
@class NSString;
|
||||
|
||||
@interface NSDictionary (SOGoDictionaryUtilities)
|
||||
|
@ -36,4 +37,11 @@
|
|||
|
||||
@end
|
||||
|
||||
@interface NSMutableDictionary (SOGoDictionaryUtilities)
|
||||
|
||||
- (void) setObjects: (NSArray *) objects
|
||||
forKeys: (NSArray *) keys;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* NSDICTIONARY_UTILITIES_H */
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#import <Foundation/NSArray.h>
|
||||
#import <Foundation/NSData.h>
|
||||
#import <Foundation/NSEnumerator.h>
|
||||
#import <Foundation/NSException.h>
|
||||
#import <Foundation/NSNull.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
|
@ -103,3 +104,23 @@
|
|||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSMutableDictionary (SOGoDictionaryUtilities)
|
||||
|
||||
- (void) setObjects: (NSArray *) objects
|
||||
forKeys: (NSArray *) keys
|
||||
{
|
||||
unsigned int count, max;
|
||||
|
||||
max = [objects count];
|
||||
if ([keys count] == max)
|
||||
for (count = 0; count < max; count++)
|
||||
[self setObject: [objects objectAtIndex: count]
|
||||
forKey: [keys objectAtIndex: count]];
|
||||
else
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Number of objects does not match"
|
||||
@" the number of keys."];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue