2 Copyright (C) 2004-2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 Show plain/calendar mail parts.
28 #import <NGObjWeb/WOResponse.h>
30 #import <NGExtensions/NSCalendarDate+misc.h>
31 #import <NGExtensions/NSNull+misc.h>
32 #import <NGExtensions/NSObject+Logs.h>
34 #import <NGImap4/NGImap4EnvelopeAddress.h>
36 #import <NGCards/iCalCalendar.h>
37 #import <NGCards/iCalEvent.h>
38 #import <NGCards/iCalPerson.h>
39 #import <NGCards/iCalDateTime.h>
41 #import <SoObjects/SOGo/SOGoDateFormatter.h>
42 #import <SoObjects/SOGo/SOGoUser.h>
43 #import <SoObjects/Appointments/SOGoAppointmentFolder.h>
44 #import <SoObjects/Appointments/SOGoAppointmentObject.h>
45 #import <SoObjects/Mailer/SOGoMailObject.h>
47 #import "UIxMailPartICalViewer.h"
49 @implementation UIxMailPartICalViewer
53 [storedEventObject release];
54 [storedEvent release];
59 [dateFormatter release];
65 - (void) resetPathCaches
67 [super resetPathCaches];
68 [inEvent release]; inEvent = nil;
69 [inCalendar release]; inCalendar = nil;
70 [storedEventObject release]; storedEventObject = nil;
71 [storedEvent release]; storedEvent = nil;
73 /* not strictly path-related, but useless without it anyway: */
74 [attendee release]; attendee = nil;
75 [item release]; item = nil;
78 /* raw content handling */
80 - (NSStringEncoding) fallbackStringEncoding
83 iCalendar invitations sent by Outlook 2002 have the annoying bug that the
84 mail states an UTF-8 content encoding but the actual iCalendar content is
85 encoding in Latin-1 (or Windows Western?).
87 As a result the content decoding will fail (TODO: always?). In this case we
88 try to decode with Latin-1.
90 Note: we could check for the Outlook x-mailer, but it was considered better
91 to try Latin-1 as a fallback in any case (be tolerant).
93 return NSISOLatin1StringEncoding;
98 - (iCalCalendar *) inCalendar
103 = [iCalCalendar parseSingleFromSource: [self flatContentAsString]];
110 - (BOOL) couldParseCalendar
112 return [[self inCalendar] isNotNull];
115 - (iCalEvent *) inEvent
120 return [inEvent isNotNull] ? inEvent : nil;
122 events = [[self inCalendar] events];
123 if ([events count] > 0) {
124 inEvent = [[events objectAtIndex:0] retain];
128 inEvent = [[NSNull null] retain];
135 - (SOGoDateFormatter *) dateFormatter
137 if (dateFormatter == nil) {
138 dateFormatter = [[context activeUser] dateFormatterInContext: context];
139 [dateFormatter retain];
142 return dateFormatter;
145 /* below is copied from UIxAppointmentView, can we avoid that? */
147 - (void) setAttendee: (id) _attendee
149 ASSIGN(attendee, _attendee);
157 - (NSString *) _personForDisplay: (iCalPerson *) person
159 NSString *fn, *email, *result;
161 fn = [person cnWithoutQuotes];
162 email = [person rfc822Email];
164 result = [NSString stringWithFormat: @"%@ <%@>",
172 - (NSString *) attendeeForDisplay
174 return [self _personForDisplay: attendee];
177 - (void) setItem: (id) _item
187 - (NSCalendarDate *) startTime
189 NSCalendarDate *date;
190 NSTimeZone *timeZone;
192 date = [[self authorativeEvent] startDate];
193 timeZone = [[context activeUser] timeZone];
194 [date setTimeZone: timeZone];
199 - (NSCalendarDate *) endTime
201 NSCalendarDate *date;
202 NSTimeZone *timeZone;
204 date = [[self authorativeEvent] endDate];
205 timeZone = [[context activeUser] timeZone];
206 [date setTimeZone: timeZone];
211 - (BOOL) isEndDateOnSameDay
213 return [[self startTime] isDateOnSameDay:[self endTime]];
216 - (NSTimeInterval) duration
218 return [[self endTime] timeIntervalSinceDate:[self startTime]];
221 /* calendar folder support */
223 - (id) calendarFolder
225 /* return scheduling calendar of currently logged-in user */
229 user = [context activeUser];
230 folder = [[user homeFolderInContext: context] lookupName: @"Calendar"
234 return [folder lookupName: @"personal" inContext: context acquire: NO];
237 - (id) storedEventObject
239 /* lookup object in the users Calendar */
242 if (storedEventObject)
243 return [storedEventObject isNotNull] ? storedEventObject : nil;
245 calendar = [self calendarFolder];
246 if ([calendar isKindOfClass:[NSException class]]) {
247 [self errorWithFormat:@"Did not find Calendar folder: %@", calendar];
252 filename = [calendar resourceNameForEventUID:[[self inEvent] uid]];
254 // TODO: When we get an exception, this might be an auth issue meaning
255 // that the UID indeed exists but that the user has no access to
257 // Of course this is quite unusual for the private calendar though.
260 tmp = [calendar lookupName:filename inContext:[self context] acquire:NO];
261 if ([tmp isNotNull] && ![tmp isKindOfClass:[NSException class]])
262 storedEventObject = [tmp retain];
266 if (storedEventObject == nil)
267 storedEventObject = [[NSNull null] retain];
269 return storedEventObject;
272 - (BOOL) isEventStoredInCalendar
274 return [[self storedEventObject] isNotNull];
277 - (iCalEvent *) storedEvent
279 return (iCalEvent *) [(SOGoAppointmentObject *)[self storedEventObject] component: NO];
282 /* organizer tracking */
284 - (NSString *) loggedInUserEMail
286 NSDictionary *identity;
288 identity = [[context activeUser] primaryIdentity];
290 return [identity objectForKey: @"email"];
293 - (iCalEvent *) authorativeEvent
295 iCalEvent *authorativeEvent;
297 if ([[self storedEvent] compare: [self inEvent]]
298 == NSOrderedAscending)
299 authorativeEvent = inEvent;
301 authorativeEvent = storedEventObject;
303 return authorativeEvent;
306 - (BOOL) isLoggedInUserTheOrganizer
308 iCalPerson *organizer;
310 organizer = [[self authorativeEvent] organizer];
312 return [[context activeUser] hasEmail: [organizer rfc822Email]];
315 - (BOOL) isLoggedInUserAnAttendee
317 NSString *loginEMail;
319 if ((loginEMail = [self loggedInUserEMail]) == nil) {
320 [self warnWithFormat:@"Could not determine email of logged in user?"];
324 return [[self authorativeEvent] isParticipant:loginEMail];
329 - (NSString *) organizerDisplayName
331 iCalPerson *organizer;
334 organizer = [[self authorativeEvent] organizer];
336 value = [self _personForDisplay: organizer];
338 value = @"[todo: no organizer set, use 'from']";
345 - (NGImap4EnvelopeAddress *) replySenderAddress
348 The iMIP reply is the sender of the mail, the 'attendees' are NOT set to
349 the actual attendees. BUT the attendee field contains the reply-status!
353 tmp = [[self clientObject] fromEnvelopeAddresses];
354 if ([tmp count] == 0) return nil;
355 return [tmp objectAtIndex:0];
358 - (NSString *) replySenderEMail
360 return [[self replySenderAddress] email];
363 - (NSString *) replySenderBaseEMail
365 return [[self replySenderAddress] baseEMail];
368 - (iCalPerson *) inReplyAttendee
372 attendees = [[self inEvent] attendees];
373 if ([attendees count] == 0)
375 if ([attendees count] > 1)
376 [self warnWithFormat:@"More than one attendee in REPLY: %@", attendees];
378 return [attendees objectAtIndex:0];
381 - (iCalPerson *) storedReplyAttendee
384 TODO: since an attendee can have multiple email addresses, maybe we
385 should translate the email to an internal uid and then retrieve
386 all emails addresses for matching the participant.
388 Note: -findParticipantWithEmail: does not parse the email!
395 e = [self storedEvent];
398 p = [e findParticipantWithEmail: [self replySenderBaseEMail]];
400 p = [e findParticipantWithEmail:[self replySenderEMail]];
406 - (BOOL) isReplySenderAnAttendee
408 return [[self storedReplyAttendee] isNotNull];
411 @end /* UIxMailPartICalViewer */